web-dev-qa-db-fra.com

Pourquoi utiliser _mm_malloc? (par opposition à _aligned_malloc, alligned_alloc ou posix_memalign)

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.

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

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?

28
Praxeolitic

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é.

26
Jeff

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].

5
supercat

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

4
Thief