2013-05-04 4 views
24

गठबंधन करने के लिए मिलता है यहाँ कोड मैं सामान्य रूप से उपयोग दृश्य स्टूडियो के साथ स्मृति गठबंधन करने के लिए जाता है और जीसीसीसबसे अच्छा पार मंच विधि स्मृति

inline void* aligned_malloc(size_t size, size_t align) { 
    void *result; 
    #ifdef _MSC_VER 
    result = _aligned_malloc(size, align); 
    #else 
    if(posix_memalign(&result, align, size)) result = 0; 
    #endif 
    return result; 
} 

inline void aligned_free(void *ptr) { 
    #ifdef _MSC_VER 
     _aligned_free(ptr); 
    #else 
     free(ptr); 
    #endif 

} 

सामान्य रूप में इस कोड को ठीक है? मैंने लोगों को _mm_malloc, _mm_free का उपयोग भी देखा है। ज्यादातर मामलों में मैं गठबंधन स्मृति चाहता हूं, यह एसएसई/एवीएक्स का उपयोग करना है। क्या मैं सामान्य रूप से उन कार्यों का उपयोग कर सकता हूं? यह मेरे कोड को बहुत आसान बना देगा।

आखिरकार, स्मृति को संरेखित करने के लिए अपना स्वयं का फ़ंक्शन बनाना आसान है (नीचे देखें)। फिर गठबंधन स्मृति प्राप्त करने के लिए इतने सारे अलग-अलग सामान्य कार्य क्यों हैं (जिनमें से कई केवल एक मंच पर काम करते हैं)?

यह कोड 16 बाइट संरेखण करता है।

float* array = (float*)malloc(SIZE*sizeof(float)+15); 

// find the aligned position 
// and use this pointer to read or write data into array 
float* alignedArray = (float*)(((unsigned long)array + 15) & (~0x0F)); 

// dellocate memory original "array", NOT alignedArray 
free(array); 
array = alignedArray = 0; 

देखें: http://www.songho.ca/misc/alignment/dataalign.html और How to allocate aligned memory only using the standard library?

संपादित करें: मामले में किसी को भी परवाह करता है, मैं Eigen से मेरी aligned_malloc() फ़ंक्शन के लिए विचार आया (Eigen/src/कोर/util/Memory.h)

संपादित करें: मुझे पता चला कि posix_memalign MinGW के लिए अपरिभाषित है। हालांकि, _mm_malloc विजुअल स्टूडियो 2012, जीसीसी, मिनजीडब्ल्यू, और इंटेल सी ++ कंपाइलर के लिए काम करता है, इसलिए यह सामान्य रूप से सबसे सुविधाजनक समाधान प्रतीत होता है। इसके लिए अपने _mm_free फ़ंक्शन का उपयोग करने की भी आवश्यकता है, हालांकि कुछ कार्यान्वयन पर आप _mm_malloc से मानक free/delete पर पॉइंटर्स पास कर सकते हैं।

+0

जबकि पते की 'हस्ताक्षरित लंबी' कास्ट अभ्यास में काम कर सकती है, यह आईएलपी 32/एलपी 64/एलएलपी 64 (win64) डेटा मॉडल के बीच पोर्टेबल नहीं हो सकता है। –

उत्तर

4

आपके द्वारा प्रस्तावित पहला कार्य वास्तव में ठीक काम करेगा।

आपका "होमब्री" फ़ंक्शन भी काम करता है, लेकिन इसमें कमी है कि यदि मान पहले से ही गठबंधन है, तो आपने केवल 15 बाइट बर्बाद कर दिए हैं। कभी-कभी कोई फर्क नहीं पड़ता, लेकिन ओएस अच्छी तरह से स्मृति प्रदान करने में सक्षम हो सकता है जो बिना किसी कचरे के सही ढंग से आवंटित किया जाता है (और यदि इसे 256 या 40 9 6 बाइट्स के साथ गठबंधन करने की आवश्यकता है, तो आप "संरेखण -1" जोड़कर बहुत सारी याददाश्त बर्बाद कर सकते हैं। बाइट्स)।

+0

लेकिन _mm_malloc के बारे में क्या? अगर मैं एसएसई/एवीएक्स का उपयोग कर रहा हूं तो क्या यह सामान्य रूप से उपयोग करना ठीक है? उस मामले के लिए, जब भी मैं एसएसई/एवीएक्स का उपयोग नहीं कर रहा हूं तब भी इसका उपयोग क्यों नहीं करें? –

+2

यदि कंपाइलर _mm_malloc() का समर्थन करता है, तो यह भी एक वैध समाधान है। आपको '_mm_free()' का उपयोग करने की भी आवश्यकता है। और हां, ज़ाहिर है, आप किसी भी स्मृति आवंटन के लिए '_mm_malloc()' का उपयोग कर सकते हैं - लेकिन निश्चित रूप से, छोटे आवंटन "सामान्य" से अधिक जगह बर्बाद कर देंगे। –

+0

ठीक है, मुझे लगता है कि मैं _mm_malloc() और _mm_free() का उपयोग करना शुरू कर दूंगा। कम से कम एसओ उत्तरों पर जब मुझे गठबंधन स्मृति की आवश्यकता होती है। यह कोड को बहुत आसान बनाता है। –

8

जब तक आप मुक्त करने के लिए एक विशेष कार्य करने के लिए ठीक कह रहे हैं, तो आपका दृष्टिकोण ठीक है। मैं आपके #ifdef एस के आसपास अन्य तरीकों से करता हूं: मानक-निर्दिष्ट विकल्पों के साथ शुरू करें और प्लेटफ़ॉर्म-विशिष्ट वाले पर वापस आएं। उदाहरण के लिए

  1. यदि __STDC_VERSION__ >= 201112Laligned_alloc का उपयोग करें।
  2. यदि _POSIX_VERSION >= 200112Lposix_memalign का उपयोग करें।
  3. यदि _MSC_VER परिभाषित किया गया है, तो विंडोज सामान का उपयोग करें।
  4. ...
  5. यदि अन्य सभी विफल हो जाते हैं, तो बस malloc/free का उपयोग करें और एसएसई/एवीएक्स कोड अक्षम करें।

समस्या तब कठिन होती है जब आप आवंटित सूचक को free पर पास करने में सक्षम होना चाहते हैं; यह सभी मानक इंटरफेस पर मान्य है, लेकिन विंडोज़ पर नहीं और विरासत memalign के साथ जरूरी नहीं है कुछ यूनिक्स जैसी प्रणालियों में काम करता है।

1

यदि आप संकलक इसका समर्थन करते हैं, तो C++ 11 रनटाइम पॉइंटर संरेखण करने के लिए std::align फ़ंक्शन जोड़ता है।आप नि: शुल्क इस (untested) की तरह अपने खुद के malloc को लागू कर सकता /:

template<std::size_t Align> 
void *aligned_malloc(std::size_t size) 
{ 
    std::size_t space = size + (Align - 1); 
    void *ptr = malloc(space + sizeof(void*)); 
    void *original_ptr = ptr; 

    char *ptr_bytes = static_cast<char*>(ptr); 
    ptr_bytes += sizeof(void*); 
    ptr = static_cast<void*>(ptr_bytes); 

    ptr = std::align(Align, size, ptr, space); 

    ptr_bytes = static_cast<void*>(ptr); 
    ptr_bytes -= sizeof(void*); 
    std::memcpy(ptr_bytes, original_ptr, sizeof(void*)); 

    return ptr; 
} 

void aligned_free(void* ptr) 
{ 
    void *ptr_bytes = static_cast<void*>(ptr); 
    ptr_bytes -= sizeof(void*); 

    void *original_ptr; 
    std::memcpy(&original_ptr, ptr_bytes, sizeof(void*)); 

    std::free(original_ptr); 
} 

तो फिर तुम यह मुक्त करने के लिए चारों ओर मूल सूचक मूल्य रखने के लिए नहीं है। चाहे यह 100% पोर्टेबल है, मुझे यकीन नहीं है, लेकिन मुझे उम्मीद है कि अगर कोई मुझे सही करेगा तो मुझे सही नहीं होगा!

+0

नीचे मेरा निश्चित संस्करण देखें। शून्य * पर पॉइंटर अंकगणित करने के साथ संकलक त्रुटि को ठीक करता है और aligned_malloc में memcpy अब मान को सही ढंग से प्रतिलिपि बनाता है। – speps

+0

यह संस्करण हमेशा अंतरिक्ष को बर्बाद कर देता है भले ही गठबंधन आवंटक उपलब्ध हों। -1। –

0

यहाँ मेरी 2 सेंट हैं:

temp = new unsigned char*[num]; 
AlignedBuffers = new unsigned char*[num]; 
for (int i = 0; i<num; i++) 
{ 
    temp[i] = new unsigned char[bufferSize +15]; 
    AlignedBuffers[i] = reinterpret_cast<unsigned char*>((reinterpret_cast<size_t> 
         (temp[i% num]) + 15) & ~15);// 16 bit alignment in preperation for SSE 
} 
2

यहाँ एक user2093113 के नमूने की तय हो गई है, प्रत्यक्ष कोड मेरे लिए का निर्माण नहीं किया (शून्य * अज्ञात आकार)। मैंने इसे टेम्पलेट क्लास ओवरराइडिंग ऑपरेटर में भी हटा दिया/हटा दिया ताकि आपको आवंटन और कॉल प्लेसमेंट नया करने की आवश्यकता न हो।

#include <memory> 

template<std::size_t Alignment> 
class Aligned 
{ 
public: 
    void* operator new(std::size_t size) 
    { 
     std::size_t space = size + (Alignment - 1); 
     void *ptr = malloc(space + sizeof(void*)); 
     void *original_ptr = ptr; 

     char *ptr_bytes = static_cast<char*>(ptr); 
     ptr_bytes += sizeof(void*); 
     ptr = static_cast<void*>(ptr_bytes); 

     ptr = std::align(Alignment, size, ptr, space); 

     ptr_bytes = static_cast<char*>(ptr); 
     ptr_bytes -= sizeof(void*); 
     std::memcpy(ptr_bytes, &original_ptr, sizeof(void*)); 

     return ptr; 
    } 

    void operator delete(void* ptr) 
    { 
     char *ptr_bytes = static_cast<char*>(ptr); 
     ptr_bytes -= sizeof(void*); 

     void *original_ptr; 
     std::memcpy(&original_ptr, ptr_bytes, sizeof(void*)); 

     std::free(original_ptr); 
    } 
}; 

इस तरह यह प्रयोग करें:

class Camera : public Aligned<16> 
{ 
}; 

अभी तक इस कोड के पार मंच सत्ता का परीक्षण नहीं किया था।

+1

आप केवल एक कथन का उपयोग करके 'हटाएं' को सरल बना सकते हैं: 'if (ptr) std :: free (static_cast (पीटीआर) [- 1]);' – bit2shift

+0

एक 'static_assert (संरेखण> आकार (शून्य *)) 'होगा एक अच्छा विचार हो, या यदि आवश्यक हो तो 'स्पेस' बढ़ाने के लिए 'min' का उपयोग करें। अंतरिक्ष को बर्बाद करने के बजाय उपलब्ध होने पर आपको गठबंधन आवंटकों का उपयोग करने के लिए निश्चित रूप से '# ifdef' का भी उपयोग करना चाहिए। (उदाहरण के लिए सी 11 के aligned_alloc जो कई सी ++ कंपाइलर्स प्रदान करते हैं)। यह भी देखें http://stackoverflow.com/questions/32612190/how-to-solve-the-32-byte-alignment-issue-for-avx-load-store-operations –

संबंधित मुद्दे