Approche moderne pour faire std :: vector allouer de la mémoire alignée

11

La question suivante est liée, mais les réponses sont anciennes, et le commentaire de l'utilisateur Marc Glisse suggère qu'il existe de nouvelles approches depuis C ++ 17 à ce problème qui pourraient ne pas être discutées de manière adéquate.

J'essaie de faire fonctionner correctement la mémoire alignée pour SIMD, tout en ayant accès à toutes les données.

Sur Intel, si je crée un vecteur flottant de type __m256et que je réduis ma taille d'un facteur 8, cela me donne une mémoire alignée.

Par exemple std::vector<__m256> mvec_a((N*M)/8);

D'une manière légèrement hacky, je peux lancer des pointeurs sur des éléments vectoriels à flotter, ce qui me permet d'accéder aux valeurs flottantes individuelles.

Au lieu de cela, je préférerais avoir un std::vector<float>qui est correctement aligné, et donc peut être chargé dans __m256et d'autres types SIMD sans segfaulting.

J'ai cherché dans align_alloc .

Cela peut me donner un tableau de style C correctement aligné:

auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));

Cependant, je ne sais pas comment faire cela std::vector<float>. Donner la std::vector<float>propriété de marr_a ne semble pas être possible .

J'ai vu quelques suggestions que je devrais écrire un allocateur personnalisé , mais cela semble beaucoup de travail, et peut-être qu'avec le C ++ moderne, il y a une meilleure façon?

Prunus Persica
la source
1
sans segfaulting ... ou sans ralentissements potentiels des divisions de ligne de cache lorsque vous utilisez _mm256_loadu_ps(&vec[i]). (Bien que notez qu'avec les options de réglage par défaut, GCC divise les charges / magasins 256 bits alignés non garantis en vmovups xmm / vinsertf128. Il y a donc un avantage à utiliser _mm256_loadover loadusi vous vous souciez de la façon dont votre code se compile sur GCC si quelqu'un oublie de utilisation -mtune=...ou -march=options.)
Peter Cordes

Réponses:

1

Tous les conteneurs de la bibliothèque C ++ standard, y compris les vecteurs, ont un paramètre de modèle facultatif qui spécifie l'allocateur du conteneur , et ce n'est pas vraiment beaucoup de travail d'implémenter le vôtre:

class my_awesome_allocator {
};

std::vector<float, my_awesome_allocator> awesomely_allocated_vector;

Vous devrez écrire un peu de code qui implémente votre allocateur, mais ce ne serait pas beaucoup plus de code que vous ne l'avez déjà écrit. Si vous ne avez pas besoin pré-C ++ 17 soutien dont vous avez seulement besoin de mettre en œuvre les allouer () et deallocate () méthodes, c'est tout.

Sam Varshavchik
la source
Ils doivent également se spécialiserallocator_traits
NathanOliver
1
Cela pourrait être un bon endroit pour une réponse canonique avec un exemple que les gens peuvent copier / coller pour sauter à travers les cadres ennuyeux de C ++. (Des points bonus s'il y a un moyen de laisser std :: vector essayer de réallouer en place au lieu du braindead habituel C ++ toujours allouer + copier.) Notez également bien sûr que ce vector<float, MAA>n'est pas compatible avec le type vector<float>(et ne peut pas être parce que tout ce qui fait .push_backsur un simple std::vector<float>compilé sans cet allocateur pourrait faire une nouvelle allocation et copier dans la mémoire à alignement minimal. Et new / delete n'est pas compatible avec align_alloc / free)
Peter Cordes
1
Je ne pense pas qu'il y ait de garantie que le pointeur renvoyé par l'allocateur soit directement utilisé comme adresse de base du std::vectortableau de. Par exemple, je pourrais imaginer une implémentation de l' std::vectorutilisation d'un seul pointeur vers la mémoire allouée qui stocke la fin / capacité / allocateur dans la mémoire avant la plage de valeurs. Cela pourrait facilement déjouer l'alignement effectué par l'allocateur.
Dietmar Kühl
1
Sauf que std::vectorça le garantit. C'est pour ça qu'il l'utilise. Vous devriez peut-être revoir ce que la norme C ++ spécifie ici.
Sam Varshavchik
1
> Ils doivent également se spécialiser allocator_traits- Non, ils ne le font pas. Il suffit d'implémenter un allocateur conforme.
Andrey Semashev