c arm benchmarking embedded-linux cortex-a

Medición de los efectos de TLB en un Cortex-A9



arm benchmarking (1)

Después de leer el siguiente documento https://people.freebsd.org/~lstewart/articles/cpumemory.pdf ("Lo que todo programador debería saber sobre la memoria") quería probar una de las pruebas del autor, es decir, medir los efectos de TLB en el tiempo de ejecución final.

Estoy trabajando en un Samsung Galaxy S3 que incorpora un Cortex-A9.

Según la documentación:

Escribí un pequeño programa que asigna una matriz de estructuras con N entradas. El tamaño de cada entrada es == 32 bytes, por lo que cabe en una línea de caché. Realizo varios accesos de lectura y mido el tiempo de ejecución.

typedef struct { int elmt; // sizeof(int) == 4 bytes char padding[28]; // 4 + 28 = 32B == cache line size }entry; volatile entry ** entries = NULL; //Allocate memory and init to 0 entries = calloc(NB_ENTRIES, sizeof(entry *)); if(entries == NULL) perror("calloc failed"); exit(1); for(i = 0; i < NB_ENTRIES; i++) { entries[i] = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if(entries[i] == MAP_FAILED) perror("mmap failed"); exit(1); } entries[LAST_ELEMENT]->elmt = -1 //Randomly access and init with random values n = -1; i = 0; while(++n < NB_ENTRIES -1) { //init with random value entries[i]->elmt = rand() % NB_ENTRIES; //loop till we reach the last element while(entries[entries[i]->elmt]->elmt != -1) { entries[i]->elmt++; if(entries[i]->elmt == NB_ENTRIES) entries[i]->elmt = 0; } i = entries[i]->elmt; } gettimeofday(&tStart, NULL); for(i = 0; i < NB_LOOPS; i++) { j = 0; while(j != -1) { j = entries[j]->elmt } } gettimeofday(&tEnd, NULL); time = (tEnd.tv_sec - tStart.tv_sec); time *= 1000000; time += tEnd.tv_usec - tStart.tv_usec; time *= 100000 time /= (NB_ENTRIES * NBLOOPS); fprintf(stdout, "%d %3lld.%02lld/n", NB_ENTRIES, time / 100, time % 100);

Tengo un bucle externo que hace que NB_ENTRIES varíe de 4 a 1024.

Como se puede ver en la figura siguiente, mientras que NB_ENTRIES == 256 entradas, el tiempo de ejecución es más largo.

Cuando NB_ENTRIES == 404 obtengo una "memoria insuficiente" (¿por qué? ¿Se superaron los TLB micro? ¿Se superaron los TLB principales? ¿Se excedieron las tablas de páginas? ¿Se excedió la memoria virtual para el proceso?)

¿Puede alguien explicarme por favor qué es lo que realmente está pasando de 4 a 256 entradas, luego de 257 a 404 entradas?

EDITAR 1

Como se ha sugerido, corrí membench ( código src ) y debajo de los resultados:

Editar 2

En el siguiente paper (página 3) ejecutaron (supongo) el mismo punto de referencia. Pero los diferentes pasos son claramente visibles desde sus tramas, que no es mi caso.

En este momento, de acuerdo con sus resultados y explicaciones, solo puedo identificar algunas cosas.

  • los gráficos confirman que el tamaño de la línea de caché L1 es de 32 bytes porque, como decían

"una vez que el tamaño de la matriz excede el tamaño de la memoria caché de datos (32KB), las lecturas comienzan a generar, [...] se produce un punto de inflexión cuando cada lectura genera un error".

En mi caso, el primer punto de inflexión aparece cuando zancada == 32 bytes. - El gráfico muestra que tenemos un caché de segundo nivel (L2). Creo que está representado por la línea amarilla (1MB == L2 tamaño) - Por lo tanto, los dos últimos gráficos sobre este último probablemente reflejan la latencia al acceder a la memoria principal (¿+ TLB?).

Sin embargo, a partir de este punto de referencia, no puedo identificar:

  • La asociatividad del caché. Normalmente, D-Cache y I-Cache son asociativas de 4 vías ( Cortex-A9 TRM ).
  • Los efectos TLB. Como decian

en la mayoría de los sistemas, un aumento secundario en la latencia es indicativo del TLB, que almacena un número limitado de traducciones virtuales a físicas. [..] La ausencia de un aumento en la latencia atribuible al TLB indica que [...] "

Probablemente se han utilizado / implementado grandes páginas.

EDITAR 3

Este link explica los efectos TLB de otro gráfico de membench. Uno puede recuperar los mismos efectos en mi gráfica.

En un sistema de páginas de 4KB, a medida que aumente la velocidad, mientras siguen siendo <4K, disfrutará de un uso cada vez menor de cada página, [...] tendrá que acceder al TLB de 2º nivel en cada acceso [ ...]

El cortex-A9 soporta el modo de páginas de 4KB . De hecho, como se puede ver en mi gráfico hasta zancadas == 4K, las latencias aumentan, luego, cuando llega a 4K

de repente empiezas a beneficiarte de nuevo porque en realidad te estás saltando páginas enteras.


tl; dr -> Proporcionar un MVCE adecuado.

Esta respuesta debe ser un comentario, pero es demasiado grande para publicarse como comentario, por lo tanto, publicar como respuesta en su lugar:

  1. Tuve que arreglar un montón de errores de sintaxis (puntos y comas que faltan) y declarar variables no definidas.

  2. Después de solucionar todos esos problemas, el código NO HIZO NADA (el programa se cerró incluso antes de ejecutar el primer mmap . Le estoy dando la punta para usar llaves cada vez, aquí está su primer error y el segundo causado por NO haberlo hecho:

.

// after calloc: if(entries == NULL) perror("calloc failed"); exit(1); // after mmap if(entries[i] == MAP_FAILED) perror("mmap failed"); exit(1);

ambas líneas terminan su programa independientemente de la condición.

  1. Aquí tienes un bucle sin fin (reformateado, se añaden rizos pero no hay otro cambio):

.

//Randomly access and init with random values n = -1; i = 0; while (++n < NB_ENTRIES -1) { //init with random value entries[i]->elmt = rand() % NB_ENTRIES; //loop till we reach the last element while (entries[entries[i]->elmt]->elmt != -1) { entries[i]->elmt++; if (entries[i]->elmt == NB_ENTRIES) { entries[i]->elmt = 0; } } i = entries[i]->elmt; }

La primera iteración comienza estableciendo las entries[0]->elmt a algún valor aleatorio, luego los incrementos del bucle interno hasta que llega a LAST_ELEMENT . Entonces i se establece en ese valor (es decir, LAST_ELEMENT ) y el segundo bucle sobrescribe el marcador final -1 en algún otro valor aleatorio. Entonces se incrementa constantemente el mod NB_ENTRIES en el bucle interno hasta que presionas CTRL + C.

Conclusión

Si desea ayuda, publique un MVCE y no otra cosa.