JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=3bf68b708a37bdfd57132fe6dda329deMedaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Geschwindigkeit Speicherzuweisung

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
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

BeitragVerfasst am: 31.08.2006, 17:00    Titel: Geschwindigkeit Speicherzuweisung Antworten mit Zitat

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.

Wink
_________________
- - - - - - - - - - - - - - - - - - - -
-> http://www.sea-productions.de
-> http://www.krawall.de
- - - - - - - - - - - - - - - - - - - -
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
PeaceKiller
JLI Master


Alter: 36
Anmeldedatum: 28.11.2002
Beiträge: 970

Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 17:16    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Mat
Senior JLI'ler


Alter: 36
Anmeldedatum: 17.09.2005
Beiträge: 205
Wohnort: Koblenz
Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 17:25    Titel: Antworten mit Zitat

Also lohnt es sich Smile das ist schonmal super - mal sehen, wie ich das dann verwalten werde Wink

-> Danke
_________________
- - - - - - - - - - - - - - - - - - - -
-> http://www.sea-productions.de
-> http://www.krawall.de
- - - - - - - - - - - - - - - - - - - -
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Chriss
Senior JLI'ler



Anmeldedatum: 18.08.2004
Beiträge: 267

Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 17:36    Titel: Antworten mit Zitat

Was hat das bitte bei den Tutorials verloren?
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 17:39    Titel: Antworten mit Zitat

'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
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 20:24    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
PeaceKiller
JLI Master


Alter: 36
Anmeldedatum: 28.11.2002
Beiträge: 970

Medaillen: Keine

BeitragVerfasst am: 31.08.2006, 22:42    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
AFE-GmdG
JLI MVP
JLI MVP


Alter: 45
Anmeldedatum: 19.07.2002
Beiträge: 1374
Wohnort: Irgendwo im Universum...
Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 08:51    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 10:16    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
GreveN
JLI Master


Alter: 38
Anmeldedatum: 08.01.2004
Beiträge: 901
Wohnort: Sachsen - Dresden
Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 15:33    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Yahoo Messenger MSN Messenger
unsigned long
Junior JLI'ler



Anmeldedatum: 02.07.2006
Beiträge: 52

Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 19:11    Titel: Antworten mit Zitat

GreveN bringt es ausnahmslos auf den Punkt.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Jonathan_Klein
Living Legend


Alter: 37
Anmeldedatum: 17.02.2003
Beiträge: 3433
Wohnort: Siegerland
Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 21:24    Titel: Antworten mit Zitat

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 Wink
_________________
https://jonathank.de/games/
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
KI
JLI Master


Alter: 39
Anmeldedatum: 04.07.2003
Beiträge: 965
Wohnort: Aachen
Medaillen: Keine

BeitragVerfasst am: 01.09.2006, 22:48    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
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

Impressum