2015-09-16 31 views
18

Istnieje kilka opcji do uzyskania wyrównanego bloku pamięci, ale są one bardzo podobne, a problem zazwyczaj sprowadza się do standardu języka i platform, na które kierujesz reklamy.Dlaczego warto używać _mm_malloc? (w przeciwieństwie do _aligned_malloc, alligned_alloc lub posix_memalign)

C11

void * aligned_alloc (size_t alignment, size_t size) 

POSIX

int posix_memalign (void **memptr, size_t alignment, size_t size) 

Okna

void * _aligned_malloc(size_t size, size_t alignment); 

I oczywiście zawsze jest też opcja, aby wyrównać ręcznie.

Firma Intel oferuje inną opcję.

Intel

void* _mm_malloc (int size, int align) 
void _mm_free (void *p) 

oparciu o kod źródłowy wydany przez firmę Intel, to wydaje się być metoda rozdzielania wyrównany pamięć ich inżynierowie wolą, ale nie mogę znaleźć żadnej dokumentacji porównując ją z innymi metodami. Najbliższe, które znalazłem, po prostu potwierdza, że ​​istnieją inne dostosowane procedury alokacji pamięci.

https://software.intel.com/en-us/articles/memory-management-for-optimal-performance-on-intel-xeon-phi-coprocessor-alignment-and

dynamiczne przydzielanie kawałek wyrównany pamięci, stosowanie posix_memalign , który jest podtrzymywany przez GCC oraz Intel kompilatora. Korzyścią z używania go jest to, że nie trzeba zmieniać interfejsu API do usuwania pamięci. Możesz użyć free() jak zawsze. Ale zwróć uwagę na profil parametrów :

int posix_memalign (void ** memptr, size_t align, size_t size);

Kompilator Intel dostarcza również inny zestaw funkcji API alokacji pamięci. Programiści C/C++ mogą używać _mm_malloc i _mm_free do przydzielania i dowolnych bloków pamięci. Na przykład następująca instrukcja żąda 64-bajtowego wyrównanego bloku pamięci dla 8 elementów zmiennoprzecinkowych .

farray = (float *) __ mm_malloc (8 * sizeof (float), 64);

Pamięć przydzielona za pomocą _mm_malloc musi zostać zwolniona przy użyciu _mm_free. Wywoływanie wolnej pamięci przydzielonej za pomocą _mm_malloc lub wywoływanie _mm_free w pamięci przydzielonej za pomocą malloc spowoduje nieprzewidywalne zachowanie.

Wyraźne różnice z punktu widzenia użytkownika jest to, że wymaga bezpośredniego _mm_malloc procesora i wsparcie kompilator i pamięć przydzielona z _mm_malloc musi zostać uwolniony z _mm_free. Biorąc pod uwagę te wady, jaki jest powód, dla którego kiedykolwiek korzystam? _mm_malloc? Czy może mieć niewielką przewagę wydajności? Historyczny wypadek?

+1

Czy przeczytałeś cały dokument, który łączysz? Nie spodziewasz się, że to podsumujemy, prawda? – alk

+4

@alk Nie ma powodu, aby być niegrzecznym. Jeśli odpowiedź jest dla ciebie oczywista, wyjaśnij to. – Praxeolitic

+1

Może to zabrzmieć nieuprzejmie, nie jest to tak rozumiane. To pytanie, prawdopodobnie nieco sarkastyczne. – alk

Odpowiedz

19

Bardzo łatwo zrozumieć tę sytuację. Kompilatory Intel obsługują systemy operacyjne POSIX (Linux) i inne niż POSIX (Windows), dlatego nie mogą polegać na funkcji POSIX lub Windows. W związku z tym wybrano rozwiązanie specyficzne dla kompilatora, ale OS-agnostyczne.

C11 to świetne rozwiązanie, ale Microsoft nawet nie obsługuje jeszcze C99, więc kto wie, czy kiedykolwiek będzie obsługiwał C11.

Nota prawna: Pracuję dla firmy Intel, ale nie mam specjalnej wiedzy o tych decyzjach, które miały miejsce na długo przed tym, zanim dołączyłem do firmy.

+1

Och, tak, to w rzeczywistości bardzo proste i ma sens! Łatwo dostać krótkowzroczność na temat własnego systemu operacyjnego i nie zdać sobie sprawy z tych rzeczy. – Praxeolitic

4

Wydaje się, że _mm_malloc został utworzony zanim istniała standardowa funkcja aligned_alloc, a potrzeba użycia _mm_free jest dziwactwem implementacji.

Domyślam się, że w przeciwieństwie do używania posix_memalign, nie ma potrzeby nadmiernej alokacji w celu zagwarantowania wyrównania, zamiast tego używa oddzielnego przydziału alokującego alignment. Pozwoli to zaoszczędzić pamięć podczas przydzielania typów z wyrównaniem innym niż domyślne wyrównanie (zwykle 8 lub 16 bajtów).

4

Możliwe jest wzięcie istniejącego kompilatora C, który obecnie nie korzysta z identyfikatorów _mm_alloc i _mm_free i zdefiniowanie funkcji o tych nazwach, które będą zachowywać się zgodnie z wymaganiami. Można to zrobić poprzez funkcję _mm_alloc jako wrapper na malloc(), która prosi o nieco przewymiarowaną alokację i konstruuje wskaźnik do pierwszego odpowiednio wyrównanego adresu, który jest od początku co najmniej jednym bajtem i zapisuje liczbę bajtów pomijane bezpośrednio przed tym adresem lub przez żądanie _mm_malloc żądania dużych porcji pamięci od malloc(), a następnie dozować je po kawałku. W każdym razie wskaźniki zwrócone przez _mm_malloc() nie byłyby wskazówkami, że free() generalnie wiedzą, jak robić cokolwiek; wywołanie _mm_free użyłoby bajta bezpośrednio poprzedzającego alokację jako pomoc w znalezieniu prawdziwego startu przydziału otrzymanego od malloc, a następnie przekazanie tego do free.

Jeśli funkcja z przydzielonym przydzieleniem może używać wewnętrznych elementów funkcji malloc i free, może to wyeliminować konieczność dodatkowej warstwy zawijania. Możliwe jest pisanie _mm_alloc()/ funkcji, które owijają się malloc/free nie wiedząc nic na temat ich wewnętrznych elementów, ale wymaga to, aby _mm_alloc() przechowywać informacje dotyczące przechowywania, które są oddzielne od tych używanych przez malloc/free.

Jeśli autor wyrównanego przydzielić funkcję umie malloc i free są realizowane, nie zawsze będzie to możliwe, aby koordynować projekt wszystkich alokacji/Free funkcji tak, że free można rozróżnić wszystkie rodzaje alokacji i obsługiwać je odpowiednio . Jednak żadna pojedyncza implementacja z alokacją z wyrównaniem nie byłaby możliwa do zastosowania we wszystkich implementacjach malloc/free.

Sugerowałbym, że najbardziej przenośnym sposobem pisania kodu byłoby prawdopodobnie wybranie kilku symboli, które nie są używane nigdzie indziej dla własnych alokacji i wolnych funkcji, aby można było wtedy powiedzieć np.

#define a_alloc(align,sz) _mm_alloc((align),(sz)) 
#define a_free(ptr) _mm_free((ptr)) 

na kompilatory, które potwierdzają, że albo

static inline void *aa_alloc(int align, int size) 
{ 
    void *ret=0; 
    posix_memalign(&ret, align, size); // Guessing here 
    return ret; 
} 
#define a_alloc(align,sz) aa_alloc((align),(sz)) 
#define a_free(ptr) free((ptr)) 

na systemach POSIX itp Dla każdego systemu powinno być możliwe do zdefiniowania makra lub funkcje, które przyniosą niezbędną zachowanie [myślę, że to prawdopodobnie lepiej używać makr konsekwentnie niż czasami używać makr, a czasem funkcji, aby umożliwić #if defined macroname testowanie, czy rzeczy są jeszcze zdefiniowane].