2015-09-16 35 views
18

Ci sono alcune opzioni per l'acquisizione di un blocco di memoria allineato, ma sono molto simili e il problema si riduce in gran parte a quale standard e piattaforme di linguaggio si sta prendendo di mira.Perché usare _mm_malloc? (al contrario di _aligned_malloc, alligned_alloc, o posix_memalign)

C11

void * aligned_alloc (size_t alignment, size_t size) 

POSIX

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

di Windows

void * _aligned_malloc(size_t size, size_t alignment); 

E naturalmente è anche sempre un'opzione per allineare a mano.

Intel offre un'altra opzione.

Intel

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

Basato sul codice sorgente rilasciato da Intel, questo sembra essere il metodo di ripartizione di memoria allineato i loro ingegneri preferiscono ma non riesco a trovare alcuna documentazione paragonandolo ad altri metodi. Il più vicino che ho trovato riconosce semplicemente che esistono altre routine di allocazione della memoria allineate.

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

Per assegnare dinamicamente un pezzo di memoria allineato, uso posix_memalign, che è supportato da GCC, nonche l'Intel compilatore. Il vantaggio di utilizzarlo è che non è necessario modificare l'API di eliminazione della memoria. Puoi usare free() come fai sempre. Ma fai attenzione al profilo dei parametri :

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

Il Compilatore Intel fornisce anche un altro set di allocazione di memoria API. I programmatori C/C++ possono utilizzare _mm_malloc e _mm_free per allocare e blocchi di memoria allineati liberi. Ad esempio, la seguente istruzione richiede un blocco di memoria allineato a 64 byte per 8 elementi in virgola mobile .

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

La memoria assegnata utilizzando _mm_malloc deve essere liberata utilizzando _mm_free. Chiamare gratuitamente sulla memoria allocata con _mm_malloc o chiamare _mm_free sulla memoria allocata con malloc risulterà in un comportamento imprevedibile.

Gli evidenti differenze da un punto di vista dell'utente è che _mm_malloc richiede CPU diretta e supporto compilatore e memoria allocata con _mm_malloc devono essere liberate con _mm_free. Considerati questi inconvenienti, qual è la ragione per cui si usa sempre _mm_malloc? Può avere un leggero vantaggio in termini di prestazioni? Incidente storico?

+1

Hai letto tutto il documento che colleghi? Non ti aspetti che lo riassumiamo, vero? – alk

+4

@alk Non c'è motivo di essere scortesi. Se la risposta è ovvia per te, per favore spiega. – Praxeolitic

+1

Potrebbe sembrare scortese, non è inteso in questo modo. È una domanda, probabilmente un po 'sarcastica. – alk

risposta

19

È molto facile capire questa situazione. I compilatori Intel supportano i sistemi operativi POSIX (Linux) e non POSIX (Windows), quindi non possono fare affidamento sulla funzione POSIX o Windows. Pertanto, è stata scelta una soluzione indipendente dal compilatore ma OS-agnostica.

C11 è un'ottima soluzione, ma Microsoft non supporta ancora C99, quindi chissà se mai supporteranno C11.

Disclaimer: Lavoro per Intel ma non ho alcuna conoscenza specifica di queste decisioni, cosa che è accaduta molto tempo prima di entrare in azienda.

+1

Oh, eh, in effetti è molto semplice e ha perfettamente senso! È facile diventare miopi sul proprio sistema operativo e non realizzare queste cose. – Praxeolitic

4

_mm_malloc sembra essere stato creato prima che esistesse una funzione standard align_alloc e la necessità di utilizzare _mm_free è una stranezza dell'implementazione.

La mia ipotesi è che a differenza di quando si utilizza posix_memalign, non è necessario sovra-allocare per garantire l'allineamento, ma utilizza un allocatore separato per l'allineamento. Ciò consente di risparmiare memoria quando si assegnano tipi con allineamento diverso rispetto all'allineamento predefinito (in genere 8 o 16 byte).

4

È possibile prendere un compilatore C esistente che attualmente non utilizza gli identificatori _mm_alloc e _mm_free e definire le funzioni con quei nomi che si comporteranno come richiesto. Questo può essere fatto con la funzione _mm_alloc come wrapper su malloc() che richiede un'allocazione leggermente sovradimensionata e costruisce un puntatore al primo indirizzo opportunamente allineato al suo interno che è almeno un byte dall'inizio e memorizza il numero di byte saltato immediatamente prima di quell'indirizzo, o avendo _mm_malloc richiedere grossi pezzi di memoria da malloc() e quindi distribuirli frammentari. In ogni caso, i puntatori restituiti da _mm_malloc() non sarebbero puntatori che in genere lo free() sa come fare qualsiasi cosa; chiamando _mm_free si utilizzerà il byte immediatamente precedente all'assegnazione come ausilio per trovare il vero inizio dell'allocazione ricevuta da malloc e quindi passare quello free.

Se una funzione di allocazione allineata è consentita per utilizzare le parti interne delle funzioni malloc e , tuttavia, ciò potrebbe eliminare la necessità del livello aggiuntivo di avvolgimento. È possibile scrivere le funzioni _mm_alloc()/_mm_free() che avvolge malloc/free senza sapere nulla del loro interno, ma richiede che _mm_alloc() conservi le informazioni di conservazione del libro che è separato da quello utilizzato da malloc/free.

Se l'autore di una funzione allineata-allocare sa malloc e free sono implementate, spesso sarà possibile coordinare l'elaborazione di tutte le/funzioni libere di assegnazione in modo che free possono distinguere tutti i tipi di allocazioni e gestirli adeguatamente . Nessuna implementazione allocata allineata singola sarebbe utilizzabile su tutte le implementazioni malloc/free, tuttavia.

Suggerirei che il modo più portabile per scrivere codice sarebbe probabilmente quello di selezionare un paio di simboli che non vengono utilizzati da nessun'altra parte per le proprie funzioni allocate e libere, in modo tale da poter quindi dire, ad es.

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

su compilatori che supportano questo, o

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)) 

sui sistemi POSIX, ecc Per ogni sistema dovrebbe essere possibile definire le macro o funzioni che consentiranno di ottenere il comportamento necessario [Penso che sia probabilmente è meglio usare le macro in modo coerente che a volte utilizzare macro e talvolta funzioni, in modo da consentire a #if defined macroname di verificare se le cose sono ancora definite].