'volatile' und Cache

Gast #2220346
Lesenswert?

Wenn eine Variable mit 'volatile' attributiert ist, dann ist der 
Compiler ja verpflichtet, die Variable bei jedem Zugriff explizit 
einlesen bzw. zurückschreiben zu lassen.

Ein paar Aspekte sind mir aber nicht klar:
- Bei Prozessoren mit Cache: Darf die Variable im Cache benutzt werden, 
oder muss der Compiler explizit ein Laden aus dem Hauptspeicher 
verlangen?
- Muss der Compiler einen Lesezugriff auch dann ausführen lassen, wenn 
er ihn bei der Optimierung als sinnlos erachtet? (Z.B., weil die 
Variable nur gelesen wird, aber nichts weiter geschieht.)
Gast #2220356
Lesenswert?

zu 1)
Die Variable muss sich im Arbeitsspeicher befinden und wird nicht 
gecachet.
Stell dir ein memory-mapped system vor, in dem deine volatile variable 
auf ein hardware peripheral register zeigt.

zu 2)
Der Compiler optimiert die nicht weg, wg siehe Bsp. von 1)
#2220361
Lesenswert?

2ter Gast schrieb:

> Die Variable muss sich im Arbeitsspeicher befinden und wird nicht
> gecachet.

Falsch. Was C und volatile angeht. Ein C Compiler interessiert sich kein 
bischen dafür, was cachable ist und was nicht. Auch nicht mit volatile.

> Stell dir ein memory-mapped system vor, in dem deine volatile variable
> auf ein hardware peripheral register zeigt.

Andere Baustelle. I/O-Register und Dual-Port Memory vom Caching 
auszunehmen ist nicht Sache des Compilers, sondern von Hardware oder 
MMU-Konfiguration.
Gast #2220377
Lesenswert?

A. K. schrieb:
> Falsch. Was C und volatile angeht. Ein C Compiler interessiert sich kein
> bischen dafür, was cachable ist und was nicht. Auch nicht mit volatile.

Das habe ich vermutet. Der Compiler "sieht" den Cache gar nicht, sondern 
muss sich darauf verlassen, dass der Prozessor für Kohärenz sorgt 
zwischen allem, was er cacht und der tatsächlichen Aussenwelt.
Gast #2220387
Lesenswert?

A. K. schrieb:
> I/O-Register und Dual-Port Memory vom Caching
> auszunehmen ist nicht Sache des Compilers, sondern der Hardware oder der
> MMU.

Woher kennt dein Compiler den Aufbau deines uC-System? Stichwort FPGA 
und Soft-Core!

A. K. schrieb:
> Falsch. Was C und volatile angeht.

Wo landet denn eine Deklaration?
1
volatile char a;
dein Compiler wird die Variable im Hauptspeicher anlegen; es sei du 
generierst ein Ptr und setzt selbst die Adresse.
#2220395
Lesenswert?

2ter Gast schrieb:

> Woher kennt dein Compiler den Aufbau deines uC-System?

Überhaupt nicht. Der Linker weiss dank Adressraumbeschreibung ein 
bischen mehr, aber das ist hier nicht relevant.

> dein Compiler wird die Variable im Hauptspeicher anlegen

Richtig. Und das ist auch völlig korrekt. Was C angeht. Ob das dem 
entspricht was du dir dabei gedacht hast ist nicht sein Problem.

Wenn das eine Speicherstelle ist, die als memory mapped i/o dient, dann 
ist es nicht Sache des Compilers, dafür zu sorgen, dass die Variable 
(bzw. dieser Speicherbereich) nicht gecached wird.

Wenn du erreichen willst, dass die Variable in einem nicht gecachten 
Bereich liegt, dann musst du den Compiler über nicht standardisierte 
Verfahren wie die GCC attributes davon überzeugen.
#2220396
Lesenswert?

2ter Gast schrieb:

> 1) mit volatile

Das hat dann aber nichts mit dem C Standard zu tun, sondern ist eine 
Spezialität dieser einen Plattform und dessen Entwicklungssystems.

Du kannst das auf jedem beliebigen C Compiler für PCs ausprobieren. Du 
wirst im erzeugten Code keinerlei Adressraumspezifika für die Variable 
oder gar explizite Cache-Control-Befehle finden.
Persönliche Seite #2220411
Lesenswert?

A. K. schrieb:

>> - Muss der Compiler einen Lesezugriff auch dann ausführen lassen, wenn
>> er ihn bei der Optimierung als sinnlos erachtet? (Z.B., weil die
>> Variable nur gelesen wird, aber nichts weiter geschieht.)
>
> Ja. Bei
>   volatile char a;
>   a;
> muss ein Lesezugriff erfolgen.

Jein. Bei GCC ist das der Fall: Implementation defined, C90 6.5.3, C99 
6.7.3

http://gcc.gnu.org/onlinedocs/gcc/Qualifiers-implementation.html#Qualifiers-implementation

Was den Cache angeht, gibt's in GCC Builtins 
wie __builtin___clear_cache. Die Implementierung dürfte allerdings stark 
architekturabhängig sein :-)

http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins

Ansonsten behilft man sich mit zur Verfügung gestellten Instrinsics oder 
Inline Assembler, wobei man da schon aufpassen muss, daß einem der 
Scheduler nicht dazwischen funkt.
Gast #2220439
Lesenswert?

Ich hab mal einen ARM-Prozessor programmiert, da war einfach alles 
doppelt in den Adressraum gemappt. Eins der Adressbits oberhalb des 
regulären Adressraums war dann für den Cache zuständig. Hat man über 
einen Zeiger zugegriffen, wo das gesetzt war, war der Zugriff ohne 
Cache, sonst mit.
Interessanter wird die Cache-Frage bei Multicore-Systemen, wenn man 
Daten zwischen Task austauschen will, die auf unterschiedlichen Kernen 
laufen, die jeweils ihre eigenen (ggf mehrstufigen) Caches haben. Aber 
dafür gibt's dann memory barriers.
#2220451
Lesenswert?

Rolf Magnus schrieb:

> Ich hab mal einen ARM-Prozessor programmiert, da war einfach alles
> doppelt in den Adressraum gemappt.

STR9: das RAM dreifach, die I/O doppelt. Dabei hat der noch nicht einmal 
einen Cache, nur ein bischen optionale Pufferung im Systembusinterface 
(1x gepuffert, 1x ungepuffert) und einen separaten schnellen RAM-Bus am 
Core.

> Aber dafür gibt's dann memory barriers.

Aber auch da ist es Sache des Programmierers, sie zu nutzen, nicht des 
Compilers.
Gast #2220471
Lesenswert?

Genau, es geht hier um ein Multicore-System. Schaut ganz danach aus, als 
hättet ihr Recht: Austausch zwischen 2 Prozessoren ist sehr schnell, so 
lange der ganze Datensatz im Cache Platz hat. Danach wird er langsamer. 
Der Compiler umgeht den Cache also nicht.

Kann er ja eigentlich auch gar nicht, denn dann müsste der C-Standard ja 
voraussetzen, dass es einen Cache-Umgehungsmechanismus gibt. Sowas wäre 
völlig sinnfrei, denn der Cache ist ja per Definition ein völlig 
transparenter Zwischenspeicher.
#2220478
Lesenswert?

Wobei solche Spielchen mit der Performance auch deutlich vom verwendeten 
Prozessor abhängen können. Das Verhalten und die Art des Datenaustauschs 
gemeinsamer Daten variiert abhängig von Verbindungstopologie und Art der 
Methode zur Gewährleistung von Konsistenz. Auch x86 können recht 
verschieden reagieren.

Wenn es um Performance geht, dann kann an dieser Stelle auch explizites 
Prefetching nützlich werden.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren