Unangenehmes Problem mit sprintf_s
-
@Shade Of Mine
rendering und input verarbeitung tust du aber schon trennen, oder?
Wie meinst du das genau?
aber über 60 ist es irrelevant wieviele mehr es sind.
WOW, ist das dein Ernst? Also wenn das Spiel bei meinem Super Highend PC mit über 60fps läuft, muss ich nichts mehr optimieren? Selber Schuld wenn die potentiellen Käufer halt keinen so tollen PC haben? :p
Das ist schlicht und ergreifend falsch. Ein vector allokiert zwar Speicher, diesen aber an einen Stück und auch für mehrere Elementen
Ja schon, aber eben jedesmal wenn dieser std::vector erzeugt wird
// Eine der nachfolgenden Zeilen einfach austauschen... int v[10]; // sub esp 0ah // std::vector<int> v(10, 0); // hier ist intern IMHO ein new erforderlich, da die Grösse zur Compilezeit nicht bekannt ist. // std::tr1::array<int, 10> v; // OK, hier ist grösse bekannt, clever! :) for(int i=0; i<10; ++i) v[i] = i;
Ist dieser Code in einer Funktion, die 10 mal pro Frame aufgerufen wird bei 500 fps verursacht std::vector 5'000 Memoryallokationen pro Sekunde, dass sind bei einer Programmdauer von 2 Spielstunden 180 Mio. Allokationen mehr als nötig. Verursacht durch ein einziges std::vector. std::tr1::array muss ich noch genau anschauen, was das genau macht, bevor ich etwas dazu sagen kann...
-
Ishildur schrieb:
@Shade Of Mine
rendering und input verarbeitung tust du aber schon trennen, oder?
Wie meinst du das genau?
Du renderst unabhängig von der logik und dem input. Logik muss man vom Rendering ja sowieso trennen, da du in einem logik-tick ja je nach hardware leistung unterschiedlich viele frames berechnen kannst.
aber über 60 ist es irrelevant wieviele mehr es sind.
WOW, ist das dein Ernst? Also wenn das Spiel bei meinem Super Highend PC mit über 60fps läuft, muss ich nichts mehr optimieren? Selber Schuld wenn die potentiellen Käufer halt keinen so tollen PC haben? :p
bewegen wir uns echt auf so einem niveau?
Ja schon, aber eben jedesmal wenn dieser std::vector erzeugt wird
[...]Ist dieser Code in einer Funktion, die 10 mal pro Frame aufgerufen wird bei 500 fps verursacht std::vector 5'000 Memoryallokationen pro Sekunde, dass sind bei einer Programmdauer von 2 Spielstunden 180 Mio. Allokationen mehr als nötig. Verursacht durch ein einziges std::vector. std::tr1::array muss ich noch genau anschauen, was das genau macht, bevor ich etwas dazu sagen kann...da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.
-
Du renderst unabhängig von der logik und dem input. Logik muss man vom Rendering ja sowieso trennen, da du in einem logik-tick ja je nach hardware leistung unterschiedlich viele frames berechnen kannst.
Ach so, ja das tue ich, ich dacht du meinst vielleicht in separaten Threads...
bewegen wir uns echt auf so einem niveau?
Wer weiss, mal sehen, was ich nach dem Studium mache...
da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.
Nein das interessiert mich jetzt, was habe ich nicht verstanden?
-
Ishildur schrieb:
da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.
Nein das interessiert mich jetzt, was habe ich nicht verstanden?
Zwischen dem:
void f1() { int v[10]; for(int i=0; i<10; ++i) v[i] = i; }
und dem:
void f2() { std::tr1::array<int, 10> v; for(int i=0; i<10; ++i) v[i] = i; }
besteht ein Unterschied von ziemlich genau Nada(ich gehe mal davon aus dass std::tr1::array auch auf dem Stack liegt). Jedes mal wenn du eine der Funktionen betrittst wird auf dem Stack Speicher reserviert und beim Verlassen wieder freigegeben. Dieses Freigeben ist bei beiden Alternativen sehr schnell weil nur ein Stackpointer geaendert werden muss.
Wenn du natuerlich sowas machst:void f3() { std::vector<int> v(10,0); for(int i=0; i<10; ++i) v[i] = i; }
Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.
Da man aber wohl davon ausgehen kann dass du eine begrenzte, konstante Anzahl von Threads hast (wenn nicht sogar nur einen) kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren.
Beispiel fuer einen Thread:class TolleCppKlasse { public: TolleCppKlasse() { v_.resize(10); } void f4() { for(int i=0; i<10; ++i) v_[i] = i; } private: std::vector< int > v_; };
Das ist wiederum exakt so schnell wie f1 und f2, aber du hast das ganze in ner schoenen Verpackung.
Eine Implementierung fuer mehrere Threads ueberlass ich mal dir.
-
@rean
Also das habe ich alles ganz genau verstanden...besteht ein Unterschied von ziemlich genau Nada
Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?
Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.
GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p
kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren
Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.
-
Ishildur schrieb:
Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?
so eine array klasse hat man einfach.
Denn sie ist einfach besser als ein nacktes array.Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese synchronisation hinfällig weil jeder Frame sein eigener Stack hat.
dh du berechnest frames parallel? finde ich strange.
aber bitte, dann packt man den vector halt auf den stack (sprich verwendet einen stackbasierten container), ist ja kein problem. ich sehe nur ein generelles konzeptproblem wenn jeder frame den du berechnest alles neu machen muss - du hast keine daten die du vom letzten frame übernehmen kannst um zB effektiveres caching zu machen?PS:
du widersprichst dir selbst aber oft.
einmal wird das array wiederverwendet und ist deshalb so schnell weil nur ein zeiger umgebogen werden muss und einmal wird nichts wiederverwendet, etc. sehr verwirrend...
-
Ishildur schrieb:
@rean
Also das habe ich alles ganz genau verstanden...besteht ein Unterschied von ziemlich genau Nada
Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?
Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.
GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p
kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren
Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.
Weil ein vector dir viel mehr Funktionalitaet bietet als ein blankes Array:
http://cplusplus.com/reference/stl/vector/
http://cplusplus.com/reference/algorithm/
Ich bin mir sicher dass du einige dieser Funktionen entweder selbst programmiert oder C-Funktionen dafuer verwendet hast.Wenn beide wirklich die selbe Funktionalitaet brauchem kannst du entweder jedem einfach ein Objekt der Klasse geben, damit hast du wieder getrennte Speicher, oder du verwendest eben ein vector-array und holst dir ueber die thread-id den passenden vector:
class TolleCppKlasse { public: TolleCppKlasse() { v_.resize(2); for( int i = 0; i < anzahl_threads; ++i ) { v_[i].resize(10); } } void f4() { std::vector< int > &cur_vec = v_[getThreadID()]; for(int i=0; i<10; ++i) cur_vec[][i] = i; } private: std::vector< std::vector< int > > v_; };
War das jetzt so schwer?
Ich glaube dein Problem ist dass du nicht weisst was dir die STL alles bietet, schau dir mal die Links oeben an.
-
rean schrieb:
Ishildur schrieb:
@rean
Also das habe ich alles ganz genau verstanden...besteht ein Unterschied von ziemlich genau Nada
Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?
Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.
GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p
kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren
Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.
Weil ein vector dir viel mehr Funktionalitaet bietet als ein blankes Array:
http://cplusplus.com/reference/stl/vector/
http://cplusplus.com/reference/algorithm/
Ich bin mir sicher dass du einige dieser Funktionen entweder selbst programmiert oder C-Funktionen dafuer verwendet hast.Wenn beide wirklich die selbe Funktionalitaet brauchem kannst du entweder jedem einfach ein Objekt der Klasse geben, damit hast du wieder getrennte Speicher, oder du verwendest eben ein vector-array und holst dir ueber die thread-id den passenden vector:
class TolleCppKlasse { public: TolleCppKlasse() { v_.resize(2); for( int i = 0; i < anzahl_threads; ++i ) { v_[i].resize(10); } } void f4() { std::vector< int > &cur_vec = v_[getThreadID()]; for(int i=0; i<10; ++i) cur_vec[i] = i; } private: std::vector< std::vector< int > > v_; };
War das jetzt so schwer?
Ich glaube dein Problem ist dass du nicht weisst was dir die STL alles bietet, schau dir mal die Links oben an.
-
@Shade of Mine
so eine array klasse hat man einfach.
Denn sie ist einfach besser als ein nacktes array.Ja Papi... :p
dh du berechnest frames parallel? finde ich strange.
Vergiss nicht, das ist erst mein 2. Spiel, ich bin also noch nicht so erfahren und muss noch viel lernen, keine Frage
Habe im 3. Semester ein XBox360 Spiel mit XNA gemacht, könnte ich da nochmal anfangen, würde ich auch einige Dinge anders machen und das wird bei diesem Projekt sicherlich auch der Fall sein. In 2-3 Jahren werde ich zurückblicken und darüber lachen, was ich heute hier zusammen hacke und wie naiv ich doch damals (jetzt) gewesen bin :p
Aber um deine Frage zu beantworten, nein ich berechne keine Frames parallel. Ich habe wie 3 parallel laufende Schleifen und an ganz bestimmten Stellen, greifen die Threads auf gemeinsame Daten zu, so nach dem Producer/Consumer Prinzip. Bspw. verarbeitet der INetworkService alle (asynchron) empfangenen UDP Packete und legt schliesslich Notification Messages in eine Queue. Diese Queue wird dann vom GameLoop im Mainthread einmal pro Frame abgefragt. Ähnlich verhält es sich mit dem IResourceService. Der GameLoop legt LadeBefehle in eine Queue, und der IResourceService lädt dann (innerhalb des Threads sequentialisiert) alle Resourcen für die ein LadeBefehl in der Queue steht.
-
Als Ergänzung zu dem was Shade Of Mine und rean gesagt haben:
Ishildur schrieb:
Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?
1. Leistet das native Array nicht genau dasselbe. Siehe auch:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-265807.html
2. Wieso zusätzliche Bibliothek? Die meisten aktuellen Kompiler bieten die Unterstützung für den Technical Report 1 an.std::tr1::array
sollte somit bereits standardmässig vorhanden sein. Ansonsten kann man sich das schnell selber erstellen. Ist eine Sache von Sekunden. Nein, ich schreibe es nicht in Sekunden, sondern kopiere es in Sekunden aus dem Boost-Quellcode File raus und füge es bei mir einIshildur schrieb:
GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!!
Schon, nur hast du völlig falsch Verglichen und deine Argumentation dazu war einfach nur falsch.
Zudem muss ich noch das hier wirklich unterstreichen:
Shade Of Mine schrieb:
du widersprichst dir selbst aber oft.
einmal wird das array wiederverwendet und ist deshalb so schnell weil nur ein zeiger umgebogen werden muss und einmal wird nichts wiederverwendet, etc. sehr verwirrend...
-
War das jetzt so schwer?
Nein sicher nicht. Ich kritisiere ja aber auch niemanden, der die STL und die Standard C++ Library oder Boost oder Loki oder alles zusammen benutzt. Wichtig ist doch, dass die verwendeten Werkzeuge ihren Zweck erfüllen.
Ich kritisiere allerdings auch niemanden, der das nicht tut und einen anderen Weg ausprobiert um zu sehen, wohin er führt...
-
du widersprichst dir selbst aber oft.
Wenn ich das tue, tut es mir leid, das ist kein Absicht.
einmal wird das array wiederverwendet und ist deshalb so schnell weil nur ein zeiger umgebogen werden muss und einmal wird nichts wiederverwendet, etc. sehr verwirrend...
Ja das waren zwei verschiedene Beispiele. Einmal das Problem, dass wenn ich einen lokalen std::vector innerhalb einer Methode habe, da eben durchaus Speicher auf dem Heap alloziiert wird. Das mit dem Zeiger umbiegen war ein anderes Beispiel aber irgendwie bin ich da wohl abgeschweift
-
Ishildur schrieb:
...Wichtig ist doch, dass die verwendeten Werkzeuge ihren Zweck erfüllen. ;)...
Was bezogen auf deinen Eingangspost jedenfalls scheinbar nicht gegeben ist.
-
Also die InGame Konsole läuft jetzt einwandfrei und der Parser, denn ich natürlich auch völlig falsch und nicht Standardkonform geschrieben habe, verarbeitet die Scripts fehlerfrei. In diesem Sinne hat sprintf_s seinen Zweck wahrlich nicht erfüllt... :p
-
Ishildur schrieb:
Also die InGame Konsole läuft jetzt einwandfrei und der Parser, denn ich natürlich auch völlig falsch und nicht Standardkonform geschrieben habe, verarbeitet die Scripts fehlerfrei. In diesem Sinne hat sprintf_s seinen Zweck wahrlich nicht erfüllt... :p
Wie ich bereits gesagt habe: die Design Entscheidungen mögen ja richtig gewesen sein (wir kennen die Umstände ja nicht) aber deine Argumentation ist falsch.