Questo è per ARM.
GCC fornisce __builtin___clear_cache
che fa dovrebbe eseguire la chiamata di sistema cacheflush
. Tuttavia potrebbe avere i suoi avvertimenti.
La cosa importante qui è che Linux fornisce una chiamata di sistema (specifica per ARM) per svuotare le cache. Puoi controllare Android/Bionic flushcache per sapere come utilizzare questa chiamata di sistema. Tuttavia non sono sicuro di che tipo di garanzie dia Linux quando lo chiami o come viene implementato attraverso i suoi meccanismi interni.
Questo post sul blog Cache e codice automodificante può essere di ulteriore aiuto.
Controlla questa pagina per l'elenco dei metodi di svuotamento disponibili nel kernel Linux:https://www.kernel.org/doc/Documentation/cachetlb.txt
Svuotamento cache e TLB sotto Linux. David S. Miller
Ci sono serie di funzioni di flushing dell'intervallo
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,unsigned long start, unsigned long end)
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'.
Puoi anche controllare l'implementazione della funzione - http://lxr.free-electrons.com/ident?a=sh;i=flush_cache_range
Ad esempio, in arm - 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 }
Nella versione x86 di Linux puoi anche trovare una funzione void clflush_cache_range(void *vaddr, unsigned int size)
che viene utilizzato allo scopo di svuotare un intervallo di cache. Questa funzione si basa sul CLFLUSH
o CLFLUSHOPT
Istruzioni. Consiglierei di verificare che il tuo processore li supporti effettivamente, perché in teoria sono opzionali.
CLFLUSHOPT
è debolmente ordinato. CLFLUSH
è stato originariamente specificato come ordinato solo da MFENCE
, ma tutte le CPU che lo implementano lo fanno con un ordinamento forte rispetto a. scrive e altri CLFLUSH
Istruzioni. Intel ha deciso di aggiungere una nuova istruzione (CLFLUSHOPT
) invece di modificare il comportamento di CLFLUSH
e per aggiornare il manuale per garantire che le future CPU implementeranno CLFLUSH
come fortemente ordinato. Per questo utilizzo, dovresti MFENCE
dopo aver utilizzato uno dei due, per assicurarti che lo svuotamento venga eseguito prima di qualsiasi caricamento dal tuo benchmark (non solo dai negozi).
In realtà x86 fornisce un'altra istruzione che potrebbe essere utile:CLWB
. CLWB
scarica i dati dalla cache alla memoria senza (necessariamente) rimuoverli, lasciandoli puliti ma ancora memorizzati nella cache. clwb
su SKX espelle come clflushopt
, però
Si noti inoltre che queste istruzioni sono coerenti con la cache. La loro esecuzione influenzerà tutte le cache di tutti i processori (processor core) nel sistema.
Tutte e tre queste istruzioni sono disponibili in modalità utente. Pertanto, puoi utilizzare assembler (o intrinseche come _mm_clflushopt
) e crea il tuo void clflush_cache_range(void *vaddr, unsigned int size)
nella tua applicazione in spazio utente (ma non dimenticare di verificarne la disponibilità, prima dell'effettivo utilizzo).
Se ho capito bene, è molto più difficile ragionare su ARM a questo proposito. La famiglia di processori ARM è molto meno coerente della famiglia di processori IA-32. Puoi avere un ARM con cache complete e un altro completamente senza cache. Inoltre, molti produttori possono utilizzare MMU e MPU personalizzate. Quindi è meglio ragionare su qualche particolare modello di processore ARM.
Sfortunatamente, sembra che sarà quasi impossibile eseguire una stima ragionevole del tempo necessario per scaricare alcuni dati. Questo tempo è influenzato da troppi fattori tra cui il numero di righe della cache scaricate, l'esecuzione non ordinata delle istruzioni, lo stato del TLB (poiché l'istruzione accetta un indirizzo virtuale come argomento, ma le cache utilizzano indirizzi fisici), il numero di CPU nel sistema, carico effettivo in termini di operazioni di memoria sugli altri processori nel sistema e quante righe dell'intervallo sono effettivamente memorizzate nella cache dai processori e infine dalle prestazioni di CPU, memoria, controller di memoria e bus di memoria. Di conseguenza, penso che il tempo di esecuzione varierà in modo significativo in ambienti diversi e con carichi diversi. L'unico modo ragionevole è misurare il tempo di scaricamento sul sistema e con un carico simile al sistema di destinazione.
E nota finale, non confondere cache di memoria e TLB. Sono entrambe cache, ma organizzate in modi diversi e con scopi diversi. TLB memorizza nella cache solo le traduzioni utilizzate più di recente tra indirizzi virtuali e fisici, ma non i dati puntati da tali indirizzi.
E TLB non è coerente, a differenza delle cache di memoria. Fai attenzione, perché lo svuotamento delle voci TLB non porta allo svuotamento dei dati appropriati dalla cache di memoria.