Esto es para ARM.
GCC proporciona __builtin___clear_cache
que hace debe hacer syscall cacheflush
. Sin embargo, puede tener sus advertencias.
Lo importante aquí es que Linux proporciona una llamada al sistema (específica de ARM) para vaciar cachés. Puede consultar Android/Bionic flushcache para saber cómo usar esta llamada al sistema. Sin embargo, no estoy seguro de qué tipo de garantías da Linux cuando lo llama o cómo se implementa a través de su funcionamiento interno.
Esta publicación de blog Cachés y código automodificable puede ayudar más.
Consulte esta página para obtener una lista de los métodos de descarga disponibles en el kernel de Linux:https://www.kernel.org/doc/Documentation/cachetlb.txt
Vaciado de caché y TLB en Linux. David S. Miller
Hay un conjunto de funciones de lavado de rango
2) flush_cache_range(vma, start, end);
change_range_of_page_tables(mm, start, end);
flush_tlb_range(vma, start, end);
3) void flush_cache_range(struct vm_area_struct *vma,inicio largo sin firmar, final largo sin firmar)
Here we are flushing a specific range of (user) virtual
addresses from the cache. After running, there will be no
entries in the cache for 'vma->vm_mm' for virtual addresses in
the range 'start' to 'end-1'.
También puede verificar la implementación de la función:http://lxr.free-electrons.com/ident?a=sh;i=flush_cache_range
Por ejemplo, en brazo:http://lxr.free-electrons.com/source/arch/arm/mm/flush.c?a=sh&v=3.13#L67
67 void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
68 {
69 if (cache_is_vivt()) {
70 vivt_flush_cache_range(vma, start, end);
71 return;
72 }
73
74 if (cache_is_vipt_aliasing()) {
75 asm( "mcr p15, 0, %0, c7, c14, 0\n"
76 " mcr p15, 0, %0, c7, c10, 4"
77 :
78 : "r" (0)
79 : "cc");
80 }
81
82 if (vma->vm_flags & VM_EXEC)
83 __flush_icache_all();
84 }
En la versión x86 de Linux también puedes encontrar una función void clflush_cache_range(void *vaddr, unsigned int size)
que se utiliza con el propósito de vaciar un rango de caché. Esta función se basa en el CLFLUSH
o CLFLUSHOPT
instrucciones. Recomendaría verificar que su procesador realmente los admita, porque en teoría son opcionales.
CLFLUSHOPT
está débilmente ordenado. CLFLUSH
se especificó originalmente como ordenado solo por MFENCE
, pero todas las CPU que lo implementan lo hacen con un orden fuerte wrt. escrituras y otros CLFLUSH
instrucciones. Intel decidió agregar una nueva instrucción (CLFLUSHOPT
) en lugar de cambiar el comportamiento de CLFLUSH
y actualizar el manual para garantizar que las CPU futuras implementarán CLFLUSH
tan fuertemente ordenado. Para este uso, debe MFENCE
después de usar cualquiera de los dos, para asegurarse de que el lavado se realice antes de cualquier carga desde su punto de referencia (no solo las tiendas).
En realidad, x86 proporciona una instrucción más que podría ser útil:CLWB
. CLWB
vacía los datos del caché a la memoria sin (necesariamente) desalojarlos, dejándolos limpios pero aún en caché. clwb
en SKX desaloja como clflushopt
, aunque
Tenga en cuenta también que estas instrucciones son coherentes con la memoria caché. Su ejecución afectará todos los cachés de todos los procesadores (núcleos de procesador) en el sistema.
Todas estas tres instrucciones están disponibles en el modo de usuario. Por lo tanto, puede emplear ensamblador (o intrínsecos como _mm_clflushopt
) y crea tu propio void clflush_cache_range(void *vaddr, unsigned int size)
en su aplicación de espacio de usuario (pero no olvide verificar su disponibilidad, antes del uso real).
Si entiendo correctamente, es mucho más difícil razonar sobre ARM a este respecto. La familia de procesadores ARM es mucho menos consistente que la familia de procesadores IA-32. Puede tener un ARM con cachés con todas las funciones y otro completamente sin cachés. Además, muchos fabricantes pueden utilizar MMU y MPU personalizados. Por lo tanto, es mejor razonar sobre algún modelo de procesador ARM en particular.
Desafortunadamente, parece que será casi imposible realizar una estimación razonable del tiempo necesario para vaciar algunos datos. Este tiempo se ve afectado por demasiados factores, incluido el número de líneas de caché vaciadas, la ejecución desordenada de instrucciones, el estado de TLB (porque la instrucción toma una dirección virtual como argumento, pero los cachés usan direcciones físicas), el número de CPU en el sistema, la carga real en términos de operaciones de memoria en los otros procesadores del sistema, y cuántas líneas del rango son realmente almacenadas en caché por los procesadores y, finalmente, por el rendimiento de la CPU, la memoria, el controlador de memoria y el bus de memoria. Como resultado, creo que el tiempo de ejecución variará significativamente en diferentes entornos y con diferentes cargas. La única forma razonable es medir el tiempo de descarga en el sistema y con una carga similar a la del sistema de destino.
Y nota final, no confundas cachés de memoria y TLB. Ambos son cachés, pero están organizados de diferentes maneras y tienen diferentes propósitos. TLB almacena en caché solo las traducciones utilizadas más recientemente entre direcciones virtuales y físicas, pero no los datos a los que apuntan esas direcciones.
Y TLB no es coherente, en contraste con los cachés de memoria. Tenga cuidado, porque el vaciado de las entradas de TLB no provoca el vaciado de los datos apropiados de la memoria caché.