Unangenehmes Problem mit sprintf_s



  • @Dravere
    Ich habe 90% der Applikation mit reinem C implementiert (die C++ Standardbibliothek habe ich nicht angerührt. Ah doch, std::type_info benutze ich. Ich verwende C++ in diesem Projekt ausschliesslich wegen der Templates sowie der Laufzeitpolymorphie. Der Grund liegt darin begründet, dass wir ein Computerspiel als Abschlussarbeit programmieren und Geschwindigkeit an erster Stelle steht. Glaub mir, ich hatte zu beginn die C++ Standard Bibliothek sowie auch die STl umfangreich benutzt, habe jedoch in Folge von Profiling immer mehr C++ Komponenten durch C oder durch eigene Konstrukte ersetzt, weil diese einfach einen nicht hinzunehmenden Overhead hatten. Die std::map benötigte bspw. einfach mal ca. 800 mal länger, um sämtliche Elemente innerhalb der Map zu löschen als bspw. der von mir entwickelte RedBlackTree (Wir haben einige temporäre Bäume, die einmal pro Frame aufgebaut und schliesslich wieder gelöscht werden müssen) Oder die Umstellung einer std::list auf ein natives C Array innerhalb eines kritischen Algorithmus innerhalb der Textengine hatte die Framerate einfach so mal verdoppelt von 500 auf 1000 fps. Die gesamte InGame Konsole benötigt durch die Umstellung von std::string auf cirkuläre c-strings noch ein einziges New und ein einziges Delete während der gesamten Lebensdauer der Applikation und nicht mehr zwischen 10 - 20 news und deletes pro Frame.

    Natürlich hat das alles einen hohen Preis: Ich muss bspw. dem RedBlackTree sagen, wie gross er maximal werden darf und wie hoch die maximale Suchtiefe sein kann und wehe das wird überschritten, genauso wie bspw. die Konsole. Im Konstruktor übergebe ich die Anzahl Zeilen sowie die Anzahl Spalten und dann alloziiere ich einen entsprechend grossen Speicherbereich (EINMAL) und dann verwalte ich diesen Speicherbereich innerhalb des Programms und kopiere nicht bei jeder neuen Eingabe zig strings hin und her und alloziiere hier wieder Speicher und muss da wieder was freigeben...

    Ich weiss doch auch nicht, vielleicht haben wir alles falsch gemacht aber wir haben uns für einen Weg entschieden und den werden wir jetzt auch so zu Ende gehen (in ca. 1.5 Monaten ist Abgabetermin) und da werde ich jtzt sicher nicht wieder alles auf die C++ Bibliothek umstellen (Was wir zu beginn hatten und nicht schnell genug war)...

    Eines aber noch Dravere, wie machst du mit C++ iostreams folgendes:

    "Mein Name ist %s und wohne in %s seit %s"
    "My name is %s and I live in %s since %s"
    ....
    ....

    Diese Strings werden extern gespeichert und werden schliesslich eingelesen und von sprintf_s verarbeitet. Die Positionen der Variablen innerhalb eines Strings kann von Sprache zu Sprache unterschiedlich ausfallen!



  • Ishildur schrieb:

    Die std::map benötigte bspw. einfach mal ca. 800 mal länger, um sämtliche Elemente innerhalb der Map zu löschen als bspw. der von mir entwickelte RedBlackTree (Wir haben einige temporäre Bäume, die einmal pro Frame aufgebaut und schliesslich wieder gelöscht werden müssen)

    Klasse bauen, fertig. Kann man auch den C code nehmen und kapseln.

    Oder die Umstellung einer std::list auf ein natives C Array innerhalb eines kritischen Algorithmus innerhalb der Textengine hatte die Framerate einfach so mal verdoppelt von 500 auf 1000 fps.

    Diese framezahlen habe ich jetzt einfach mal ueberlesen. aber list und array sind unterschiedliche datenstrukturen.

    Die gesamte InGame Konsole benötigt durch die Umstellung von std::string auf cirkuläre c-strings noch ein einziges New und ein einziges Delete während der gesamten Lebensdauer der Applikation und nicht mehr zwischen 10 - 20 news und deletes pro Frame.

    nocopy strings nehmen oder strings aus einem statischen memory pool aufbauen...

    Ich weiss doch auch nicht, vielleicht haben wir alles falsch gemacht aber wir haben uns für einen Weg entschieden und den werden wir jetzt auch so zu Ende gehen (in ca. 1.5 Monaten ist Abgabetermin) und da werde ich jtzt sicher nicht wieder alles auf die C++ Bibliothek umstellen (Was wir zu beginn hatten und nicht schnell genug war)...

    Der Fehler war von C++ wegzugehen 😉 Denn du hast kein Argument gegen C++ genannt nur gegen bestimmte klassen die sich aber problemlos ersetzen lassen.

    Eines aber noch Dravere, wie machst du mit C++ iostreams folgendes:

    "Mein Name ist %s und wohne in %s seit %s"
    "My name is %s and I live in %s since %s"
    ....
    ....

    Diese Strings werden extern gespeichert und werden schliesslich eingelesen und von sprintf_s verarbeitet. Die Positionen der Variablen innerhalb eines Strings kann von Sprache zu Sprache unterschiedlich ausfallen!

    boost::format

    aber wenn man C programmiert oder C code warten muss, ist sprintf_s natuerlich eine gute wahl. nur bei einer neuentwicklung... ich weiss nicht.



  • @Shade Of Mine

    Klasse bauen, fertig.
    

    Habe ich ja genauso gemacht?

    Diese framezahlen habe ich jetzt einfach mal ueberlesen.

    Glaubst du mir etwa nicht?

    aber list und array sind unterschiedliche datenstrukturen.

    Ja ich habe mich verschrieben, war natürlich ein std::vector
    Der Punkt dabei war einfach, dass ich für die Textengine (1000fps, was du mir ja nicht glaubst) ein deferred Rendering verwende. Sprich, wenn ich SpriteBatch::DrawText aufrufe, wird noch gar nichts gezeichnet, sondern der entsprechende Text als DrawJob gespeichert. Schliesslich wird einmal pro Frame der komplette Text mit Hilfe eines einzigen Rendercalls gerendert. Dafür muss aber nach jedem Frame der std::vector der Drawjobs komplett entleert werden. Mit einem nativen c - array war dieser Enleerungsprozess jedoch hinfällig, weil ich stattdessen die DrawJobs da lasse wo sie sind und stattdessen eifach den Zeiger wieder auf das erste Element setze, so werden die alten Drawjobs nach und nach überschrieben. (Was eigentlich jedes Betriebssystem auch so macht, wird ja auch nicht jedes bit mit null überschrieben, wenn eine Datei gelöscht wird...)

    Sprite aSpr[MAX_SPRITE];
    uint32 cSpr  = 0;
    
    void SpriteBatch::DrawText(){
     this->aSpr[this->cSpr++] = // kompliziert... :-p
    }
    
    void Render(){
     for(uint32 i=0;i<this->cSpr;++i){
      // in VertexBuffer abfüllen
     }
    
     IDirect3DDevice9::DrawIndexedPrimitive();
    
     // die Sprites werden nicht gelöscht oder alle auf null gesetzt oder
     // sonst irgendwas
     this->cSpr = 0;
    }
    

    Der Fehler war von C++ wegzugehen

    Ja ich habs vielleicht falsch ausgedrückt, als ich sagte, ich hätte zu 90% in C programmiert meinte ich, dass ich fast ausschliesslich die C Standard Bibliothek anstelle der C++ Standard Bibliothek verwende oder dann grad komplett eigene Implementierungen geschrieben habe.

    oder strings aus einem statischen memory pool aufbauen

    Genau das mache ich doch??

    Denn du hast kein Argument gegen C++ genannt nur gegen bestimmte klassen die sich aber problemlos ersetzen lassen.

    Genau das mache ich doch?? Ich finde C++ super, nur viele der Standardbibliotheken passen mir nicht und habe ich desshalb durch eigene Implementationen ersetzt.



  • @Shade Of Mine
    Das mit den Framezahlen habe ich mit Fraps nachgemessen um sicherzustellen, dass ich keinen Fehler in der Berechungsformel habe.



  • Ich vermute bei den Problemen mit std::vector etc. eher, dass Debugmodus und/oder checked Iterators (die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen) vermessen wurden. Gerade das "entleeren" eines std::vector sollte nichts kosten, da std::vector beim Verkleinern nicht reallokiert. Und wenn die im std::vector gespeicherten Strukturen PODs sind, findet auch kein Destruktoraufruf statt (und wenn es keine PODs sind, müssen auch die Elemente im C-Array destruiert werden).



  • Ishildur schrieb:

    Diese framezahlen habe ich jetzt einfach mal ueberlesen.

    Glaubst du mir etwa nicht?

    Die Zahlen sind komisch. FPS ist kein sehr guter Indikator für die tatsächliche Geschwindigkeit.

    Fraglich ist, wie gemessen wurde und wie relevant das Ergebnis ist. Wenn mit einer Auflösung von 1 ms gemessen wurde, kann schon ein tatsächlicher Unterschied von lediglich 0.01 ms zu so einem drastischen Sprung des angezeigten Messwerts führen. Da du ausgerechnet 1000 und 500 genannt hast, liegt es nahe, dass das hier passiert sein könnte.

    Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS; auf diese realistische Frequenz umgerechnet beträgt der Unterschied nur noch ein paar Prozent. Und das auch nur, wenn tatsächlich exakt gemessen wurde, und nicht im 1 ms-Raster.
    Diese paar Prozent, die nachher vielleicht gar nicht relevant sind, hast du dir durch mehr Entwicklungsaufwand erkauft. Und vielleicht mehr Debugging-Aufwand, wenn sich Fehler eingeschlichen haben die mit erprobten Strukturen nicht aufgetreten wären.

    LordJaxom schrieb:

    Ich vermute bei den Problemen mit std::vector etc. eher, dass Debugmodus und/oder checked Iterators (die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen) vermessen wurden.

    Ein sehr gern gemachter Fehler beim Messen.



  • die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen

    Hoppla, ja da hatte ich tatsächlich nichts entsprechendes deaktiviert, wie mache ich denn das?

    Fraglich ist, wie gemessen wurde und wie relevant das Ergebnis ist. Wenn mit einer Auflösung von 1 ms gemessen wurde, kann schon ein tatsächlicher Unterschied von lediglich 0.01 ms zu so einem drastischen Sprung des angezeigten Messwerts führen. Da du ausgerechnet 1000 und 500 genannt hast, liegt es nahe, dass das hier passiert sein könnte.

    Ich benutze den QueryPerformanceCounter also nix 1ms Raster :p

    Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS

    Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt) 60Hz ist für das Auge durchaus vernünftig und völlig ausreichend, nicht jedoch für die Haptik, da wärend 1kHz und mehr durchaus wünschenswert...


  • Administrator

    Ishildur schrieb:

    die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen

    Hoppla, ja da hatte ich tatsächlich nichts entsprechendes deaktiviert, wie mache ich denn das?

    http://msdn.microsoft.com/en-us/library/aa985965.aspx

    Ishildur schrieb:

    Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt)

    Das ist völliger Humbug. VSync ist bei LCD immer noch nötig. Wenn die Graphikkarte mit höherer Geschwindigkeit Bilder produziert als der Bildschirm Herz hat, dann kann es immernoch zu Überlappungen kommen, weil womöglich zu dem Zeitpunkt, als sich der Bildschirm sein Bild holte, die Graphikkarte gerade in den Puffer am schreiben war.

    Ishildur schrieb:

    Der Punkt dabei war einfach, dass ich für die Textengine (1000fps, was du mir ja nicht glaubst) ein deferred Rendering verwende. Sprich, wenn ich SpriteBatch::DrawText aufrufe, wird noch gar nichts gezeichnet, sondern der entsprechende Text als DrawJob gespeichert. Schliesslich wird einmal pro Frame der komplette Text mit Hilfe eines einzigen Rendercalls gerendert. Dafür muss aber nach jedem Frame der std::vector der Drawjobs komplett entleert werden. Mit einem nativen c - array war dieser Enleerungsprozess jedoch hinfällig, weil ich stattdessen die DrawJobs da lasse wo sie sind und stattdessen eifach den Zeiger wieder auf das erste Element setze, so werden die alten Drawjobs nach und nach überschrieben. (Was eigentlich jedes Betriebssystem auch so macht, wird ja auch nicht jedes bit mit null überschrieben, wenn eine Datei gelöscht wird...)

    Also das musst du mir jetzt nochmals genauer erklären. Wieso müsste eigentlich ein std::vector entleert werden, ein C Array aber nicht? Wer zwingt dich überhaupt clear aufzurufen? Abgesehen davon, dass natürlich ein clear eigentlich gar keinen Speicher freigeben würde. Das klingt für mich, dass du std::vector regelmässig gelöscht und neu Speicher reservieren hast lassen und dich dann darüber wunderst, wenn du dies mit einem C Array nicht machst, dass es schneller ist.

    Da bekommt man doch etwas Zweifel an deinen Performance-Messungen 😉

    Ishildur schrieb:

    oder strings aus einem statischen memory pool aufbauen

    Genau das mache ich doch??

    Nein, du verwendest schlicht und einfach C Strings mit einem Memory Pool. Dabei gäbe es Möglichkeiten sowas zu kapseln. Man könnte zum Beispiel einen Memory Pool erstellen und die std::string von dort ihren Speicher holen lassen. Oder man erstellt Views auf den Speicher mit eigenen Klassen. Es gäbe verdammt viele Möglichkeiten sowas zu optimieren und zwar auch direkt mit der STL.

    Es gäbe zum Beispiel auch die Möglichkeiten den Allocator zu ändern oder man kann sich Klassen bauen, welche automatisch Speicher aus einem Memory Pool besorgen, wenn einem die Allocators zu unangenehm sind.

    Ein Stichwort wäre hier zum Beispiel: Small Object Allocator.
    Eine mögliche Implementation hat Andrei Alexandrescu in seinem Buch Modern C++ Design vorgestellt. Der Code ist im Internet in der Loki Bibliothek vorhanden:
    http://loki-lib.sourceforge.net/
    http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/SmallObj.h?view=markup

    Daran sieht man, was für Möglichkeiten einem offen stehen und man kann das für seine Zwecke verändern.

    Genau das mache ich doch?? Ich finde C++ super, nur viele der Standardbibliotheken passen mir nicht und habe ich desshalb durch eigene Implementationen ersetzt.

    Das sieht aber nicht wirklich danach aus. Es sieht mehr nach einem C mit Klassen aus. Schon nur deine C Strings deuten darauf hin, welche du nicht sinnvoll gekapselt hast. Wahrscheinlich auch an vielen Orten Dinge wie RAII missachtet, usw. usf.
    Es sieht hauptsächlich danach aus, als wenn du die C++ Standardbibliothek weggeworfen hast und nun die C Bibliothek einsetzt und dies einfach in Klassen. Das ist aber kein sinnvoller und sicherer Ersatz.

    Für eine Korrektur ist es sicherlich zu spät, da stimme ich dir zu. Nur solltest du vielleicht aufpassen, was du in die Arbeit schreibst, wieso du so programmiert hast. Und für die Zukunft gibt es noch einiges zu lernen 🙂

    Grüssli



  • Ishildur schrieb:

    Ich benutze den QueryPerformanceCounter also nix 1ms Raster :p

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Ishildur schrieb:

    Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS

    Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt) 60Hz ist für das Auge durchaus vernünftig und völlig ausreichend, nicht jedoch für die Haptik, da wärend 1kHz und mehr durchaus wünschenswert...

    Zu dem was Dravere dazu geschrieben hat möchte ich noch hinzufügen, dass ich den Sinn von Optimierungen fragwürdig finde, die dazu dienen, die Anzahl der berechneten, aber letztlich sowieso unsichtbaren Bilder von 440 auf 940 zu steigern 🙂

    Und die Sache mit der Haptik... 1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät. Es würde mich wundern, wenn irgendein Gerät öfter als vielleicht 100x pro Sekunde abgefragt würde.



  • Das ist völliger Humbug. VSync ist bei LCD immer noch nötig.

    Ja meinetwegen, ich habe zusammen mit meinem Partner 5 Testgeräte, das Spiel hat überall unterschiedliche Frameraten, ein Flackern oder sonstige typische Effekte von ausgeschaltetem V-Sync konnten wir nirgends wahrnehmen, sollte sich dies ändern hat der Spieler jederzeig die Möglichkeit, V-Sync einzuschalten.

    Wer zwingt dich überhaupt clear aufzurufen?

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    ein, du verwendest schlicht und einfach C Strings mit einem Memory Pool. Dabei gäbe es Möglichkeiten sowas zu kapseln. Man könnte zum Beispiel einen Memory Pool erstellen und die std::string von dort ihren Speicher holen lassen. Oder man erstellt Views auf den Speicher mit eigenen Klassen. Es gäbe verdammt viele Möglichkeiten sowas zu optimieren und zwar auch direkt mit der STL.

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    Und für die Zukunft gibt es noch einiges zu lernen
    

    Wer kann das nicht von sich behaupten? :p


  • Administrator

    Ishildur schrieb:

    Wer zwingt dich überhaupt clear aufzurufen?

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    1. Ich will dich nicht als völligen Idioten hinstellen. Ich will dir nur mögliche Fehler aufzeigen, da man aus Fehlern lernt.
    2. Du willst mir doch nicht sagen, dass std::vector::clear aus deiner Sicht die einzige andere Funktionalität zu einem C Array darstellt?
    Zudem gäbe es, wie ich schon früher mal sagte, die Möglichkeit von std::tr1::array , bzw. boost::array , falls du statische Arraygrössen hast.

    Ishildur schrieb:

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    Ich zweifle sehr stark daran, dass dies der weniger aufwendigere Weg gewesen ist. Auf den ersten Blick mag dies vielleicht stimmen, aber spätestens beim Zweiten solltest du erkennen, wie fehleranfällig solche C Konstrukte sein können. Vielleicht hast du ein bisschen weniger Aufwand zum Schreiben (wobei ich sogar dies bezweifle), dafür kannst du dir eine Menge Ärger zu einem späteren Zeitpunkt einholen. Dass du ein komplettes Framework dafür schreiben müsstest, ist theatralisch übertrieben.

    Auch finde ich es irgendwie lustig, dass du auf die C++ Möglichkeiten verzichtest, C einsetzt, dann aus Sicherheitsgründen auf nicht standardisierte Funktionen wie sprintf_s setzt und am Ende damit noch in undefiniertes Verhalten reinrennst 😉

    Ishildur schrieb:

    Und für die Zukunft gibt es noch einiges zu lernen
    

    Wer kann das nicht von sich behaupten? :p

    Ich natürlich ... zweifelst du das in etwa an? 🤡
    Es war aber mehr im Sinne gemeint, dass du aus deinen Ergebnissen besser nicht all zu viele Schlüsse für die Zukunft in der Programmierung in C++ ziehen solltest. Du dich daher besser zu der Thematik mit zum Beispiel Fachliteratur informieren solltest.

    Grüssli



  • Ishildur schrieb:

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    Weil deine Argumentation falsch ist. ob vector oder nicht, so eine funktionalität hat gekapselt zu sein. und deine argumentation mit allokationen ist ebenfalls falsch - denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.

    nur vector oder etwas entsprechendes würde hier eine menge code sparen. was wenn du plötzlich mehr draw jobs hast?

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    eine klasse oder ein allokator, der aufwand sind vielleicht 30min.
    ne ne, das zählt nicht.

    deine entscheidungen mögen ja vielleicht sinn machen - aber deine argumentation ist falsch.



  • @Nukularfüsiker

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Besser nicht sonst werde ich hier noch mehr zusammengestaucht :p

    Zu dem was Dravere dazu geschrieben hat möchte ich noch hinzufügen, dass ich den Sinn von Optimierungen fragwürdig finde, die dazu dienen, die Anzahl der berechneten, aber letztlich sowieso unsichtbaren Bilder von 440 auf 940 zu steigern 🙂

    Naja, wenn ich sämtliche Komponenten zusammenfüge inklusive Physik und AI bin ich schon bei unter 100 fps, aber für die Performance Tests der einzelnen Komponenten schalte ich alle anderen zwischenzeitlich aus. Die Textengine arbeitet (wenn alles andere deaktiviert ist) mit den 1000 fps, aber auch nur dann, wenn ich nur eine enzige Schrift verwende. Muss ich während dem Rendern noch ein Texturwechsel vornehmen, sinkt die Framerate auch gleich wieder drastisch, weil ich es dann in zwei Render Calls aufteilen muss, wobei ich natürlich nach Textur gruppiere.

    1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät

    Ich studiere den Schwerpunkt "Computer Perception & Virtual Reality" offenbar sind dann alle unsere Scripts fehlerhaft... :p
    Gucks du hier: http://www.pc-cooling.de/Eingabegeraete/Maeuse/900500200/SPEEDLINK+Kudos+Gaming+Mouse,+black.html

    @Dravere

    Auch finde ich es irgendwie lustig, dass du auf die C++ Möglichkeiten verzichtest, C einsetzt, dann aus Sicherheitsgründen auf nicht standardisierte Funktionen wie sprintf_s setzt und am Ende damit noch in undefiniertes Verhalten reinrennst

    Jaja, das findest du jetzt lustig was du Assi :p



  • Ishildur schrieb:

    @Nukularfüsiker

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Besser nicht sonst werde ich hier noch mehr zusammengestaucht :p

    Dann vielleicht als genereller Tipp: Zeig zusätzlich zu den FPS auch die Framedauer in ms an, bis auf 2 Stellen hinter dem Komma (sollte mit PerformanceCounter ja kein Problem sein) und benutze diese Zahl für Vergleiche. FPS sind irreführend, weil bei 1000 FPS beispielsweise 0.5 ms Mehraufwand als dramatischer Verlust von 333 FPS dargestellt werden. Bei 60 FPS wären das gerade mal 2 Frames weniger. Und Rundungsfehler bei der Umrechnung können auch eine erhebliche Abweichung verursachen.

    1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät

    Ich studiere den Schwerpunkt "Computer Perception & Virtual Reality" offenbar sind dann alle unsere Scripts fehlerhaft... :p
    Gucks du hier: http://www.pc-cooling.de/Eingabegeraete/Maeuse/900500200/SPEEDLINK+Kudos+Gaming+Mouse,+black.html

    Ok, ich erkenne die Existenz dieser "Gaming Mouse" an, die 1000 Hz polling rate verspricht. Was diese Werbeaussauge in der Realität wert ist, kann ich nicht beurteilen. Und übliches Equipment dürfte erheblich langsamer abgefragt werden.



  • @Shade of Mine
    denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.

    std::vector<int> lsInt;
     int index = 0;
    
    int aInt[MAX_TEXT];
     int index = 0;
    

    Wo ist jetzt der Unterschied? Das std::vector selbstständig wächst? Ja aber nicht wenn ich den [] operator von std::vector benutze um daraum zuzugreifen. Damit std::vector wächst muss ich Add benutzen. Und wenn ich Add benutze muss ich doch auch Clear benutzten?? Natürlich, im einfachsten Fall setzt Clear einfach den internen AddZeiger wieder auf 0, aber eben man weiss nicht so genau was das Ding dann wirklich macht? Bei einem nativen array weiss ich hingegen genau was ich mache. Zusätzlich wird einfach von Vector jedes Mal, wenn ich diese Methode aufrufe ein new und ein delete erzeugt. Während das native Array einfach ein sub esp MAX_TEXT macht? Was wird wohl schneller sein?

    eine klasse oder ein allokator, der aufwand sind vielleicht 30min.

    Ein Memorypool Manager, der sämtliche Instancen informieren muss, wenn eine Reallokation auf dem Heap stattgefunden hat programmierst du in 30min? 😮



  • @Nukularfüsiker

    Dann vielleicht als genereller Tipp: Zeig zusätzlich zu den FPS auch die Framedauer in ms an

    Das überzeugt mich! Eine Sekunde bin gerade dabei 🙂

    Und übliches Equipment dürfte erheblich langsamer abgefragt werden.

    Ich sagte auch bloss dass 1kHz und mehr wünschenswert wären. Das Problem ist einfach die menschliche Sensorik. Das Auge ist einfach ein extrem träger biometrischer Sensor. Der Tastsinn bspw. reagiert einfach extrem viel schneller und sensibler. Man merkt dies bspw. schon an einfachen Games. Bei 30 fps reagiert bspw. die Steuerung bereits extrem träge obwohl das Bild noch nicht ruckelt. Für das Auge ist es noch schnell genug, aber all unsere anderen Sensoren bemerken längst, dass da etwas nicht stimmt...



  • Ishildur schrieb:

    Wo ist jetzt der Unterschied?

    MAX_TEXT

    das ist der einzige.

    dh, du sparst speicher mit vector 😉

    und natürlich die sicherheit mit bounds checking und so, das was man in c++ hat alles gratis bekommt.

    Ein Memorypool Manager, der sämtliche Instancen informieren muss, wenn eine Reallokation auf dem Heap stattgefunden hat programmierst du in 30min? 😮

    klar.
    voraussetzung ist halt, dass der code schon existiert. oder wie hast du ihn in C geschrieben? da ein c++ interface drumherum um eben bufferoverlows und co zu verhinden dauert dann 30min.

    PS:
    rendering und input verarbeitung tust du aber schon trennen, oder?
    FPS sind ein komplett uninteressantes mess werkzeug. denn du willst zwar viele frames haben, aber über 60 ist es irrelevant wieviele mehr es sind.

    input und logik läuft davon sowieso getrennt.



  • Ishildur schrieb:

    denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.
    ...
    Wo ist jetzt der Unterschied? Das std::vector selbstständig wächst? Ja aber nicht wenn ich den [] operator von std::vector benutze um daraum zuzugreifen. Damit std::vector wächst muss ich Add benutzen. Und wenn ich Add benutze muss ich doch auch Clear benutzten??...

    Mal ganz davon abgesehen das std::vector weder eine Add noch eine Clear-Methode hat (wenn schon push_back und clear), und clear nicht nötig ist, wenn du ihn nur überschreiben willst, kann man einem vector auch für eine feste Größe reservieren lassen (Denn ansonsten kann ggf. beim push_back ein umkopieren nötig werden => was sich tatsächlich in der Performance unterscheidet).

    Wenn man std::vector RICHTIG verwendet (sprich in deinem Fall auch mit reserve oder resize, bzw. richtigen Konstruktor um die Größen festzulegen, oder den Speicher richtig zu reservieren), ist er kaum mehr von einen C-Array zu unterscheiden. Hierfür gibt es auch noch einen besseren Ersatz: std::tr1::array oder boost::array.

    Ishildur schrieb:

    Zusätzlich wird einfach von Vector jedes Mal, wenn ich diese Methode aufrufe ein new und ein delete erzeugt.

    Das ist schlicht und ergreifend falsch. Ein vector allokiert zwar Speicher, diesen aber an einen Stück und auch für mehrere Elementen. Ein push_back führt nur dann zu einem neuallokieren, wenn der reservierte Speicher nicht ausreicht. Ein Vector der richtig initialisiert wurde (sprich wenn man die richtige Größe auch weiß), wird nicht einmal den Speicher neu reservieren.

    // Eine der nachfolgenden Zeilen einfach austauschen...
    int v[10];
    // std::vector<int> v(10, 0);
    // std::tr1::array<int, 10> v;
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    

    So schon hast du die Array-Notation. Die array-Klasse ist dabei imho die beste Wahl wenn die Größe bekannt ist (Da man sie auch bei Bedarf einfach kopieren kann usw.), und gegenüber einen C-Array so gut wie keinen Overhead besitzt.



  • @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

    @asc

    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.


Anmelden zum Antworten