Benchmark float/int



  • Hallo zusammen

    Ich habe mir spasseshalber ein Progrämmchen in C++ geschrieben, um die floating-point und Integer Rechenleistung meines betagten 550MHz Athlons zu messen. Für die Messung musste der Computer, für verschiedene Datentypen, die vier Grundrechenoperationen in einem Loop ausführen. Für das folgende Ergebnis wurden die Loops 100Mio mal durchlaufen:

    char performance = 727.273 MIOPS
    short performance = 1025.64 MIOPS
    int performance = 727.273 MIOPS
    long performance = 1052.63 MIOPS
    float performance = 1025.64 MFLOPS
    double performance = 1052.63 MFLOPS
    long double performance = 1025.64 MFLOPS

    Interessant finde ich, dass die Rechnungen mit char und int besonders langsam sind, jedoch die Berechnungen mit double sowie long double nicht langsamer als die mit float. Es würden mich eure Meinungen/Ideen dazu interessieren. 🙂

    #include <cstdlib>
    #include <ctime>
    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    // stopwatch class
    class Stopwatch
    {
        public:
    
            void Start(void);
    
            void Stop(void);
    
            double Show(void);
    
        private:
    
            clock_t m_start_time;
            clock_t m_stop_time;
    
        };
    
    void Stopwatch::Start(void)
    {
        m_start_time = clock();
        }
    
    void Stopwatch::Stop(void)
    {
        m_stop_time = clock();
        }
    
    double Stopwatch::Show(void)
    {
        return (double)(m_stop_time - m_start_time) / CLOCKS_PER_SEC;
        }
    
    // benchmark template
    template <class T>
    double Benchmark(unsigned long loops)
    {
        Stopwatch sw;
    
        sw.Start();
    
        T n;
    
        for(unsigned long i = 0; i < loops; ++i)
        {
            n = 2;
    
            n *= 4;
            n += 7;
            n /= 3;
            n -= 1;
    
            }
    
        sw.Stop();
    
        // MFLOPS
        return ((loops * 4) / sw.Show()) / 1000000; 
    
        }
    
    // main program
    int main(int argc, char *argv[])
    {
    
        fstream file("./benchmark.txt", ios::out);
    
        file << "char performance        = " << Benchmark<char>(100000000)          << " MIOPS" << endl;
        file << "short performance       = " << Benchmark<short>(100000000)         << " MIOPS" << endl;
        file << "int performance         = " << Benchmark<int>(100000000)           << " MIOPS" << endl;
        file << "long performance        = " << Benchmark<long>(100000000)          << " MIOPS" << endl;
        file << "float performance       = " << Benchmark<float>(100000000)         << " MFLOPS" << endl;
        file << "double performance      = " << Benchmark<double>(100000000)        << " MFLOPS" << endl;
        file << "long double performance = " << Benchmark<long double>(100000000)   << " MFLOPS" << endl;
    
        file.close();
    
        system("PAUSE");
        return EXIT_SUCCESS;
    }
    


  • Stöffel schrieb:

    Interessant finde ich, dass die Rechnungen mit char und int besonders langsam sind...

    in der tat sehr merkwürdig.
    in der 'benchmark' funktion wird ja mit konstanten gerechnet, änder' das mal in irgendwas variables, damit dein compiler das nicht optimieren kann...



  • olaf@pc:~/test$ g++ test.cpp
    olaf@pc:~/test$ ./a.out
    char performance = 177.778 MIOPS
    short performance = 177.778 MIOPS
    int performance = 198.02 MIOPS
    long performance = 190.476 MIOPS
    float performance = 216.216 MFLOPS
    double performance = 209.424 MFLOPS
    long double performance = 45.4545 MFLOPS
    olaf@pc:~/test$ g++ -O3 test.cpp
    olaf@pc:~/test$ ./a.out
    char performance = inf MIOPS
    short performance = inf MIOPS
    int performance = inf MIOPS
    long performance = inf MIOPS
    float performance = inf MFLOPS
    double performance = inf MFLOPS
    long double performance = inf MFLOPS

    du wirst mit deinem programm keine brauchbaren ergebnisse erzielen, es kommt halt ganz drauf an was dein compiler alles so optimiert.



  • Du solltest mindestens 2 Modifikationen machen:

    1. Ermittle den Wert von "loops" zur Laufzeit - lies den aus einem Textfile oder sowas. So dass der Compiler den Wert zur Compilezeit eben nicht wissen kann. Das sorgt schonmal dafür dass das Ergebnis der Schleife nicht zur Compilezeit ermittelt werden kenn.

    2. Übergib das Ergebnis einer Funktion die der Compiler nicht kennt bzw. nicht wegoptimieren kann. Dazu eignet sich unter Windows z.B. WriteDebugString oder du kannst den Wert auch einfach mit ausgeben lassen (in das Textfile/den cout Stream/...). Das sorgt dafür dass der Compiler nicht die ganze Berechnung aus der Schleife rausnehmen kann, weil das Ergebnis ja verwendet wird.

    Das Programm so wie es ist würde dir ein wirklich guter Compiler "zu nichts" optimieren 😉
    EDIT: genau das hat der gcc mit -O3 anscheinend gemacht.



  • Hmja, ein Ergebnis von Unendlich spricht wohl schon dafür, dass der ganze Loop wegoptimiert wurde. Ich hatte gehofft dass der Compiler nicht clever genug ist, um zu sehen dass die Berechnungen eigentlich überflüssig sind. Ich werde mal einen Versuch machen, wo die Variable einen zufälligen Anfangswert hat und nicht in jedem Loopdurchlauf neu initialisiert wird und das Resultat dann auch zurück gegeben wird. Mal sehen. Danke für eure Antworten. 🕶



  • schaltet doch einfach die Optimierung aus



  • Das macht den Vergleich aber nicht unbedingt deutlich aussagekräftiger. Tests sollten unter möglichst realen Bedingungen laufen. Keine Optimierungen ist imho nicht sehr real 😉



  • TactX schrieb:

    Das macht den Vergleich aber nicht unbedingt deutlich aussagekräftiger. Tests sollten unter möglichst realen Bedingungen laufen. Keine Optimierungen ist imho nicht sehr real 😉

    naja, aber in dem fall will er ja nicht wissen wie toll und schnell sein programm läuft, sondern wie viel zeit die berechnungen verbraten...



  • Aber eben die Berechnungen werden ja auch durch die Optimierung beeinflusst.



  • TactX schrieb:

    Aber eben die Berechnungen werden ja auch durch die Optimierung beeinflusst.

    aber eben deshalb muss man auch dafür sorgen, dass nix optimiert werden kann...



  • Also testen wir Berechnungen unter vollkommen unrealistischen Bedingungen um was rauszufinden? Die Vorteile der CPUs die ja teilweise nur in "realem" Code zum tragen kommen fliessen hier ja nicht ein. Ich sehe den Sinn einfach nicht 😕



  • TactX schrieb:

    Die Vorteile der CPUs die ja teilweise nur in "realem" Code zum tragen kommen fliessen hier ja nicht ein.

    guck doch mal seine 'benchmark' funktion.
    ein aggressiv optimierender compiler compiliert die zu *nichts*
    es gibt da zwar 'realen' sourcecode, aber den kann er auch gleich in /* */ einpacken 😉



  • net schrieb:

    TactX schrieb:

    Die Vorteile der CPUs die ja teilweise nur in "realem" Code zum tragen kommen fliessen hier ja nicht ein.

    guck doch mal seine 'benchmark' funktion.
    ein aggressiv optimierender compiler compiliert die zu *nichts*

    Klar. Ich meine ja nur, dass man sowas eh nur mit einem etwas besseren/realeren Test einigermassen aussagekräftig testen kann. Der Test wird ja nicht wirklich sinnvoller nur weil man das komplette Wegoptimieren unterbindet. Wenn eh nur die einzelnen Laufzeiten der ALU/FPU-Befehle interessieren, kann eh ins Manual schauen. Alle anderen Effekte (Pipelining, Caching, SIMD, whatever) scheinen euch ja nicht zu kehren.


Anmelden zum Antworten