Performance frage static /dynamic memory!?
-
Hallo Leute ich habe folgendes ausprobiert:
const int SIZE = 1000000; typedef struct { int a; double b; } xx; static void BM_staticMemorySet(benchmark::State& state) { static xx arr[SIZE]; for (auto _ : state) { for (int i = 0; i < SIZE; ++i) { arr[i]= { i,(double)i * 2 }; } benchmark::DoNotOptimize(arr); } } BENCHMARK(BM_staticMemorySet); static void BM_dynamicMemorySet(benchmark::State& state) { xx* arr = new xx[SIZE]; for (auto _ : state) { for (int i = 0; i < SIZE; ++i) { arr[i] = { i,(double)i * 2 }; } benchmark::DoNotOptimize(arr); } delete[] arr; } BENCHMARK(BM_dynamicMemorySet);
Ich hätte jetzt gedacht, dass static memory access "vieel" schnell ist, aber ich bekomm diese ergebnisse:
BM_staticMemorySet 5306343 ns 5312500 ns 100 BM_dynamicMemorySet 5276769 ns 5312500 ns 100
versteh ich jetzt nich? hab ich nen denkfehler?;)
-
Du forderst ja nur einmalig Speicher an und der Großteil der Performance geht bei der Array-Initialisierung drauf.
Du müßtest auch das Allozieren und Löschen des Arrays in
BM_dynamicMemorySet
innerhalb derstate
-Schleife setzen, um einen Unterschied zu sehen (ich gehe davon aus, daß100
die Anzahl der Schleifendurchgänge hier ist, oder?).
-
Dieser Beitrag wurde gelöscht!
-
@Th69 servus ja da hast du recht, aber das habe ich bewußt rausgenommen, weil es mir nur um lesen und schreiben geht.. ohne allocation at runime...
dachte dass der zugriff schon einen enormen unterschied macht.
interessanteweiße ist das ganze auch faktor 10 schneller wenn jeden member der struktur einzelen geschrieben wird
for (int i = 0; i < SIZE; ++i) { ((arr + i)->a) = i; ((arr + i)->b) = i*2; }
habe gedacht, dass bei statischen speicher schon bei kompiletime die speicher stelle offsets gesetzt werrden , und bei dynamische zur laufzeut das erstgemacht wird..deswegn es einiges langsamer sein müsste...
-
@Th69 sagte in Performance frage static /dynamic memory!?:
Du müßtest auch das Allozieren und Löschen des Arrays in BM_dynamicMemorySet innerhalb der state-Schleife setzen, um einen Unterschied zu sehen (ich gehe davon aus, daß 100 die Anzahl der Schleifendurchgänge hier ist, oder?).
korrekt 100 tryes dann querschnitt (google benchmark)
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
habe gedacht, dass bei statischen speicher schon bei kompiletime die speicher stelle offsets gesetzt werrden , und bei dynamische zur laufzeut das erstgemacht wird..deswegn es einiges langsamer sein müsste...
Du scheinst die falsche Vorstellung zu haben, dass
static
irgendwie vorteilhaft wäre. Dabei ist das Gegenteil der Fall,static
ist der Tod aller Optimierungen. Beispielsweise darf hier der Compiler ja auf gar keinen Fall den Speicher vorab initialisieren, weil er sonst die Regeln für static-Variablen verletzen würde. Und auch sonst darf er absolut nix wegoptimieren, was irgendwie nach außen sichtbar wäre, was halt alles ist, was static ist. Bei rein internen Variablen könnte der Compiler pfuschen wie er will und sogar alles im Voraus berechnen. Daherstatic
nie zur Optimierung, sondern nur wenn technisch absolut notwendig (Also eigentlich nie).
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
u scheinst die falsche Vorstellung zu haben, dass static irgendwie vorteilhaft wäre. Dabei ist das Gegenteil der Fall, static ist der Tod aller Optimierungen. Beispielsweise darf hier der Compiler ja auf gar keinen Fall den Speicher vorab initialisieren, weil er sonst die Regeln für static-Variablen verletzen würde. Und auch sonst darf er absolut nix wegoptimieren, was irgendwie nach außen sichtbar wäre, was halt alles ist, was static ist. Bei rein internen Variablen könnte der Compiler pfuschen wie er will und sogar alles im Voraus berechnen. Daher static nie zur Optimierung, sondern nur wenn technisch absolut notwendig (Also eigentlich nie).
ja das "static" keyword hatte ich jetzt hier nicht im blick, es ging mir um die primär darum dass ich dachte, dass vorab definierte speicherblöcke und nicht zur laufzeut erzeugte speicherblöcke in einen anderen speicher segement gelegt werden, deren zugriff viel effinzienter sein soll!?
hab mal das "static" entfertn, und den speicher block global angelegt, leider sehe ich da auch keine verbesserung!
const int SIZE = 1000000; typedef struct { int a; double b; } xx; xx arr[SIZE]; static void BM_staticMemorySet(benchmark::State& state) { for (auto _ : state) { for (int i = 0; i < SIZE; ++i) { arr[i]= { i,(double)i * 2 }; } benchmark::DoNotOptimize(arr); } } BENCHMARK(BM_staticMemorySet); static void BM_dynamicMemorySet(benchmark::State& state) { xx* arr = new xx[SIZE]; for (auto _ : state) { for (int i = 0; i < SIZE; ++i) { arr[i] = { i,(double)i * 2 }; } benchmark::DoNotOptimize(arr); } delete[] arr; } BENCHMARK(BM_dynamicMemorySet);
-
Wie kommst du darauf, daß der Speicherzugriff effizienter sein soll? Beides sind Speicherblöcke im Hauptspeicher (RAM).
Nur das Verwenden von lokalen Variablen (bei höchstens der max. Registerbreite) kann der Compiler so optimieren, daß nur interne CPU-Register benutzt werden, und damit schneller als ein Speicherzugriff ist.Außerdem könntest du ja einfach den Schleifen-Code in eine eigene Funktion auslagern:
void InitArray(xx *arr) { for (auto _ : state) { for (int i = 0; i < SIZE; ++i) { arr[i] = { i,(double)i * 2 }; } benchmark::DoNotOptimize(arr); } }
Und jeweils mit
InitArray(xx)
aufrufen.
Da gibt es (auch) keinen Unterschied im Laufzeitverhalten.
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
ja das "static" keyword hatte ich jetzt hier nicht im blick, es ging mir um die primär darum dass ich dachte, dass vorab definierte speicherblöcke und nicht zur laufzeut erzeugte speicherblöcke in einen anderen speicher segement gelegt werden, deren zugriff viel effinzienter sein soll!?
Ich erkläre dir, warum
static
böse für Optimierungen ist, weil es global sichtbar ist, und du probierst als nächstes echten globalen Speicher aus und wunderst dich über mangelnde Optimierung
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
hab mal das "static" entfertn, und den speicher block global angelegt, leider sehe ich da auch keine verbesserung!
Woher sollte auch eine Verbesserung kommen?
Anders sieht die Sache zwischen
std::list
vsstd::array
aus.
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
@SoIntMan sagte in Performance frage static /dynamic memory!?:
ja das "static" keyword hatte ich jetzt hier nicht im blick, es ging mir um die primär darum dass ich dachte, dass vorab definierte speicherblöcke und nicht zur laufzeut erzeugte speicherblöcke in einen anderen speicher segement gelegt werden, deren zugriff viel effinzienter sein soll!?
Ich erkläre dir, warum
static
böse für Optimierungen ist, weil es global sichtbar ist, und du probierst als nächstes echten globalen Speicher aus und wunderst dich über mangelnde Optimierungok. gut dann habe ich wohl gar nichts verstanden. Aber wie müssten den die implementierung aussehen damit ich Signifikate unterschied sehe?
@Quiche-Lorraine sagte in Performance frage static /dynamic memory!?:
Woher sollte auch eine Verbesserung kommen?
Anders sieht die Sache zwischen std::list vs std::array aus.is das nicht das gleich wie arr[size] and arr = new (size)
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
ok. gut dann habe ich wohl gar nichts verstanden. Aber wie müssten den die implementierung aussehen damit ich Signifikate unterschied sehe?
Hier eigentlich gar nix, denn das was passiert ist nicht spannend genug, um Optimierungspotential zu haben.
Meine Bemerkung war eher allgemein, nicht auf diesen speziellen Fall. Du scheinst irgendetwas über static, new & Co. aufgeschnappt zu haben, das nicht stimmt. Das wollte ich korrigieren.
is das nicht das gleich wie arr[size] and arr = new (size)
Du verwechselt list mit vector.
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
Meine Bemerkung war eher allgemein, nicht auf diesen speziellen Fall. Du scheinst irgendetwas über static, new & Co. aufgeschnappt zu haben
Ja das genau habe ausgeschnappt (CoPilot) hier ein abschnitt:
Access Speed:
Static Memory: Generally faster due to fixed addresses and better cache utilization. The access patterns are predictable, which helps in optimizing cache usage.
Dynamic Memory: Slower due to potential cache misses and the overhead of pointer dereferencing. The access patterns can be less predictable, leading to more cache misses.
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
CoPilot
Kein Kommentar...
Das "static" da hat nix mit
static
zu tun.Wildes Herumspringen im Speicher ist es, was Cachemisses erzeugt. Das ist aber keine Eigenschaft von statischem oder dynamischem Speicher, sondern von dem, was man damit macht. Mit dynamischen Speicher ist es halt einfacher, komplexe Datenstrukturen aufzubauen. Die können dann langsamer sein bei schödem iterativen Zugriff, aber das ist nix negatives, denn man hat die Struktur ja gebaut, damit sie spezielle andere Eigenschaften hat, die man braucht. Siehe
list
,vector
,array
. List ist dynamisch und kann viel mehr als die beiden anderen ist aber viel langsamer bei iterativem Zugriff, weil man dann wild im Speicher herumspringt. vector ist dynamisch, kann aber auch nicht wirklich mehr als array (außer dynamisch zu sein) und ist entsprechend bei iterativem Zugriff genauso schnell. Array ist statisch, aber wenn du dumm drin herumspringst, statt von vorne nach hinten durchuzugehen, wäre es genau so langsam wie eine Liste.
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
Das "static" da hat nix mit static zu tun.
Wildes Herumspringen im Speicher ist es, was Cachemisses erzeugt. Das ist aber keine Eigenschaft von statischem oder dynamischem Speicher, sondern von dem, was man damit macht. Mit dynamischen Speicher ist es halt einfacher, komplexe Datenstrukturen aufzubauen. Die können dann langsamer sein bei schödem iterativen Zugriff, aber das ist nix negatives, denn man hat die Struktur ja gebaut, damit sie spezielle andere Eigenschaften hat, die man braucht. Siehe list, vector, array. List ist dynamisch und kann viel mehr als die beiden anderen ist aber viel langsamer bei iterativem Zugriff, weil man dann wild im Speicher herumspringt. vector ist dynamisch, kann aber auch nicht wirklich mehr als array (außer dynamisch zu sein) und ist entsprechend bei iterativem Zugriff genauso schnell. Array ist statisch, aber wenn du dumm drin herumspringst, statt von vorne nach hinten durchuzugehen, wäre es genau so langsam wie eine Liste.ok wenn kurz, solange ich den Speicher lineare durchiteriere (loop) den ich "dynamisch" allokiert habe macht es kein unterschied zu statischem Speicher? (allokiert mallock immer einen "ganzen" block). Wenn ich aber sporadisch hin und her springe bin ich bei statische schneller...?
std::list ist ja als linked list implementiert oder? da kann ja jedes element ganz woanders liegen?
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
ok wenn kurz, solange ich den Speicher lineare durchiteriere (loop) den ich "dynamisch" allokiert habe macht es kein unterschied zu statischem Speicher?
Ja.
(allokiert mallock immer einen "ganzen" block).
Ja.
Wenn ich aber sporadisch hin und her springe bin ich bei statische schneller...?
Nein. Außer eventuell doch ja, aber dann durch so komische Effekte, wie dass du bei statischer Allokation größenmäßig sehr beschränkt bist, so dass sowieso alles im Cache liegt. Aber das ist weiterhin keine Eigenschaft des statischen Speichers an sich, sondern davon, dass man damit weniger machen kann, was langsam sein könnte. Würdest du in einem kleinen Block dynamischen Speichers gelegentlich hin und her springen, wäre das genauso schnell wie in einem kleinen Block statischen Speicher gelegentlich hin und her zu springen. Wenn du die Größenlimits deines statischen Speichers ausschaltest und in einem riesigen Block gelegentlich hin und her springen, wäre es genauso langsam wie in einem riesigen Block dynamischen Speichers hin und her zu springen. Wie jetzt schon oft gesagt, gibt es keinen prinzipiellen technischen Unterschied zwischen statischen und dynamischen Speicher, sondern alle Unterschiede kommen daher, was man damit macht (Es gibt noch einen Unterschied darin, wie aufwändig die Anforderung eines neuen Blocks ist, aber das lassen wir mal außen vor, weil es hier um Unterschiede bei der Nutzung geht).
std::list ist ja als linked list implementiert oder?
Ja.
da kann ja jedes element ganz woanders liegen?
Ja.
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
Wie jetzt schon oft gesagt, gibt es keinen prinzipiellen technischen Unterschied zwischen statischen und dynamischen Speicher, sondern alle Unterschiede kommen daher, was man damit macht (Es gibt noch einen Unterschied darin, wie aufwändig die Anforderung eines neuen Blocks ist, aber das lassen wir mal außen vor, weil es hier um Unterschiede bei der Nutzung geht).
Super Danke für deine Ausführungen, hat mir geholfen es zu verstehen. In meinen Fall ist das dann super.. da ich meinen speicher nur "einmal" bei initalisieren dynamisch allokcieren und nur noch verwende. Hätte eben gedacht wenn ich der speicher statisch ist, dass ich performance vorteile habe. Und vom caching her,passt es auch, weil ich auch keine wilden array sprünge mache:)
-
Ich hoffe doch, dass das kein reales Beispiel war? Benutz in echtem Code bloß kein new/delete (außer du baust eigene Allokatoren o.Ä.)! Rule of 0!
-
@SeppJ sagte in Performance frage static /dynamic memory!?:
Ich hoffe doch, dass das kein reales Beispiel war? Benutz in echtem Code bloß kein new/delete (außer du baust eigene Allokatoren o.Ä.)! Rule of 0!
Nein war nur dummy code... aber sorry das verstehe ich jetzt nicht in c++ new/delete c malloc/free? oder wie meinst du das?
im produktiv code c muss ich malloc/Free nehmen und .. in C++ smart ptr etc. also nicht nativ new/Delete;)
-
@SoIntMan sagte in Performance frage static /dynamic memory!?:
@SeppJ sagte in Performance frage static /dynamic memory!?:
Ich hoffe doch, dass das kein reales Beispiel war? Benutz in echtem Code bloß kein new/delete (außer du baust eigene Allokatoren o.Ä.)! Rule of 0!
Nein war nur dummy code... aber sorry das verstehe ich jetzt nicht in c++ new/delete c malloc/free? oder wie meinst du das?
Mit C++11 wurden smart pointer eingeführt, sodass man eigentlich kein
new
unddelete
mehr braucht.