 |
JLI Spieleprogrammierung
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Mat Senior JLI'ler

Alter: 36 Anmeldedatum: 17.09.2005 Beiträge: 205 Wohnort: Koblenz Medaillen: Keine
|
Verfasst am: 31.08.2006, 17:00 Titel: Geschwindigkeit Speicherzuweisung |
|
|
Hey,
glitze kleine Frage eigendlich:
Weiß einer von euch ob die Zeit relevant ist, die der Computer benötigt um Speicher einer Varable zuzuweisen ?
Klingt ja eigendlich nicht so, aber wenn dies durchgehend in einer Schleife (z.B. Spielschleife) geschieht, könnte das ja durchaus zu begutachten sein.
Ich denke jetzt daran ob es sich lohnt, einen namespace für Globale Variablen zu erstellen, in dem sich Buffer-Variablen befinden. z.B:
int i
std::string StringBuffer
Also Buffervariablen die immerwieder benötigt werden einmal anzulegen, und nicht hundert mal während das Programm läuft.
 _________________ - - - - - - - - - - - - - - - - - - - -
-> http://www.sea-productions.de
-> http://www.krawall.de
- - - - - - - - - - - - - - - - - - - - |
|
Nach oben |
|
 |
PeaceKiller JLI Master

Alter: 36 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
Verfasst am: 31.08.2006, 17:16 Titel: |
|
|
Buffer static zu machen, kann einiges an Performance bringen. Ich hatte mal bei einem Filehasher einen Geschwindigkeitszuwachs Faktor 20, wegen eines einzigen static!
Allerdings langt es die Variablen als static zu deklarieren, es gibt keinen Grund sie deswegen global zu machen. Oder wenn du den Buffer in verschiedenen Klassen brauchst, kannst du dir auch eine Verwaltungsklasse schreiben. _________________ »If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.«
– Robert X. Cringely, InfoWorld magazine |
|
Nach oben |
|
 |
Mat Senior JLI'ler

Alter: 36 Anmeldedatum: 17.09.2005 Beiträge: 205 Wohnort: Koblenz Medaillen: Keine
|
Verfasst am: 31.08.2006, 17:25 Titel: |
|
|
Also lohnt es sich das ist schonmal super - mal sehen, wie ich das dann verwalten werde
-> Danke _________________ - - - - - - - - - - - - - - - - - - - -
-> http://www.sea-productions.de
-> http://www.krawall.de
- - - - - - - - - - - - - - - - - - - - |
|
Nach oben |
|
 |
Chriss Senior JLI'ler
Anmeldedatum: 18.08.2004 Beiträge: 267
Medaillen: Keine
|
Verfasst am: 31.08.2006, 17:36 Titel: |
|
|
Was hat das bitte bei den Tutorials verloren? |
|
Nach oben |
|
 |
GreveN JLI Master

Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 31.08.2006, 17:39 Titel: |
|
|
'static' bedeutet einfach, dass das Objekt nicht jedesmal neu erzeugt wird, sondern auch nach dem Verlassen des Scopes bestehen bleibt, deshalb kann es einen Geschwindigkeitsbonus bringen, temporäre, nicht triviale Objekte (also keine floats, ints etc.) statisch zumachen. Jedoch wäre ich vorsichtig, was static angeht und würde schauen, ob sich das Erstellen zusätlicher temporärer Objekte nicht irgendwie anders vermeiden lässt. Die Geschwindigkeit der Zuweisung hängt logischerweise von der jeweiligen Implementation des verwendeten Zuweisungsoperator ab. |
|
Nach oben |
|
 |
Jonathan_Klein Living Legend

Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 31.08.2006, 20:24 Titel: |
|
|
ja, also kommt darauf an. Wenn man ein i hat in einer for-Schleife, die jedesmal aufgerufen wird, muss vielleicht immer ein i erstellt werdne, läuft die Schleife aber 500 mal durch wird das denke ich mal nicht so den riesen Unterschied machen, obs nun static ist oder nicht.
Da ist es wohl wichitger das die Algorythmen effizient sind. Global machen kann sehr gefährlich sein, ich hatte mal einen Iterator als Klassenmember, dumemrweise hab ich den in 2 Schleifen gleichzeitig gebraucht, was ich algne nciht bemerkt hab, weil die net verschachtelt waren.
Dann doch sowas lieber lokal und static machen. _________________ https://jonathank.de/games/ |
|
Nach oben |
|
 |
PeaceKiller JLI Master

Alter: 36 Anmeldedatum: 28.11.2002 Beiträge: 970
Medaillen: Keine
|
Verfasst am: 31.08.2006, 22:42 Titel: |
|
|
GreveN hat Folgendes geschrieben: | 'static' bedeutet einfach, dass das Objekt nicht jedesmal neu erzeugt wird, sondern auch nach dem Verlassen des Scopes bestehen bleibt
[snip] |
Mmmh ... wenn ich mir das so Recht überlege, ist das auch nicht das gelbe vom Ei, 8mb Speicher einfach so brachliegen zu lassen ist auch nicht so schön. _________________ »If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.«
– Robert X. Cringely, InfoWorld magazine |
|
Nach oben |
|
 |
AFE-GmdG JLI MVP


Alter: 45 Anmeldedatum: 19.07.2002 Beiträge: 1374 Wohnort: Irgendwo im Universum... Medaillen: Keine
|
Verfasst am: 01.09.2006, 08:51 Titel: |
|
|
Ich glaube ja überhaupt nicht, dass die einfache Zuweisung einer Variable weniger Zeit kostet, nur weil sie static ist - schliesslich ist der Ram überall gleich schnell. Das Zuweisen von einfachen Integer oder Float-Variablen ist zudem eine Atomare Operation welche man schlecht "optimieren" kann.
Anders sieht es mit Klassen aus, die einen Konstruktor haben. Am Konstruktor kann man dann sicherlich auch optimieren.
PS.: Singletons sind ja auch nur Klassen, welche (ihre einzige) Instanz im statischen Speicher haben - je nachdem, was alles in der Klasse gespeichert wird, sind das auch mal schnell 8 MB. Wobei es Egal ist, ob das nun Statischer oder Dynamischer Speicher ist... _________________
CPP: | float o=0.075,h=1.5,T,r,O,l,I;int _,L=80,s=3200;main(){for(;s%L||
(h-=o,T= -2),s;4 -(r=O*O)<(l=I*I)|++ _==L&&write(1,(--s%L?_<(L)?--_
%6:6:7)+\"World! \\n\",1)&&(O=I=l=_=r=0,T+=o /2))O=I*2*O+h,I=l+T-r;} |
|
|
Nach oben |
|
 |
KI JLI Master

Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 01.09.2006, 10:16 Titel: |
|
|
Soweit ich weiß wird beim 'Betreten' einer Funktion für alle Variablen auf dem Stack schonmal Speicher reserviert. Es ist also egal, ob du die Varaible am Anfang der Funktion deklarierst oder in der Mitte oder am Ende.
Auch für Variablendeklarationenen innerhalb einer Schleife gilt das.
Wenn die Schleife z.B. das zweite mal aufgerufen wird, wird einfach der Speicherbererich für das i von vorher benutzt. Es macht also keinen Unterschied ob du das machst:
CPP: | while(true){
int i;
// etwas Code, wo i verwendet wird
}
|
oder
CPP: | int i;
while(true){
// etwas Code, wo i verwendet wird
}
|
Die Variable global zu deklarieren macht allerdings einen Unterschied.
Da gibt es spezielle Datensegmente für, die nicht auf dem Stack liegen. Weiß aber auch nicht genau wie das funktioniert
Variablen, dessen Speicher per 'new' reserviert wird kommen auf den Heap. Das dauert natürlich länger und der Heap wird bei Speicherfreigaben auch fragmentiert.
Wenn man große Objekte im Speicherablegen will kommt man mit dem kleinen (1 MB glaube ich) Stack nicht hin.
Langer Rede kurzer Sinn, du brauchst dich um sowas nicht zu kümmern.
Speicher im Heap zu reservieren sollte man nicht gerade innerhalb einer Schleife machen (wenn es geht und sinnvoll erscheint). |
|
Nach oben |
|
 |
GreveN JLI Master

Alter: 38 Anmeldedatum: 08.01.2004 Beiträge: 901 Wohnort: Sachsen - Dresden Medaillen: Keine
|
Verfasst am: 01.09.2006, 15:33 Titel: |
|
|
PeaceKiller hat Folgendes geschrieben: | Mmmh ... wenn ich mir das so Recht überlege, ist das auch nicht das gelbe vom Ei, 8mb Speicher einfach so brachliegen zu lassen ist auch nicht so schön. |
Jupp, allerdings wird der beim Beenden des Programms automatisch wieder freigegeben, da das Objekt ja auf im statischen Datenbereich liegt.
AFE-GmdG hat Folgendes geschrieben: | Ich glaube ja überhaupt nicht, dass die einfache Zuweisung einer Variable weniger Zeit kostet, nur weil sie static ist - schliesslich ist der Ram überall gleich schnell. |
Das ist natürlich korrekt, aber wenn man 'static' einsetzt um die Geschwindigkeit zu optimieren, dann nutzt man ja den Umstand aus, dass eventuell teure Konstruktoraufrufe gespart werden können, von daher macht es natürlich bei primitiven Typen keinen Sinn, könnte aber eventuell einen kleinen Geschwindigkeitsgewinn bringen, wenn man relativ komplexe Typen relativ oft, z.B. eben in Schleifen oder dergleichen erzeugt. Fraglich ist natürlich, ob man in diesem Fall wirklich an der richtigen Stelle optimiert. Ich hab das selber noch nie im Profiler ausprobiert, wäre aber eigentlich mal interessant zu testen ob und wenn, wieviel es tatsächlich bringt.
Hier ein netter Artikel zum Thema:
http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=static#Answ
KI hat Folgendes geschrieben: | Soweit ich weiß wird beim 'Betreten' einer Funktion für alle Variablen auf dem Stack schonmal Speicher reserviert. Es ist also egal, ob du die Varaible am Anfang der Funktion deklarierst oder in der Mitte oder am Ende. |
Nope, Objekte werden erzeugt, wenn sie gebraucht werden und das ist auch gut so. Wenn du eine relativ komplexe Funktion hast, welche zahlreiche temporäre Objekte erzeugt, aber nicht zwangsweise bis zum Ende ausgeführt werden muss, wäre dieses Verhalten sehr ineffizient, da ein Großteil der Objekte so eventuell niemals gebraucht würden.
Noch ein schöner Artikel dazu:
http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=Declare#Answ
KI hat Folgendes geschrieben: | Auch für Variablendeklarationenen innerhalb einer Schleife gilt das.
Wenn die Schleife z.B. das zweite mal aufgerufen wird, wird einfach der Speicherbererich für das i von vorher benutzt. Es macht also keinen Unterschied ob du das machst:
CPP: | while(true){
int i;
// etwas Code, wo i verwendet wird
}
|
oder
CPP: | int i;
while(true){
// etwas Code, wo i verwendet wird
}
|
|
Oha, das macht auf alle Fälle einen Unterschied. Wenn du "i" im Scope der Schleife erzeugst, wird es beim Verlassen der Schleife und damit des Scopes auch vom Stack entfernt und ist somit nicht mehr verfügbar. Erzeugst du "i" dagegen vor der Schleife, kannst du auch danach noch darauf zugreifen. Jeder neuere Compiler sollte das endlich korrekt beherrschen, VC6 hatte da afaik z.B. noch 'ne Macke. |
|
Nach oben |
|
 |
unsigned long Junior JLI'ler

Anmeldedatum: 02.07.2006 Beiträge: 52
Medaillen: Keine
|
Verfasst am: 01.09.2006, 19:11 Titel: |
|
|
GreveN bringt es ausnahmslos auf den Punkt. |
|
Nach oben |
|
 |
Jonathan_Klein Living Legend

Alter: 37 Anmeldedatum: 17.02.2003 Beiträge: 3433 Wohnort: Siegerland Medaillen: Keine
|
Verfasst am: 01.09.2006, 21:24 Titel: |
|
|
VC 6 hatte die Macke doch nur in FOrSchleifen, weil da die Varaiblen noch nicht innerhalb der geschweiften Klammern erzeugt wruden, sondern in den rundne Klammern in der Zeile davor.
Ist ist dann halt definitiionssache, das die nur innerhalb der for Schleife gültig zu sein haben, und naja, sowas kann ja mal passeiren  _________________ https://jonathank.de/games/ |
|
Nach oben |
|
 |
KI JLI Master

Alter: 39 Anmeldedatum: 04.07.2003 Beiträge: 965 Wohnort: Aachen Medaillen: Keine
|
Verfasst am: 01.09.2006, 22:48 Titel: |
|
|
Ich glaube es ist nicht ganz klar gworden, was ich sagen wollte. Es geht um das Reservieren von Speicherbereichen.
Ich habe es gerade nochmal getestet. Bei Funktionseintritt wird auf dem Stack auch schon der Speicher für die Variable reserviert, die womöglich erst später in einer Schleife verwendet wird.
Alle Variablen haben schon ihren perönlichen Bereich auf dem Stack. Wenn man sich den Assemblercode anguckt, kann man das schön sehen.
Hier ist eine einfache Klasse der Größe (2 * 4 Bytes) 8 Bytes.
CPP: | class SomeClass
{
private:
int m_i;
int m_j;
public:
SomeClass(int i);
void doSomething();
};
SomeClass::SomeClass(int i)
{
m_i = i;
}
void SomeClass::doSomething()
{
m_i *= 2;
}
|
Jetzt habe ich 2 Funktionen.
CPP: | void doLoop1()
{
while(true)
{
SomeClass someObject(42);
someObject.doSomething();
}
}
void doLoop2()
{
SomeClass someObject(42);
while(true)
{
someObject.doSomething();
}
}
|
Wie man sieht, wird bei der ersten Funktion 'DoLoop1' das Objekt innerhalb der Schleife deklariert und bei der Funktion 'DoLoop2' am direkt Anfang der Funktion.
Ein Blick in den generierten Assemblercode schafft Klarheit.
DoLoop1:
CPP: | ; 29 : {
push ebp
mov ebp, esp
sub esp, 8
$LN2@doLoop1:
; 30 : while(true)
mov eax, 1
test eax, eax
je SHORT $LN3@doLoop1
; 31 : {
; 32 : SomeClass someObject(42);
push 42 ; 0000002aH
lea ecx, DWORD PTR _someObject$5821[ebp]
call ??0SomeClass@@QAE@H@Z ; SomeClass::SomeClass
; 33 :
; 34 : someObject.doSomething();
lea ecx, DWORD PTR _someObject$5821[ebp]
call ?doSomething@SomeClass@@QAEXXZ ; SomeClass::doSomething
; 35 : }
jmp SHORT $LN2@doLoop1
$LN3@doLoop1:
; 36 : }
mov esp, ebp
pop ebp
ret 0
|
DoLoop2:
CPP: | ; 39 : {
push ebp
mov ebp, esp
sub esp, 8
; 40 : SomeClass someObject(42);
push 42 ; 0000002aH
lea ecx, DWORD PTR _someObject$[ebp]
call ??0SomeClass@@QAE@H@Z ; SomeClass::SomeClass
$LN2@doLoop2:
; 41 :
; 42 : while(true)
mov eax, 1
test eax, eax
je SHORT $LN3@doLoop2
; 43 : {
; 44 : someObject.doSomething();
lea ecx, DWORD PTR _someObject$[ebp]
call ?doSomething@SomeClass@@QAEXXZ ; SomeClass::doSomething
; 45 : }
jmp SHORT $LN2@doLoop2
$LN3@doLoop2:
; 46 : }
mov esp, ebp
pop ebp
ret 0
|
An den markierten Positionen sieht man wie jeweils 8 Bytes auf dem Stack reserviert werden.
Mit der Dekleration wird lediglich der Konstruktor aufgerufen.
someObject mag in der ersten Funktion nach der Schleife in C++ nicht mehr mit konventionellen Mitteln erreichbar sein.
Es ist aber noch da. Wenn man sich den Zeiger vorher merkt, kann man den Wert nachher noch lesen und verändern.
Noch ein Beispiel.
CPP: | void doLoop1()
{
while(true)
{
SomeClass someObject(42);
someObject.doSomething();
}
SomeClass someObject(21);
}
|
Hier sieht man wie nach der Schleife nochmal ein Objekt deklariert wird (Sogar vom gleichen Namen). Obwohl an der Stelle der alten Variable aus der Schleife wieder Platz wäre, wird eben der vorher reservierte Platz auf dem Stack genutzt.
Assemblercode:
CPP: | ; 29 : {
pushebp
movebp, esp
subesp, 16; 00000010H
$LN2@doLoop1:
; 30 : while(true)
moveax, 1
testeax, eax
jeSHORT $LN1@doLoop1
; 31 : {
; 32 : SomeClass someObject(42);
push42; 0000002aH
leaecx, DWORD PTR _someObject$5821[ebp]
call??0SomeClass@@QAE@H@Z; SomeClass::SomeClass
; 33 :
; 34 : someObject.doSomething();
leaecx, DWORD PTR _someObject$5821[ebp]
call?doSomething@SomeClass@@QAEXXZ; SomeClass::doSomething
; 35 : }
jmpSHORT $LN2@doLoop1
$LN1@doLoop1:
; 36 :
; 37 : SomeClass someObject(21);
push21; 00000015H
leaecx, DWORD PTR _someObject$[ebp]
call??0SomeClass@@QAE@H@Z; SomeClass::SomeClass
; 38 : }
movesp, ebp
popebp
ret0
|
|
|
Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB.de
|