studio programacion para móviles libro edición desarrollo desarrollar curso aprende aplicaciones c++ alignment c++11

c++ - para - manual de programacion android pdf



Determinando la alineación máxima posible en C++ (6)

A falta de un tipo maximally_aligned_t que todos los compiladores prometieron fielmente para soportar todas las arquitecturas en todas partes, no veo cómo esto podría resolverse en tiempo de compilación. Como usted dice, el conjunto de tipos potenciales es ilimitado. ¿Es el puntero adicional indirecto realmente tan importante?

¿Hay alguna forma portátil para determinar cuál es la alineación máxima posible para cualquier tipo?

Por ejemplo, en x86, las instrucciones SSE requieren una alineación de 16 bytes, pero hasta donde sé, ninguna instrucción requiere más que eso, por lo que cualquier tipo puede almacenarse de manera segura en un búfer alineado de 16 bytes.

Necesito crear un búfer (como una matriz de caracteres) donde pueda escribir objetos de tipos arbitrarios, por lo que necesito poder confiar en el inicio del búfer para alinear.

Si todo lo demás falla, sé que la asignación de una matriz char con new garantiza una alineación máxima, pero con las plantillas TR1 / C ++ 0x aligned_storage y aligned_storage , me pregunto si sería posible crear el búfer en el lugar en mi clase de búfer, en lugar de requerir el direccionamiento de puntero adicional de una matriz asignada dinámicamente.

Ideas?

Me doy cuenta de que hay muchas opciones para determinar la alineación máxima para un conjunto de tipos acotados: una unión, o simplemente la alignment_of TR1, pero mi problema es que el conjunto de tipos no tiene límites. No sé de antemano qué objetos deben almacenarse en el búfer.


Desafortunadamente, asegurar la alineación máxima es mucho más difícil de lo que debería ser, y no hay soluciones garantizadas AFAIK. Desde el blog de GotW ( artículo de Fast Pimpl ):

union max_align { short dummy0; long dummy1; double dummy2; long double dummy3; void* dummy4; /*...and pointers to functions, pointers to member functions, pointers to member data, pointers to classes, eye of newt, ...*/ }; union { max_align m; char x_[sizeofx]; };

No se garantiza que sea totalmente portátil, pero en la práctica es lo suficientemente cerca porque hay pocos o ningún sistema en el que no funcionará como se esperaba.

Eso es sobre el ''truco'' más cercano que conozco por esto.

Hay otro enfoque que he usado personalmente para la asignación súper rápida. Tenga en cuenta que es malo, pero trabajo en campos de trazado de rayos donde la velocidad es una de las mejores medidas de calidad y contamos con un código de perfil a diario. Implica el uso de un asignador de pila con memoria asignada previamente que funciona como la pila local (solo incrementa un puntero en la asignación y disminuye uno en la desasignación).

Lo uso para Pimpls particularmente. Sin embargo, solo tener el asignador no es suficiente; para que este asignador funcione, debemos asumir que la memoria para una clase, Foo, se asigna en un constructor, la misma memoria se desasigna también en el destructor, y que Foo se crea en la pila. Para hacerlo seguro, necesitaba una función para ver si el puntero ''este'' de una clase está en la pila local para determinar si podemos usar nuestro asignador de pila súper rápido basado en el montón. Para eso tuvimos que TIBs soluciones específicas del sistema operativo: utilicé TIBs y TIBs para Win32 / Win64, y mis compañeros de trabajo encontraron soluciones para Linux y Mac OS X.

El resultado, después de una semana de investigación de métodos específicos del sistema operativo para detectar el rango de la pila, los requisitos de alineación y hacer muchas pruebas y perfiles, fue un asignador que podría asignar memoria en 4 ciclos de reloj de acuerdo con nuestros puntos de referencia de contador de ticks en lugar de aproximadamente 400 ciclos para malloc / operator new (nuestra prueba involucró la contención de hilos, por lo que es probable que malloc sea un poco más rápido que esto en casos de un solo hilo, quizás un par de cientos de ciclos). Añadimos una pila de pilas por subproceso y detectamos qué subproceso se estaba utilizando, lo que aumentó el tiempo a aproximadamente 12 ciclos, aunque el cliente puede realizar un seguimiento del asignador de subprocesos para obtener las asignaciones de 4 ciclos. Se borró de la asignación de memoria puntos de acceso en el mapa.

Si bien no tiene que pasar por todos esos problemas, escribir un asignador rápido puede ser más fácil y más generalmente aplicable (por ejemplo, permitir que la cantidad de memoria para asignar / desasignar se determine en tiempo de ejecución) que algo como max_align aquí. max_align es fácil de usar, pero si buscas velocidad para las asignaciones de memoria (y suponiendo que ya has perfilado tu código y has encontrado puntos de acceso en malloc / free / operator new / delete con los principales colaboradores en el código sobre el que tienes control) , escribir tu propio asignador realmente puede hacer la diferencia.


En C ++ 0x, el parámetro Align plantilla de std::aligned_storage<Len, Align> tiene un argumento predeterminado de "alineación predeterminada", que se define como (N3225 §20.7.6.6 Tabla 56):

El valor de la alineación predeterminada será el requisito de alineación más estricto para cualquier tipo de objeto C ++ cuyo tamaño no sea mayor que Len .

No está claro si los tipos SSE se considerarían "tipos de objetos C ++".

El argumento predeterminado no era parte de TR1 aligned_storage ; Fue añadido para C ++ 0x.


En C ++ 11 std :: max_align_t definido en el encabezado cstddef es un tipo POD cuyo requisito de alineación es al menos tan estricto (tan grande) como el de cada tipo escalar.

Usar el nuevo operador alignin sería tan simple como alignof(std::max_align_t)


Esto es lo que estoy usando. Además de esto, si está asignando memoria, una nueva () matriz de caracteres con una longitud mayor o igual a max_alignment se alineará con max_alignment para que luego pueda usar índices en esa matriz para obtener direcciones alineadas.

enum { max_alignment = boost::mpl::deref< boost::mpl::max_element< boost::mpl::vector< boost::mpl::int_<boost::alignment_of<signed char>::value>::type, boost::mpl::int_<boost::alignment_of<short int>::value>::type, boost::mpl::int_<boost::alignment_of<int>::value>::type, boost::mpl::int_<boost::alignment_of<long int>::value>::type, boost::mpl::int_<boost::alignment_of<float>::value>::type, boost::mpl::int_<boost::alignment_of<double>::value>::type, boost::mpl::int_<boost::alignment_of<long double>::value>::type, boost::mpl::int_<boost::alignment_of<void*>::value>::type >::type >::type >::type::value }; }