Dies ist für ARM.
GCC stellt __builtin___clear_cache
bereit was tut sollte Syscall cacheflush
ausführen . Es kann jedoch seine Vorbehalte haben.
Wichtig ist hier, dass Linux einen Systemaufruf (ARM-spezifisch) zum Leeren von Caches bereitstellt. Sie können Android/Bionic Flushcache überprüfen, um zu erfahren, wie Sie diesen Systemaufruf verwenden. Ich bin mir jedoch nicht sicher, welche Art von Garantien Linux gibt, wenn Sie es aufrufen, oder wie es durch sein Innenleben implementiert wird.
Dieser Blog-Beitrag Caches und selbstmodifizierender Code kann weiterhelfen.
Auf dieser Seite finden Sie eine Liste der verfügbaren Flush-Methoden im Linux-Kernel:https://www.kernel.org/doc/Documentation/cachetlb.txt
Cache- und TLB-Flushing unter Linux. David S. Miller
Es gibt eine Reihe von Bereichsspülfunktionen
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'.
Sie können auch die Implementierung der Funktion überprüfen - http://lxr.free-electrons.com/ident?a=sh;i=flush_cache_range
Zum Beispiel 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 }
In der x86-Version von Linux finden Sie auch eine Funktion void clflush_cache_range(void *vaddr, unsigned int size)
die zum Leeren eines Cache-Bereichs verwendet wird. Diese Funktion stützt sich auf den CLFLUSH
oder CLFLUSHOPT
Anweisungen. Ich würde empfehlen zu überprüfen, ob Ihr Prozessor sie tatsächlich unterstützt, da sie theoretisch optional sind.
CLFLUSHOPT
ist schwach geordnet. CLFLUSH
wurde ursprünglich als nur von MFENCE
bestellt angegeben , aber alle CPUs, die es implementieren, tun dies mit starker Ordnung bzgl. schreibt und andere CLFLUSH
Anweisungen. Intel hat beschlossen, eine neue Anweisung hinzuzufügen (CLFLUSHOPT
), anstatt das Verhalten von CLFLUSH
zu ändern , und das Handbuch zu aktualisieren, um zu garantieren, dass zukünftige CPUs CLFLUSH
implementieren werden als stark bestellt. Für diese Verwendung sollten Sie MFENCE
verwenden nachdem Sie beides verwendet haben, stellen Sie sicher, dass das Spülen vor dem Laden von Ihrem Benchmark (nicht nur dem Laden) durchgeführt wird.
Tatsächlich bietet x86 eine weitere Anweisung, die nützlich sein könnte:CLWB
. CLWB
löscht Daten aus dem Cache in den Speicher, ohne sie (notwendigerweise) zu entfernen, und hinterlässt sie sauber, aber immer noch im Cache. clwb
auf SKX wird wie clflushopt
entfernt , obwohl
Beachten Sie auch, dass diese Befehle Cache-kohärent sind. Ihre Ausführung wirkt sich auf alle Caches aller Prozessoren (Prozessorkerne) im System aus.
Alle diese drei Anweisungen sind im Benutzermodus verfügbar. Daher können Sie Assembler (oder systeminterne Elemente wie _mm_clflushopt
) verwenden ) und erstellen Sie Ihren eigenen void clflush_cache_range(void *vaddr, unsigned int size)
in Ihrer Userspace-Anwendung (aber vergessen Sie nicht, ihre Verfügbarkeit vor der tatsächlichen Verwendung zu überprüfen).
Wenn ich das richtig verstehe, ist es in dieser Hinsicht viel schwieriger, über ARM nachzudenken. Die Familie der ARM-Prozessoren ist viel weniger konsistent als die Familie der IA-32-Prozessoren. Sie können einen ARM mit voll funktionsfähigen Caches haben und einen anderen ganz ohne Caches. Darüber hinaus können viele Hersteller kundenspezifische MMUs und MPUs verwenden. Daher ist es besser, über ein bestimmtes ARM-Prozessormodell nachzudenken.
Leider sieht es so aus, als wäre es fast unmöglich, eine vernünftige Schätzung der Zeit vorzunehmen, die zum Löschen einiger Daten erforderlich ist. Diese Zeit wird von zu vielen Faktoren beeinflusst, darunter die Anzahl der geleerten Cache-Zeilen, die ungeordnete Ausführung von Anweisungen, der Status von TLB (weil die Anweisung eine virtuelle Adresse als Argument akzeptiert, Caches jedoch physische Adressen verwenden), die Anzahl der CPUs im System, tatsächliche Last in Bezug auf Speicheroperationen auf den anderen Prozessoren im System und wie viele Zeilen aus dem Bereich tatsächlich von Prozessoren zwischengespeichert werden, und schließlich von der Leistung von CPU, Speicher, Speichercontroller und Speicherbus. Infolgedessen denke ich, dass die Ausführungszeit in verschiedenen Umgebungen und mit unterschiedlichen Lasten erheblich variieren wird. Der einzig vernünftige Weg ist, die Spülzeit auf dem System und mit einer ähnlichen Last wie das Zielsystem zu messen.
Und abschließend:Verwechseln Sie Speicher-Caches nicht mit TLB. Sie sind beide Caches, aber auf unterschiedliche Weise organisiert und dienen unterschiedlichen Zwecken. TLB speichert nur die zuletzt verwendeten Übersetzungen zwischen virtuellen und physischen Adressen, aber keine Daten, auf die diese Adressen verweisen.
Und TLB ist im Gegensatz zu Speichercaches nicht kohärent. Seien Sie vorsichtig, da das Leeren von TLB-Einträgen nicht dazu führt, dass die entsprechenden Daten aus dem Speichercache gelöscht werden.