Unterschiedliche Rechenergebnisse: Debug und Release



  • Sobald ich die Compilereinstellungen für Release x64 ändere addiert der Compiler wieder korrekt?!



  • Tomahawk schrieb:

    Sobald ich die Compilereinstellungen für Release x64 ändere addiert der Compiler wieder korrekt?!

    Der Code den du gepostet hast ist so nicht ausführbar. Wieso debuggst du ihn nicht einfach? Du könntest auch mal die Startwerte für einzelnen Variablen durchgeben.

    1. Geh Iteration für Iteration durch und schau ab wann der Fehler auftaucht. Wenn es viele Ergebnisse sind dann gebe zwei Dateien aus und dann siehst du ab welcher Iteration der Wert unterschiedlich ist.

    2. Poste mal die Compiler Flags.

    3. Wenn du irgendwelche Optimierungen im Release Modus nutzt, dann schalte sie Schritt für Schritt aus.

    4. Ich habe auch die VS2010 und diese hat einen sehr angenehmen Debug Modus.



  • darkfate schrieb:

    Tomahawk schrieb:

    Sobald ich die Compilereinstellungen für Release x64 ändere addiert der Compiler wieder korrekt?!

    Der Code den du gepostet hast ist so nicht ausführbar. Wieso debuggst du ihn nicht einfach? Du könntest auch mal die Startwerte für einzelnen Variablen durchgeben.

    1. Geh Iteration für Iteration durch und schau ab wann der Fehler auftaucht. Wenn es viele Ergebnisse sind dann gebe zwei Dateien aus und dann siehst du ab welcher Iteration der Wert unterschiedlich ist.

    2. Poste mal die Compiler Flags.

    3. Wenn du irgendwelche Optimierungen im Release Modus nutzt, dann schalte sie Schritt für Schritt aus.

    4. Ich habe auch die VS2010 und diese hat einen sehr angenehmen Debug Modus.

    Leider bin ich im Lesen von Assemblercode nicht so fit. Daher kann ich die "fehlerhafte" Release Engine nicht debuggen. Die Debugversion habe ich schon gründlich untersucht.

    Hier die Compilerflags:

    /nologo /W4 /WX- /O2 /Ob2 /Oi /Ot /Oy /GT /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /GF- /Gm- /MT /GS- /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope /GR- /Fp"x64\Release\Loop 2010.pch" /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gr /errorReport:queue /favor:INTEL64

    Sobald ich die Optimierungsflags zurücksetzte (zB O2) gibts keine Unregelmässigkeiten mehr.

    Gruss
    T.



  • Mit dem MS 2008 Compiler gibts keine Unregelmässigkeiten.

    Bisher ist es tatsächlich nur das 64-Bit Release Build des MS 2010 Compilers mit obigen Flags.

    Auch verschiedene Versionen des BoundsChecker konnten nach mehrtägigen Analysen keine Probleme feststellen.

    Gruss



  • Tomahawk schrieb:

    Leider bin ich im Lesen von Assemblercode nicht so fit.

    Wenn Assembler überhaupt nicht geht, dann hilft nur die gute alte Fileausgabe, oder cout, so dass du dir den Status aller Variablen in der Console oder irgend einer Textbox ausgeben lässt. Datei ist besser, weil du siehst welcher Thread wann zuerst schreibt oder priorisiert wird.

    Alternativ lässt sich der optimierte Code, der vor dem kompilieren erstellt wurde auch behalten ohne ihn nach dem optimieren zu löschen. Aber dieser ist nach getätigten Optimierungen manchmal fast genau so aufschlussreich wie Assemblercode

    Oder du gibst, falls es möglich ist, die Startwerte der Variablen.

    Hier die Compilerflags:

    Tomahawk schrieb:

    /nologo /W4 /WX- /O2 /Ob2 /Oi /Ot /Oy /GT /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /GF- /Gm- /MT /GS- /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope /GR- /Fp"x64\Release\Loop 2010.pch" /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gr /errorReport:queue /favor:INTEL64

    Hui, du hast alles angeschaltet was sich nach irgendwie Geschwindigkeit angehört hat. Du solltest hingehen und den Profiler nutzen. Manchmal haben die Einstellungen auch keinen Mehrwert und bringen nur aufgeblähten Code mit sich.

    Nebenbei: Man sollte nur den Rechenteil so intensiv optimieren. Besser: Mit schnelleren Algorithmen als mit agressiven Compiler Flags. GUI oder ähnliches nur mit Standard Release Einstellungen optimieren.

    Wahrscheinlich ist auch dass alle Release Versionen irgendwo ein Problem haben, nur zeigt es sich an einer Stelle, die du zum Glück beobachten kannst.

    Zuerst: Schalte mal nur /MP ab und versuche es noch einmal mit den selben Einstellungen. Wenn sich die beiden beißen, dann muss man die for Schleife ein wenig überdenken.

    Nächster Vorschlag. Du stellst überall die Release Optimierungs-Einstellungen auf Default.

    Wenn du SSE2 Nutzt, dann solltest du das Alignment auf 128Bit setzen:
    Lies dir bei Gelegenheit das mal durch: http://msdn.microsoft.com/en-us/library/aa290049(VS.71).aspx
    Compiler Flag /Zp16

    Flag /GT nur wenn du Fibers oder TLS nutzt.

    Tomahawk schrieb:

    Sobald ich die Optimierungsflags zurücksetzte (zB O2) gibts keine Unregelmässigkeiten mehr.

    Riecht nach einer Überoptimierung.



  • Bin ratlos und meine Kollegen bei den Softwarentwicklern haben auch keine Idee mehr. Vielleicht liegt es an den Kompilereinstellunge, aber darüber kann ich keine Aussage machen.

    Warum werde im x64 Release Modus 2 int Zahlen nicht addiert.

    Gibt es die Möglichkeit den Quellcode hier zu veröffentlichen (~1500 Zeilen) und mal Jemanden mit Ahnung von Assembler und Compiler Settings drüberschauen zu lassen?

    Vollkommen ratlos und erschöpft... 😞



  • Hier mal den Code:

    class sort_c {
    public:
      sort_c();
    
    private:
      move_info_c * last_move;
      move_info_c move_list[256];
    };
    
    sort_c::sort_c() {
      char string[256];
      int temp;
    
      last_move = generate_evasions(move_list);
    
      move_info_c * current = move_list+8;
    
      int move = current->move;
      int value = static_exchange_evaluation(move);
    
      temp = 0;
    
      if (value < 0) {
        current->value = value;
      }
      else if (move_is_capture(move)) {
        // hier wird nicht addiert
        temp = 50000 + piece_value_midgame(move_piece_captured(move)) - move_piece(move);
        current->value = temp;
      }
      else {
        current->value = 0;
      }
    
      printf_s("move............%s %d\n", move_to_string(move, string), move);
      printf_s("see value.......%d\n", value);
      printf_s("piece captured..%d\n", move_piece_captured(move));
      printf_s("piece value.....%d\n", piece_value_midgame(move_piece_captured(move)));
      printf_s("piece...........%d\n", move_piece(move));
      printf_s("value...........%d\n", current->value);
      printf_s("temp............%d\n", temp);
      printf_s("is enpassant....%d\n", move_is_enpassant(move));
      printf_s("\n");
      fflush(stdout);
    }
    

    Es werden in einer Stellung 9 Züge generiert. Danach untersuche ich den betreffenden Zug Nr 9, also move_list+8. Die print-Ausgaben stimmen zwar alle, aber temp und current->value ergeben nur 50000 statt 50198 (wie es sein sollte und von allen gtesteten Compilern gemacht wird).



  • Ich würde meine eMail Adresse hier angeben, wer möchte kann mich kurz anschreiben und ich sende den Code zu.

    Gruss
    T.



  • Die Ausgabe des Programmes:

    move............e4f3 34581
    see value.......0
    piece captured..0
    piece value.....198
    piece...........0
    value...........50000
    temp............50000
    is enpassant....1
    

    Hier erkennt man doch ganz klar, dass piece_value_midgame(move_piece_captured(move)) 198 ist und move_piece(move) 0. Also ist die Summe doch temp = 50000 + 198 - 0;

    Was sehe ich und meine Kollegen nicht?



  • Tomahawk schrieb:

    Sobald ich die Optimierungsflags zurücksetzte (zB O2) gibts keine Unregelmässigkeiten mehr.

    Hier ist auch die Lösung des Problems. Die Compilereinstellungen passen nicht zu deinem Code. Lade eine pw geschützte Zip Datei bei Rapidshare hoch oder sowas.



  • Super, danke!

    Hier der Download Link:

    http://rapidshare.com/files/403808358/Problem.rar.html

    Passwort ist unnötig, da nichts besonderes drin steht.

    Bitte unbedingt unter MS Visual Studio 2010 Professional x64 Release testen. Und mit den Compilereinstellungen (sind beim Download enthalten).

    Bin gespannt auf die Interpretation des Problems, kann es mir mit meinen Kenntnissen nicht erklären.

    Gruss
    T.





  • Man kann ja dem Compiler beim optimieren ein wenig Sand ins Getriebe streuen, dann gehts. Eine sinnlose bool Zuweisung kann da helfen. 🙂 Fürs erste natürlich. Meine Zeit ist im Moment begrenzt.

    #include <stdio.h>
    #include "sort.h"
    #include "value.h"
    #include "board.h"
    
    bool dummy = false;
    
    sort_c::sort_c() {
    	char string[256];
    	int temp;
    
    	last_move = generate_evasions(move_list);
    
    	move_info_c * current = move_list+8;
    
    	int move = current->move;
    	int value = static_exchange_evaluation(move);
    
    	temp = false;
    
    	if (value < 0) current->value = value;
    	else if (move_is_capture(move)){
    		dummy=0;
    		current->value = 50000 + piece_value_midgame(move_piece_captured(move)) - move_piece(move);
    	}
    	else current->value = 0;
    
    	printf_s("move............%s %d\n", move_to_string(move, string), move);
    	printf_s("see value.......%d\n", value);
    	printf_s("piece captured..%d\n", move_piece_captured(move));
    	printf_s("piece value.....%d\n", piece_value_midgame(move_piece_captured(move)));
    	printf_s("piece...........%d\n", move_piece(move));
    	printf_s("value...........%d\n", current->value);
    	printf_s("temp............%d\n", temp);
    	printf_s("is enpassant....%d\n", move_is_enpassant(move));
    	printf_s("\n");
    	fflush(stdout);
    }
    
    // X64 Release
    move............e4f3 34581
    see value.......0
    piece captured..0
    piece value.....198
    piece...........0
    value...........50198
    temp............0
    is enpassant....1
    


  • darkfate schrieb:

    Tomahawk schrieb:

    Sobald ich die Optimierungsflags zurücksetzte (zB O2) gibts keine Unregelmässigkeiten mehr.

    Hier ist auch die Lösung des Problems. Die Compilereinstellungen passen nicht zu deinem Code.

    Was soll das denn bedeuten? Eine Compileroptimierung darf niemals das beobachtbare Verhalten eines (korrekten) Programms ändern.

    Ich vermute mal, dass irgendwo im Programm UB auftritt und dieses erst durch die Optimierungen sichtbar wird.



  • life schrieb:

    Was soll das denn bedeuten? Eine Compileroptimierung darf niemals das beobachtbare Verhalten eines (korrekten) Programms ändern.

    Stimmt nicht. Wenn ich meinen Linux Kernel kompiliere, dann sind manche Optimierungseinstellungen in der Optimierungsstufe "-O3" sogar tabu.



  • Der Linux Kernel ist auch nicht standard-konform.



  • life schrieb:

    Der Linux Kernel ist auch nicht standard-konform.

    Man kann nicht alle Probleme Standardkonform lösen.



  • life schrieb:

    darkfate schrieb:

    Tomahawk schrieb:

    Sobald ich die Optimierungsflags zurücksetzte (zB O2) gibts keine Unregelmässigkeiten mehr.

    Hier ist auch die Lösung des Problems. Die Compilereinstellungen passen nicht zu deinem Code.

    Was soll das denn bedeuten? Eine Compileroptimierung darf niemals das beobachtbare Verhalten eines (korrekten) Programms ändern.

    Ich vermute mal, dass irgendwo im Programm UB auftritt und dieses erst durch die Optimierungen sichtbar wird.

    UB ?

    Diese Programmteile sind genau durchgecheckt. Ausschliessen möchte ich einen Fehler natürlich nicht. Aber in den wenigen Code-Zeilen kann ich nichts entdecken.

    Gruss



  • life schrieb:

    Eine Compileroptimierung darf niemals das beobachtbare Verhalten eines (korrekten) Programms ändern.

    Es gibt zwei Situationen, in denen es der C++-Standard sogar ausdrücklich erlaubt: Bei Rückgabewerten von Funktionen und bei temporären Objekten darf eine unnötige Kopie vom Compiler wegoptimiert werden.

    Tomahawk schrieb:

    UB ?

    Undefined behaviour (undefiniertes Verhalten)



  • life schrieb:

    Eine Compileroptimierung darf niemals das beobachtbare Verhalten eines (korrekten) Programms ändern.

    Fast alle IDE's compiler verzichten in den Release Versionen auf auf frame pointer, agressives inlining und -O3 egal ob unter Windows oder Linux. Warum wohl?

    Wenn es nichts am Programmfluss ändern würde, dann bräuchte man diese Optionen in Release nicht weil sie immer default on wären.


Anmelden zum Antworten