Lösung : Prozessorspeed in MHZ



  • Ich hab mal versucht den Code nach C, POSIX.1 und gcc-asm-syntax zu portieren, aber ich erhalte immer die unterschiedlichsten Werte 😞

    #include <stdio.h>
    #include <unistd.h>
    
    unsigned long getmhz(void)
    {
      unsigned long value1=0,value2=0,value3=0,value4=0;
      double mhz;
      __asm__ __volatile__("rdtsc":"=a"(value1),"=d"(value2)::);
      sleep(1); //POSIX 1 function
      __asm__ __volatile__("rdtsc":"=a"(value3),"=d"(value3)::);
      value1=value3-value1;
      value2=value4-value2;
      mhz=(value1+(value2*(2^32)))/1000/1000;
      return (unsigned long)mhz;
    }
    
    int main()
    {
      printf("%d\n",getmhz());
      return 0;
    }
    

    seht ihr einen Fehler?

    [ Dieser Beitrag wurde am 18.09.2002 um 20:31 Uhr von kingruedi editiert. ]



  • Ich hab mir mal erlaubt das ganze in MASM-ASM zu übersetzen:

    .586
    .model flat, stdcall
    option casemap:none
    include C:\masm32\include\windows.inc
    include C:\masm32\include\kernel32.inc
    include C:\masm32\include\user32.inc
    includelib kernel32.lib
    includelib user32.lib
    
    .data
    value1 dd 0
    value2 dd 0
    value3 dd 0
    value4 dd 0
    MsgCaption db "CPU",0
    MsgBoxText db "    "
    MHZ db " MHz",0
    
    .code
    
    INTTOSTR MACRO INTEGER, STRING
        mov eax, INTEGER
        xor ecx,ecx
        mov ebx,000Ah
        @@DecConvert:
        xor edx,edx
        div ebx 
        add edx,0030h
        push edx
        inc ecx
        or eax,eax
        jnz short @@DecConvert
        mov edi,offset STRING
        @@SortDec:
        pop eax
        stosb 
        loop @@SortDec
    ENDM
    
    start:
        rdtsc   
        mov value1, eax
        mov value2, edx
        invoke Sleep, 1000
        rdtsc   
        mov value3, eax
        mov value4, edx
    
        mov eax,dword ptr [value3]
        sub eax,dword ptr [value1]
        mov dword ptr [value1],eax
        mov edx,dword ptr [value4]
        sub edx,dword ptr [value2]
        mov dword ptr [value2],edx
        imul eax,dword ptr [value2],34
        add eax,dword ptr [value1]
        mov ecx,1000
        cdq
        idiv ecx
        mov ecx,1000
        cdq
        idiv ecx
    
        INTTOSTR eax, MsgBoxText
    
        invoke MessageBox, NULL, addr MsgBoxText, addr MsgCaption, MB_OK
        invoke ExitProcess, NULL
    end start
    


  • hab noch ne kleine erweiterung dazugestellt:
    es wird jetzt auch die speicherauslastung angezeigt (zumindest bei mir 😉 )

    #include <iostream>
    #include <windows.h>
    #include <conio.h>
    using namespace std;
    
    #define DIV 1024
    #define WIDTH 7
    
    int GetMHz(void);
    void GetMemoryStatus(void);
    
    char *divisor = "K";
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
    
      while(!kbhit())
      {
        gotoxy(1,1);
        printf("CPU-Speed: %i MHz\n\n", GetMHz());
        GetMemoryStatus();
      }
    
      return 0;
    }
    //---------------------------------------------------------------------------
    
    int GetMHz(void)
    {
      unsigned long v1, v2, v3, v4;
      double MHz;
    
      _asm{
            rdtsc
            mov [v1], eax
            mov [v2], edx
          }
    
      Sleep(500);
    
        _asm{
            rdtsc
            mov [v3], eax
            mov [v4], edx
          }
    
      v1=v3-v1;
      v2=v4-v2;
      MHz=(v1+(v2*(2^32)))/1000/500;
    
      return (int)MHz;
    }
    
    void GetMemoryStatus(void)
    {
      MEMORYSTATUS stat;
    
      GlobalMemoryStatus (&stat);
    
      printf ("%7ld percent of memory in use.\n",
              stat.dwMemoryLoad);
    
      printf ("%*ld %sbytes total physical memory.\n",
              WIDTH, stat.dwTotalPhys/DIV, divisor);
    
      printf ("%*ld %sbytes free physical memory.\n",
              WIDTH, stat.dwAvailPhys/DIV, divisor);
    
      printf ("%*ld %sbytes total paging file.\n",
              WIDTH, stat.dwTotalPageFile/DIV, divisor);
    
      printf ("%*ld %sbytes free paging file.\n",
              WIDTH, stat.dwAvailPageFile/DIV, divisor);
    
      printf ("%*ld %sbytes total virtual memory.\n",
              WIDTH, stat.dwTotalVirtual/DIV, divisor);
    
      printf ("%*ld %sbytes free virtual memory.\n",
              WIDTH, stat.dwAvailVirtual/DIV, divisor);
    }
    


  • hm, das erste funktioniert bei mir gut, aber mit dem neuen bekomme ich 1 error 1 warning

    erstmal weiß der mit pragma nicht viel anzufangen,
    und das andere sag ich, wenn ichs wieder weiß 😉
    1536mhz



  • ich hab versucht den code
    von kingruedi auf linux mit dem gcc zum laufen
    zu kriegen.
    allerdings wird mir der code nicht uebersetzt.

    __asm__ __volatile__("rdtsc":"=a"(value1),"=d"(value2)::); // <-- parse error
    sleep(1); //POSIX 1 function
    __asm__ __volatile__("rdtsc":"=a"(value3),"=d"(value3)::); // <-- parse error

    ich krieg einen parse error vor dem ::.
    was mach ich falsch?



  • hast du vielleicht den Parameter aktiviert, dass der GCC keine eigenen Erweiterungen akzeptiert?

    Welche Version hast du?



  • ich hab den gcc 2.95.4.
    und uebersetze das ganze mit:
    gcc mhz.c
    (den quelltext hab ich von hier oben rauskopiert)

    #include <stdio.h>
    #include <unistd.h>
    
    unsigned long getmhz(void)
    {
      unsigned long value1=0,value2=0,value3=0,value4=0;
      double mhz;
      __asm__ __volatile__("rdtsc":"=a"(value1),"=d"(value2)::); //<- 41: fehler
      sleep(1); //POSIX 1 function 
      __asm__ __volatile__("rdtsc":"=a"(value3),"=d"(value3)::); //<- 43: fehler
      value1=value3-value1;
      value2=value4-value2;
      mhz=(value1+(value2*(2^32)))/1000/1000;
      return (unsigned long)mhz;
    }
    
    int main()
    {
      printf("%d\n",getmhz());
      return 0;
    }
    

    (da hab ich noch n paar komentare drin deswegen zeile 41)
    die genaue fehlrmeldung:
    mhz.c: In function getmhz': mhz.c:41: parse error before)'
    mhz.c:43: parse error before `)'

    [ Dieser Beitrag wurde am 23.09.2002 um 20:47 Uhr von entelechie editiert. ]



  • Bitte kläre mal einen unwissenden über deinen Code Auf. Erstmal Danke für den genialen Ansatz, aber wenn ich die Sleep - Zeit verändern will, so geht das nicht. Also habe ich einmal mit der Berechnung der MHZ - Zahl ein bischen rumgespielt.

    du rechnest:

    double MHZ = (value1+(value2*(2^32)))/1000/1000;

    value2*(2^32) soll nehme ich an das shiften der höherwertigen Bits darstellen, da ja in value2 die Diffrenz der beiden höherwetigen DWORD - Variablen ist. 2^32 entspricht doch aber nicht 2 hoch 32 sondern dem exklusiven oder Operator oder ( zumindest bei mir beim VC )? Demzufolge hat aus irgendwelchen Gründen bei mir das ganze nur hingehauen, bei genau Sleep(1000). Ich hab die Routine jetzt mal ein bisschen umgeändert, um die Messzeit verlängern zu können, damit die 5ms - Ungenauigkeit des Sleep nicht so sehr ins gewicht fällt.

    Wie folgt:

    DWORD GetMHZ()
    {
        DWORD iDurationMeasure = 12000;
        DWORD value1    = 0;
        DWORD value2    = 0;
        DWORD value3    = 0;
        DWORD value4    = 0;
        __asm
            {
            rdtsc
            mov value1, eax //Low order Bits
            mov value2, edx //High oreder Bits
            }
        Sleep(iDurationMeasure);
        __asm
            {
            rdtsc
            mov value3, eax
            mov value4, edx
            }
        value1          = value3 - value1;//Low order Bytes
        value2          = value4 - value2;//High Order Bytes
        ULONGLONG dwHigOrderBytes = ULONGLONG((ULONGLONG)value2 << 32);//shift der höherwetigen Bits
        ULONGLONG ulTicks = dwHigOrderBytes + value1;//berechnen der Gesamtticks
        DWORD MHZ      = (ulTicks / ( DWORD )( iDurationMeasure * 1000 )  );//Umrechnung in Mhz
        return (DWORD)MHZ;    
    }
    

    Bei Zwölf Sekunden Messzeit habe ich jetzt noch Streuungen von maximal 1Mhz. Vielleicht liege ich ja auch falsch. Bitte klärt mich auf.

    Danke



  • #include <iostream>
    #include <windows.h>
    #include <conio.h>
    using namespace std;
    
    DWORD GetMHZ()
        {
        DWORD value1    = 0;
        DWORD value2    = 0;
        DWORD value3    = 0;
        DWORD value4    = 0;
        __asm
            {
            rdtsc
            mov value1, eax
            mov value2, edx
            }
        ::Sleep(1000); // HIER GEHÖRT EIN :: hin!! ::Sleep(...);
        __asm
            {
            rdtsc
            mov value3, eax
            mov value4, edx
            }
        value1          = value3 - value1; //meckert er bei mir das value1 2 3 4 nicht deklariert seien in diesem namensbereich!
        value2          = value4 - value2;
        double MHZ      = (value1+(value2*(2^32)))/1000/1000;
        return (DWORD)MHZ;
        }
    
    int main()
    {
        cout << (int)GetMHZ << " MHZ"<<endl;
        getch();
        return 0;
    }
    


  • Original erstellt von Lars Skiba:
    **```cpp
    ::Sleep(1000); // HIER GEHÖRT EIN :: hin!! ::Sleep(...);

    Nur bei einem C++-Programm und davon war hier nie die Rede 😃



  • @Lars
    nur wenn durch iostream auch eine Sleep Funktion definiert wird 🙄

    @TheBigW
    in C(++) ist ^ der exklusiv oder Operator, dass liegt nicht am VC++ (auch wenn der viel anders macht). pow (aus der math.h bzw. cmath) benutzt man zum potenzieren. (Warum es keinen ** Operator, wie in FORTRAN gibt, versteh ich auch nicht ganz :))

    @entelchien
    Versuchs mal so

    gcc -O3 -Wall -W -o cpu cpu.c



  • @kingruedi
    ok ich habs zum laufen gebracht. erhalte aber auch
    unterschiedliche werte... und viel zu hoch...

    hast du das problem mitlerweile geloest?



  • nö, ich hab mich nicht dran gesetzt. Weiss nicht genau woran es liegt.



  • Könnte man mit dem Code auch messen, wie lange die CPU für einen Befehl braucht, z.b. für ein xor ax,ax oder so?
    Ich hab´s mal versucht und das Sleep dagegen ersetzt, aber hab immer nur 11 rausgekriegt, egal was ich statt xor eingesetzt habe, auch bei 30 xor kommt noch 11 raus.

    #include <iostream>
    #include <windows.h>
    #include <conio.h>
    using namespace std;
    
    DWORD GetMHZ()
        {
        DWORD value1    = 0;
        DWORD value2    = 0;
        DWORD value3    = 0;
        DWORD value4    = 0;
        __asm
            {
            rdtsc
            mov value1, eax
            mov value2, edx
            }
        __asm
            {
               xor ax,ax
               xor ax,ax 
               xor ax,ax
               xor ax,ax
            }
        __asm
            {
            rdtsc
            mov value3, eax
            mov value4, edx
            }
        value1          = value3 - value1; 
        value2          = value4 - value2;
        double MHZ      = (value1+(value2*(2^32)));
        return (DWORD)MHZ;
        }
    
    int main()
    {
        cout << (int)GetMHZ() << " Ticks"<<endl;
        cout << (int)GetMHZ() << " Ticks"<<endl;
        cout << (int)GetMHZ() << " Ticks"<<endl;
        cout << (int)GetMHZ() << " Ticks"<<endl;
    
        getch();
        return 0;
    }
    

    Wieso kommt mir da immer 11 raus?

    mfg und thx im Voraus
    Noob



  • Hallo Leute,
    Der Thread ist schon etwas älter, aber ich habe ein Problem mit diesem Code:
    Ich bekomme ca alle 2 bis 4 Sekunden in value4 einen Wert, der um 1 zu groß ist, bzw in value 2 einen, der um 1 zu klein ist.
    Da die Differenz dieser beiden Zahlen bei der Berechnung mit 2 hoch 32 malgenommen wird (hab diese Stelle in meinem code berichtigt), hat das natürlich ziemliche auswirkungen ...
    Ich dachte erst, das liegt daran, dass Sleep zu ungenau ist, deswegen hab ich mir mit QueryPerformanceFrequency und QueryPerformanceCounter ne eigene Sleep-Funktion gebastelt. Brachte aber keine Besserung. Jemand ne Idee, woran das liegen könnte und wie ich es beheben kann?
    Und hat jemand ne Ahnung, was QueryPerformanceFrequency ausliest und ob ich das anstelle dieses Codes irgendwie verwenden kann? Das kann nicht das gleiche sein, da der Wert sehr viel kleiner ist ...
    Danke



  • Niemand ne Idee?



  • Mich wundert, dass diese CPU-Speed-messung so ueberhaupt funktionieren soll... Die Interrupts bleiben schliesslich aktiviert, dadurch wird IMHO das Ergebnis verfaelscht 😕



  • wenn ich schreibe:

    ;vergangene millisekunden messen
    mov ecx,10000
    loop__:
    db 90 dup(10000)
    dec ecx
    jnz loop__:
    ;nochmal millisekunden messen

    damit kriege ich doch die ungefähre zeit raus die die CPU für 100MHZ(wenn ihc mich nicht verrechnet habe) raus oder?
    Damit könnte man die geschwindigkeit auf die echte Rechenleistung hoch rechnen.



  • So wie ich das sehe, wuerde diese Prozedur zwischen den beiden Messpunkten ziemlich lange dauern... Da kannst Du dir sicher sein, dass Windows in der Zwischenzeit ein paar Interrupts abhandelt und schon ist das Ergebnis unbrauchbar.



  • Original erstellt von Bigor:
    damit kriege ich doch die ungefähre zeit raus die die CPU für 100MHZ(wenn ihc mich nicht verrechnet habe) raus oder?
    Damit könnte man die geschwindigkeit auf die echte Rechenleistung hoch rechnen.

    Jein, nicht wenn dein Prozessor parallelisiert und z.B. drei NOPs gelichzetig ausführt 🙂


Anmelden zum Antworten