keywords - ¿Cómo detectaría genéricamente la asociatividad de línea de caché desde el código de modo de usuario?
meta tags generator (3)
Estoy armando un pequeño parche para la herramienta cachegrind / callgrind en valgrind que se detectará automáticamente, utilizando un código completamente genérico, instrucciones de CPU y configuración de caché (en este momento solo se configura automáticamente x86 / x64, y otras arquitecturas no proporcionan Configuración de tipo CPUID a código no privilegiado). Este código deberá ejecutarse completamente en un contexto sin privilegios, es decir, código de modo de usuario puro. También debe ser portátil a través de implementaciones POSIX muy diferentes, por lo que grokking / proc / cpuinfo no funcionará ya que uno de nuestros sistemas de destino no tiene tal cosa.
La detección de la frecuencia de la CPU, el número de cachés, sus tamaños e incluso el tamaño de la línea de caché se puede realizar utilizando un código POSIX 100% genérico que no tiene ningún código de operación específico de la CPU (solo una gran cantidad de suposiciones razonables, como la adición dos números juntos, si sin memoria o registro se detiene la dependencia, probablemente se ejecutarán en un solo ciclo). Esta parte es bastante sencilla.
Lo que no es tan sencillo, y por qué le pregunto a StackOverflow, es cómo detectar la asociatividad de línea de caché para un caché dado. La asociatividad es la cantidad de lugares en un caché que puede contener una línea de caché dada desde la memoria principal. Puedo ver que la asociatividad de caché L1 podría detectarse, pero ¿caché L2? ¿Seguramente la asociatividad L1 se interpone en el camino?
Aprecio que este es probablemente un problema que no se puede resolver. Pero lo tiro a StackOverflow y espero que alguien sepa algo que yo no. Tenga en cuenta que si fallamos aquí, simplemente codificaré el código en una asociación de forma predeterminada de cuatro maneras, asumiendo que no supondría una gran diferencia en los resultados.
Gracias,
Niall
¿Podrías hacer un pequeño programa que solo acceda a líneas desde el mismo conjunto? Luego puede aumentar la distancia de pila entre los accesos y cuando el tiempo de ejecución caiga dramáticamente, puede asumir que ha alcanzado la asociatividad.
Probablemente no sea muy estable, pero tal vez eso podría dar una pista, no sé. Espero que pueda ayudar.
Aquí hay un esquema:
Tenga un patrón de acceso a la memoria con una zancada S y la cantidad de elementos únicos a los que accedió = N. La prueba primero toca cada elemento único, y luego mide el tiempo promedio para acceder a cada elemento, accediendo al mismo patrón una gran cantidad de veces.
Ejemplo: para S = 2 y N = 4 el patrón de dirección sería 0,2,4,6,0,2,4,6,0,2,4,6, ...
Considere una jerarquía de caché multinivel. Puede hacer las siguientes suposiciones razonables:
- El tamaño de la memoria caché de nivel n + 1 es una potencia de dos veces el tamaño de la memoria caché n.
- La asociatividad de n + 1 ° caché también es una potencia de dos veces la asociatividad de la caché n.
Estas 2 suposiciones nos permiten decir que si dos direcciones se asignan al mismo conjunto en n + 1 ° caché (por ejemplo, L2), entonces deben asignarse al mismo conjunto en el enésimo caché (por ejemplo, L1).
Digamos que conoces los tamaños de L1, L2 caches. Necesitas encontrar la asociatividad de la caché L2.
- establecer zancada S = tamaño de caché L2 (de modo que cada acceso se asigna al mismo conjunto en L2, y también en L1)
- variar N (por potencias de 2)
Obtienes los siguientes regímenes:
- Régimen 1: N <= asociatividad de L1. (Todos los accesos HIT en L1)
- Régimen 2: asociatividad de L1 <N <= asociatividad de L2 (todos los accesos fallan en L1, pero HIT en L2)
- Régimen 3: N> asociatividad de L2 (todos los accesos faltan en L2)
Por lo tanto, si traza el tiempo de acceso promedio contra N (cuando S = tamaño de L2), verá una gráfica escalonada. El final del paso más bajo te da la asociatividad de L1. El siguiente paso te da la asociatividad de L2.
Puede repetir el mismo procedimiento entre L2-L3 y así sucesivamente. Por favor, hágamelo saber si eso ayuda. El método para obtener parámetros de caché variando el paso de un patrón de acceso a la memoria es similar al utilizado por el punto de referencia LMBENCH. No sé si lmbench infiere asociatividad también.
Para la plataforma x86 puedes usar cpuid
:
Consulte http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html para obtener más información.
Necesitas algo como:
long _eax,_ebx,_ecx,_edx;
long op = func;
asm ("cpuid"
: "=a" (_eax),
"=b" (_ebx),
"=c" (_ecx),
"=d" (_edx)
: "a" (op)
);
Luego use la información según el documento en el enlace mencionado anteriormente.