La siguiente pregunta está relacionada, sin embargo, las respuestas son antiguas, y el comentario del usuario Marc Glisse sugiere que hay nuevos enfoques desde C ++ 17 a este problema que podrían no discutirse adecuadamente.
Estoy tratando de que la memoria alineada funcione correctamente para SIMD, sin dejar de tener acceso a todos los datos.
En Intel, si creo un vector de tipo flotante __m256
y reduzco mi tamaño en un factor de 8, me da memoria alineada.
P.ej std::vector<__m256> mvec_a((N*M)/8);
De una manera un poco hacky, puedo lanzar punteros a elementos vectoriales para flotar, lo que me permite acceder a valores de flotación individuales.
En cambio, preferiría tener uno std::vector<float>
que esté correctamente alineado y, por lo tanto, se pueda cargar en __m256
y otros tipos de SIMD sin segfaullar.
He estado buscando en alineado_alloc .
Esto me puede dar una matriz de estilo C que está correctamente alineada:
auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));
Sin embargo, no estoy seguro de cómo hacer esto std::vector<float>
. Dar la std::vector<float>
propiedad de marr_a
no parece ser posible .
He visto algunas sugerencias de que debería escribir un asignador personalizado , pero esto parece mucho trabajo, y tal vez con C ++ moderno ¿hay una mejor manera?
_mm256_loadu_ps(&vec[i])
. (Aunque tenga en cuenta que con las opciones de ajuste predeterminadas, GCC divide las cargas / tiendas de 256 bits no alineadas garantizadas en vmovups xmm / vinsertf128. Por lo tanto, es una ventaja usar_mm256_load
overloadu
si le importa cómo se compila su código en GCC si alguien olvida uso-mtune=...
u-march=
opciones.)Respuestas:
Todos los contenedores en la biblioteca estándar de C ++, incluidos los vectores, tienen un parámetro de plantilla opcional que especifica el asignador del contenedor , y en realidad no es mucho trabajo implementar el suyo:
Tendrá que escribir un poco de código que implemente su asignador, pero no sería mucho más código del que ya escribió. Si no necesita soporte anterior a C ++ 17, solo necesita implementar los métodos allocate () y deallocate () , eso es todo.
fuente
allocator_traits
vector<float, MAA>
no es compatible con el tipovector<float>
(y no puede ser porque todo lo que haga.push_back
en un planostd::vector<float>
compilado sin este asignador podría hacer una nueva asignación y copiar en una memoria mínimamente alineada. Y nuevo / eliminar no es compatible con alineado_alloc / gratis)std::vector
matriz. Por ejemplo, podría imaginar una implementación destd::vector
usar solo un puntero a la memoria asignada que almacena el final / capacidad / asignador en la memoria antes del rango de valores. Eso podría frustrar fácilmente la alineación realizada por el asignador.std::vector
garantiza. Para eso lo usa. Quizás debería revisar lo que el estándar C ++ especifica aquí.allocator_traits
. No, no lo hacen. Todo lo que se necesita es implementar un asignador compatible.