Il existe quelques options pour acquérir un bloc de mémoire aligné, mais elles sont très similaires et le problème se résume principalement à la norme de langue et aux plates-formes que vous ciblez.
C11
void * aligned_alloc (size_t alignment, size_t size)
POSIX
int posix_memalign (void **memptr, size_t alignment, size_t size)
Les fenêtres
void * _aligned_malloc(size_t size, size_t alignment);
Et bien sûr, c'est aussi toujours une option pour s'aligner à la main.
Intel propose une autre option.
Intel
void* _mm_malloc (int size, int align)
void _mm_free (void *p)
Basé sur le code source publié par Intel, cela semble être la méthode d'allocation de mémoire alignée que leurs ingénieurs préfèrent, mais je ne trouve aucune documentation la comparant à d'autres méthodes. Le plus proche que j'ai trouvé reconnaît simplement qu'il existe d'autres routines d'allocation de mémoire alignées.
Pour allouer dynamiquement un morceau de mémoire alignée, utilisez posix_memalign, qui est pris en charge par GCC ainsi que le compilateur Intel. L'avantage de l'utiliser est que vous n'avez pas à modifier l'API de suppression de mémoire. Vous pouvez utiliser free () comme vous le faites toujours. Mais attention au profil des paramètres:
int posix_memalign (void ** memptr, size_t align, size_t size);
Le compilateur Intel fournit également un autre ensemble d'API d'allocation de mémoire. Les programmeurs C/C++ peuvent utiliser _mm_malloc et _mm_free pour allouer et libérer des blocs de mémoire alignés. Par exemple, l'instruction suivante demande un bloc de mémoire aligné sur 64 octets pour 8 éléments à virgule flottante.
farray = (float *) __ mm_malloc (8 * sizeof (float), 64);
La mémoire allouée à l'aide de _mm_malloc doit être libérée à l'aide de _mm_free. Appeler gratuitement sur la mémoire allouée avec _mm_malloc ou appeler _mm_free sur la mémoire allouée avec malloc entraînera un comportement imprévisible.
Les différences évidentes du point de vue de l'utilisateur sont que _mm_malloc
nécessite une prise en charge directe du CPU et du compilateur et de la mémoire allouée avec _mm_malloc
doit être libéré avec _mm_free
. Compte tenu de ces inconvénients, quelle est la raison de toujours utiliser _mm_malloc?
Peut-il avoir un léger avantage en termes de performances? Accident historique?
Les compilateurs Intel prennent en charge les systèmes d'exploitation POSIX (Linux) et non POSIX (Windows) et ne peuvent donc pas compter sur la fonction POSIX ou Windows. Ainsi, une solution spécifique au compilateur mais indépendante du système d'exploitation a été choisie.
C11 est une excellente solution, mais Microsoft ne prend même pas encore en charge C99, alors qui sait s'ils prendront jamais en charge C11.
Mise à jour: Contrairement aux fonctions d'allocation C11/POSIX/Windows, les intrinsèques ICC incluent une fonction de désallocation. Cela permet à cette API d'utiliser un gestionnaire de tas distinct de celui par défaut. Je ne sais pas si/quand il le fait, mais il peut être utile de prendre en charge ce modèle.
Clause de non-responsabilité: je travaille pour Intel, mais je n'ai aucune connaissance particulière de ces décisions, qui se sont produites bien avant de rejoindre la société.
Il est possible de prendre un compilateur C existant qui n'utilise pas actuellement les identifiants _mm_alloc
Et _mm_free
Et de définir des fonctions avec ces noms qui se comporteront comme requis. Cela pourrait être fait en ayant la fonction _mm_alloc
Comme un wrapper sur malloc()
qui demande une allocation légèrement surdimensionnée et construit un pointeur vers la première adresse convenablement alignée en son sein qui est au moins une octet depuis le début et en stockant le nombre d'octets ignorés juste avant cette adresse, ou en demandant à _mm_malloc
de demander de gros morceaux de mémoire à malloc()
, puis de les distribuer au coup par coup. Dans tous les cas, les pointeurs renvoyés par _mm_malloc()
ne seraient pas des pointeurs avec lesquels free()
saurait généralement faire quoi que ce soit; appeler _mm_free
utiliserait l'octet précédant immédiatement l'allocation comme une aide pour trouver le début réel de l'allocation reçue de malloc
, puis passerait ce faire free
.
Cependant, si une fonction d'allocation alignée est autorisée à utiliser les fonctions internes des fonctions malloc
et free
, cela peut éliminer le besoin d'une couche supplémentaire d'encapsulation. Il est possible d'écrire des fonctions _mm_alloc()
/_mm_free()
qui enveloppent malloc
/free
sans rien savoir de leurs internes, mais cela nécessite que _mm_alloc()
conserve les informations de comptabilité qui sont distinctes de celles utilisées par malloc
/free
.
Si l'auteur d'une fonction d'allocation alignée sait comment malloc
et free
sont implémentés, il sera souvent possible de coordonner la conception de toutes les fonctions d'allocation/libres afin que free
peut distinguer toutes sortes d'allocations et les gérer de manière appropriée. Cependant, aucune implémentation d'allocation alignée unique ne serait utilisable sur toutes les implémentations malloc
/free
.
Je suggérerais que la façon la plus portable d'écrire du code serait probablement de sélectionner quelques symboles qui ne sont utilisés nulle part ailleurs pour vos propres fonctions d'allocation et de libre, afin que vous puissiez ensuite dire, par exemple.
#define a_alloc(align,sz) _mm_alloc((align),(sz))
#define a_free(ptr) _mm_free((ptr))
sur les compilateurs qui prennent en charge cela, ou
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))
sur les systèmes Posix, etc. Pour chaque système, il devrait être possible de définir des macros ou des fonctions qui produiront le comportement nécessaire [Je pense qu'il est probablement préférable d'utiliser des macros de manière cohérente que d'utiliser parfois des macros et parfois des fonctions, afin de permettre #if defined macroname
Pour tester si les choses sont encore définies].
_mm_malloc semble avoir été créé avant qu'il n'y ait une fonction alignée_alloc standard, et la nécessité d'utiliser _mm_free est une bizarrerie de l'implémentation.
Je suppose que contrairement à l'utilisation de posix_memalign, il n'a pas besoin de surallouer pour garantir l'alignement, mais utilise un allocateur distinct compatible avec l'alignement. Cela économisera de la mémoire lors de l'allocation de types avec un alignement différent de l'alignement par défaut (généralement 8 ou 16 octets).