Cpu-cycles



  • hallo

    Ich möchte gerne bei meinem Programm -Algorithm die Cpu cycles messen.
    Da ich aber leider keine libs. gefunden habe und ich auch nicht gerade weis wie man das in assembler macht, wäre ich dankbar um Hilfe.

    int main()
    {
    
    start=cpucycles();
    
    ....
    ...
    ...
    
    end=cpucycles();
    
    printf("AUSGABE",   );
    
    }
    

    irgendwie so stelle ich mir das vor ..
    Danke für eure Hilfe.



  • Mit ANSI-C geht das nicht.

    Wenn Du Dein Programm unter Windows laufen möchtest:
    Dann sollst Du Dir QueryPerformanceFrequency() http://msdn.microsoft.com/en-us/library/ms644904.aspx und
    QueryPerformanceCounter() http://msdn.microsoft.com/en-us/library/ms644905.aspx näher ansehen.

    "How to use the QueryPerformanceCounter function to time code in Visual C++" http://support.microsoft.com/kb/815668/en-us/

    Falls es Dich interessiert, kann ich ja kurzen Quellcode posten.

    Martin

    [Edit: Links hinzugefügt.]



  • für x86 ist vielleicht auch das interessant: http://www.ccsl.carleton.ca/~jamuir/rdtscpm1.pdf
    🙂



  • hi

    Für ein wenig quelltext wäre ich dankbar. 🙂

    Wen mir jemand zeigen könnte wie ich das mit ein paar Zeilen inline assembler machen kann...wäre ich froh,den ich möchte es ja auch portabel haben..

    Lb



  • lowbyte_ schrieb:

    Für ein wenig quelltext wäre ich dankbar.

    Schau mal hier: http://www.c-plusplus.net/forum/viewtopic-var-t-is-237896-and-postdays-is-0-and-postorder-is-asc-and-start-is-0.html
    Vielleicht kannst Du da was wiederverwenden...



  • für ein paar beispiele wäre ich dankbar..
    Da ich das nicht so ganz verstehe.

    QueryyperformanceCounter(&start) ;

    ...
    ...

    QueryperformanceCounter(&end);

    Jetz so wie ich das verstanden habe..

    (End-start)*QueryPerformanceFrequency(&freq)

    Doch das gibt werte jenseits meiner vorstellung..und kann nicht sein.was mache ich falsch?
    Wen ich end - start rechne..würde es vieleicht hinkommen..doch ichweis es auch nicht..wäre forh um hilfe.

    Lb



  • lb schrieb:

    (End-start)*QueryPerformanceFrequency(&freq)

    Falsch!

    In einem Link, den weiter oben gepostet habe, ist im Quelltext zu lesen:

    Console::WriteLine("100 Increment time: {0} seconds.",((ctr2 - ctr1) * 1.0 / freq).ToString());
    

    Also Division nicht Multiplikation!

    Bitte beachte: start und end müssen 64bit breit sein!

    Martin



  • vielen dank martin

    Doch meine probleme liegen da .

    Qpc(&s);
    For(i=0;i<10000;i++) {
    Var += 1;
    }

    Qpc(&e);
    Printf("%Li",(end-start)*1,0 / qpf(&f));

    Gibt immer 0.

    Start-end ergiebt ca. 30 bei 10000 schleifen durchläufen. Und qpf auf meinem p4 35000 oder so..(sorry bin nicht am rechner.)
    Das ergiebt immer 0. Das ist mein problem.
    Das mit der division hatest du schon recht war ein tipfehler von mir sorry.
    Und die vars sind auch 64bit breit __int64 verwende ich.

    Lb



  • hallo

    Es funktioniert jetz ...

    doch ein problem habe ich noch... Kan mir jemand erklären warum bei meinem des algorythmus über alle runden nur 14 cpu cycles gemmesen werden ??

    Das kann einfach nicht stimmen.. Kann mir jemand helfen?

    Lb



  • hi

    Möchte doch einfach nur von einem bestimmten teil des code die cpu cycles messen..ist das den so schwierig??
    Scheinbar doch... Wäre wirklich froh wen mir jemand das genauer erklären könnte..

    Thx lb



  • Für den GCC kannst du die Funktion verwenden:

    static inline uint64_t rdtsc(void)
    {
      uint32_t lo, hi;
      __asm__ __volatile__
      (
        "xorl %%eax, %%eax\n"
        "cpuid\n"
        "rdtsc\n"
        : "=a" (lo), "=d" (hi)
        :
        : "%ebx", "%ecx");
      return (uint64_t)hi << 32 | lo;
    }
    

    Für den VC dürfte es nicht so schwer sein, etwas entsprechendes über Google zu finden. QueryPerformanceCounter kannst du für kleine Codeabschnitte vergessen, da die Funktion selbst viele tausend Zyklen in Anspruch nimmt.
    Außerdem solltest du bedenken, dass dein Compiler das:
    for(i=0;i<10000;i++)Var += 1;
    ohne weiteres in Var += 10000; optimieren darf.



  • hi

    Danke. Danke... Genau das wollte ich wissen..

    Lb



  • lb schrieb:

    Qpc(&s);
    For(i=0;i<10000;i++) {
    Var += 1;
    }

    Qpc(&e);
    Printf("%Li",(end-start)*1,0 / qpf(&f));

    Du verwendest hier anscheinend zwei verschiedene Sätze von Variablen?
    Einen Satz mit Variablen "s" und "e" sowie
    den anderen Satz mit Variablen "start" und "end"

    Das kann so nicht funktionieren.
    Am besten poste mal Deinen kompletten Code hier.
    (Bitte dabei C++ Tags verwenden, sonst leidet die Lesbarkeit hier arg darunter...)

    Martin



  • hi
    Für windof finde ich einfach nichts vergleichbares in asm..
    Könntest du mir vieleicht noch einmal unter die armen greifen,da du den anschein machst was von der sache zu verstehen..?!
    Noch eine frage zur linux asm funktion..
    So wie ich das verstehe muss ich die funktion an einer stelle auffrufen, und dan nocheinmal..einfach bis zu dem punkt den ich messen möchte. Und dann subtrahieren..ist das richtig?
    Danach sollte ich die cpu cycles von dem codeabschnitt haben!? Richtig?

    Danke jetz schon
    Lb



  • lb schrieb:

    Für windof finde ich einfach nichts vergleichbares in asm..

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

    lb schrieb:

    So wie ich das verstehe muss ich die funktion an einer stelle auffrufen, und dan nocheinmal..einfach bis zu dem punkt den ich messen möchte. Und dann subtrahieren..ist das richtig?
    Danach sollte ich die cpu cycles von dem codeabschnitt haben!? Richtig?

    fast richtig. leider hat windoof multitasking und das kommt dir dabei in die quere.
    🙂



  • Mal schnell zusammenkopiert (ohne Gewähr auf Syntaxfehler o.ä.):

    #include <windows.h>
    
    BOOL b_stoppuhr_frequenz_ermittelt;
    LARGE_INTEGER i64_stoppuhr_start;
    LARGE_INTEGER i64_stoppuhr_ende;
    LARGE_INTEGER i64_stoppuhr_frequenz;
    
    void Stoppuhr_Start( void )
    {
    if ( QueryPerformanceFrequency( &i64_stoppuhr_frequenz ) == 0 )
                                                     //QueryPerformanceFrequency() can fail, and it reports
                                                     //error 998 (ERROR_NOACCESS - Invalid access to memory location).
    {
        b_stoppuhr_frequenz_ermittelt = 0;           //QueryPerformanceFrequency() ist fehlgeschlagen.
    }
    else
    {
      b_stoppuhr_frequenz_ermittelt = 1;
      if ( QueryPerformanceCounter( &i64_stoppuhr_start ) == 0 )
      {
        b_stoppuhr_frequenz_ermittelt = 0;           //QueryPerformanceCounter() ist fehlgeschlagen ->
                                                     //Bit zurücksetzen, um die Messung ungültig zu machen.
      }
    }
    } //Ende von Stoppuhr_Start().
    
    DWORD Stoppuhr_Ende_Zeit_ms( void )
    {
    if ( b_stoppuhr_frequenz_ermittelt == 0 )
    {
      return( 0 );                                   //Messung ist ungültig.
    }
    if ( QueryPerformanceCounter( &i64_stoppuhr_ende ) == 0 )
    {
      b_stoppuhr_frequenz_ermittelt = 0;             //QueryPerformanceCounter() ist fehlgeschlagen ->
                                                     //Bit zurücksetzen, um die Messung ungültig zu machen.
      return( 0 );                                   //Messung ist ungültig.
    }
    
    return( (DWORD)( (float)( i64_stoppuhr_ende.QuadPart - i64_stoppuhr_start.QuadPart ) * 1000.0 / (float)i64_stoppuhr_frequenz.QuadPart ) );
                                                     //Differenzbildung funktioniert auch bei einem Überlauf des
                                                     //PerformanceCounters,d.h. wenn Wert i64_debug_stoppuhr_start
                                                     //ist größer als Wert i64_debug_stoppuhr_ende.
    } //Ende von Stoppuhr_Ende_Zeit_ms().
    

    Als Beginn der Messung rufst Du zuerst Stoppuhr_Start() auf.
    Wenn Du die verstrichene Zeit nun messen willst, rufst dann Stoppuhr_Ende_Zeit_ms() auf. Diese Funktion liefert Dir als Rückgabewert die verstrichene Zeit in ms (32 bit Bereich)
    Werte unter 1ms sind zu ungenau da Windows unkalkulierbare Threadwechsel usw. durchführt. Dazu kommen Zeitverluste durch die verwendeten Funktionen selbst.
    In diesem Fall einfach die zu untersuchende Aktion z.B. 1000mal wiederholen.

    HTH,
    Martin



  • hallo

    Glaube mir alles stimmt was ich geschrieben habe stimmt.Das mit der qpc funtion.

    (End-strart) * 1,0 / freq

    Doch jetz shreibst du * 1000,0 das verstehe ich nicht.
    Das andere ist...wen ich mit meinen zeilen messe also (end - start) * 1,0 / freq dan messe ich beim DES Verschlüsselungs algorithm über alle 16 runden nur 15 cpu cycles. Das kann nicht stimmen.Das ist mein problem.

    Lb



  • QueryPerformanceFrequency() liefert Dir die Frequenz, also Einheit 1/s.

    Nach Deiner Rechnung wären das 15 Sekunden!
    Meine Routine liefert dagegen den Wert in ms (Millisekunden).
    1000ms ergeben eben die 1s, deshalb mein Faktor 1000.0

    Diese Funktionen liefern Dir NICHT die Anzahl der CPU-Zyklen!
    Das würde auf Windows auch nicht viel bringen, da Windows selbst entscheidet, wann das Programm (oder Prozess, genauer gesagt die Threads) unterbrochen wird, um die Rechenleistung dem nächsten Programm weiterzugeben.

    Du hast richtig gelesen: Windows unterbricht bei Bedarf jederzeit mitten in der Ausführung den Prozessor, stellt die CPU einem anderen Prozess zur verfügung und kehrt irgendwann wieder zur unterbrochenen Stelle Deines Programms zurück
    -> Daher sind Messungen zur Anzahl der CPU-Zyklen unzuverlässig bzw. unbrauchbar!

    Es gibt spezielle Funktionen, mit denen Windows Dir mitteilt, wie lange das Programm tatsächlich gebraucht hat, d.h. die Zeiten bei CPU-Wechsel auf andere Prozesse nicht mitgerechnet.

    Es ist vor allem die Frage, was Du Messen willst.
    Willst Du nur sehr kurze Sequenzen messen (sagen wir mal, bis ca. 10.000 CPU Zyklen) dann macht das CPU-Zyklen messen durchaus Sinn. Wobei Du hier hin und wieder durch Windows-Taskwechsel eklatante Ausreißer messen wirst. Diese Ausreißer kannst Du aber durch Zeitvergleiche erkennen.

    Martin



  • Hi

    Danke, aber das wusste ich zum teil schon... mir war einfach die multi.. nicht ganz klar..kund mir war schon klar das die funktion in ms misst.Aber ich brauche ja eigentlich die Cpu cycles die der Cpu braucht um den code von mir zu verarbeiten.
    also zum bsp. a=b^c; wäre ein cycle. in etwa so. du weisst schon wie ich meine.
    Jetz müsste man eine funktion haben die nur von meinem thread/proc die cpu cycles misst.
    könntest du mir den so ein beispiel zeigen?
    Genau das würde ich brauchen!


Log in to reply