Prozessorlast auslesen



  • Hallo,

    also ich habe gesehen, dass es zu dem Thema auch einen FAQ Beitrag gibt. (http://www.c-plusplus.net/forum/86669-full) Der Code funktioniert bei mir alelrdings nur eingeschränkt. Beim ersten Aufruf (logischerweise) gibt er 0 zurück. Ab dem zweiten immer 100%.
    Da der Beitrag schon recht alt ist (2004), wollte ich ihn auch nicht wieder hervor kramen. Kann es sein, dass "GetCpuUsage()" Nur die Auslastung eines Kernes zurück gibt und nicht die Gesamtauslastung?
    Wenn ja, gibt es über die WinAPI eine Möglichkeit die Gesamtauslastung zu bekommen?
    Meine recherchen haben mir einen recht guten .net(http://msdn.microsoft.com/de-de/library/fa60x4ta.aspx Code und Funktionen zu Tage befördert, allerdings muss ich auf .net möglichst verzichten.

    Schonmal vielen Dank.



  • Der Code aus der FAQ liefert bei mir auch keine richtigen Ergebnisse. "GetProcessTimes" scheint ja nur für einen Prozess zu funktionieren. Darum hab ich mal schnell was eigenes gebastelt:

    #include <stdint.h>
    #include <Windows.h>
    #include <iostream>
    
    uint64_t FileTimeToInt64(FILETIME time)
    {
    	return (((uint64_t)time.dwHighDateTime)<<32) +time.dwLowDateTime;
    }
    
    //returns the CPU load (average over the timespan to the last time the function was called)
    double GetCPULoad2() 
    { 
    	static uint64_t lastIdleTime = 0;
    	static uint64_t lastBusyTime = 0;
    	FILETIME idleFileTime, kernelFileTime, userFileTime;
    	GetSystemTimes(&idleFileTime, &kernelFileTime, &userFileTime);
    
    	uint64_t idleTime = FileTimeToInt64(idleFileTime);
    	uint64_t busyTime = FileTimeToInt64(kernelFileTime) + FileTimeToInt64(userFileTime) - idleTime; // subtract idleTime, because kernelTime includes the time the system has been idle
    
    	uint64_t diffIdle = idleTime - lastIdleTime;
    	uint64_t diffBusy = busyTime - lastBusyTime;
    
    	double load = (double)diffBusy / (diffBusy + diffIdle);
    
    	lastIdleTime = idleTime;
    	lastBusyTime = busyTime;
    
        return load; 
    }
    
    // Test the function
    int main()
    {
    	GetCPULoad2(); // Initialize
    	for(int i=0; i< 100; i++)
    	{
    		Sleep(1000);
    		double load2 = GetCPULoad2();
    		std::cout << "time: " << load2*100 << "%" << std::endl;
    	}
    }
    

    Kurze Erklärung:

    <a href= schrieb:

    msdn - GetSystemTimes ">Retrieves system timing information. On a multiprocessor system, the values returned are the sum of the designated times across all processors.

    Die Funktion liefert

    1. Die Zeit die in Usermode verbracht wurde
    2. Die Zeit die Idle verbracht wurde
    3. Die Summe der Zeiten die Idle und im Kernel verbracht wurden.

    Aus diesen Werten kannst du dann ganz einfach die Auslastung ausrechen, einfach das Verhältnis der Zeit in Threads zu der Gesamtzeit.
    Laut meinen kurzen Vergleichen mit dem Taskmanager stimmen sie Zeiten auch, trotzdem keine Garantie dass es keine Probleme gibt. 😃



  • Danke,

    scheint zu funktionieren. Ich werde es mir aber noch genauer ansehen und mit Fehlerbehandlung und Änderungen noch einmal hier rein schreiben.

    Bis dahin



  • Hier der Versprochene Code einer Funktion:

    std::wstring SystemInformation::getCPULoad()
    {
        std::wstringstream retValue;
        static uint64_t lastIdleTime = 0;
        static uint64_t lastBusyTime = 0;
        FILETIME idleFileTime, kernelFileTime, userFileTime;
        double load = 0;
    
        for (int i = 0; i < 10; ++i)
        {
            if (GetSystemTimes(&idleFileTime, &kernelFileTime, &userFileTime))
            {
                uint64_t idleTime = fileTimeToInt64(idleFileTime);
                uint64_t busyTime = fileTimeToInt64(kernelFileTime) + fileTimeToInt64(userFileTime) - idleTime; // subtract idleTime, because kernelTime includes the time the system has been idle
    
                uint64_t diffIdle = idleTime - lastIdleTime;
                uint64_t diffBusy = busyTime - lastBusyTime;
    
                load = (double)diffBusy / (diffBusy + diffIdle);
    
                lastIdleTime = idleTime;
                lastBusyTime = busyTime;
    
                load = load * 100;
            }
            else
            {
                DWORD error = GetLastError();
                wchar_t errorText[1024];
                std::wstring errorMessage;
    
                FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, NULL, errorText, 1024, NULL);
                errorMessage = errorText;
                retValue << "Error by getting System Times:" << std::endl << errorMessage << std::endl;
            }
            Sleep(1000);
        }
        retValue << std::setprecision(2) << load << "%" << std::endl;
    
        return retValue.str();
    }
    

    Soltle funktionieren, habe im Vergleich zu dem, was ich benutze nur den Rückgabetyp und damit den typ des String Streams geändert, wobei ich bei meiner Benutzung über eine externe Funktion zwischen string und wstring hin und her konvertiere.
    Viel Erfolg!



  • Ein paar Sachen zu deinem Code:

    //Header und fehlende Funktion nachgeliefert
    #include <string>
    #include <sstream>
    #include <stdint.h>
    #include <iomanip> 
    #include <windows.h>
    
    uint64_t fileTimeToInt64(FILETIME time)
    {
    	return (((uint64_t)time.dwHighDateTime)<<32) +time.dwLowDateTime;
    }
    
    //warum einen string zurück geben ?
    //Gib lieber einen Fehlercode zurück (z.B. -1) und lass das Programm entscheiden was es damit macht
    //Wobei ich generell sagen würde dass "GetSystemTimes" nie fehlschlagen sollte wenn die Parameter korrekt sind, ergo würde ich den Fehlercheck auch weglassen.
    //Im übrigen blockt die Funktion für 10 Sekunden, finde ich keine gute Idee so
    std::wstring getCPULoad()
    { 
        std::wstringstream retValue; //warum schon hier erstellen statt erst wenn sie gebraucht wird ?
        static uint64_t lastIdleTime = 0; 
        static uint64_t lastBusyTime = 0; 
        FILETIME idleFileTime, kernelFileTime, userFileTime; 
        double load = 0; 
    
        for (int i = 0; i < 10; ++i) 
        { 
            if (GetSystemTimes(&idleFileTime, &kernelFileTime, &userFileTime)) 
            { 
                uint64_t idleTime = fileTimeToInt64(idleFileTime); 
                uint64_t busyTime = fileTimeToInt64(kernelFileTime) + fileTimeToInt64(userFileTime) - idleTime;
    
                uint64_t diffIdle = idleTime - lastIdleTime; 
                uint64_t diffBusy = busyTime - lastBusyTime; 
    
                load = (double)diffBusy / (diffBusy + diffIdle); 
    
                lastIdleTime = idleTime; 
                lastBusyTime = busyTime; 
    
                load = load * 100; // warum 10 durchläufe wenn du die ersten 9 Ergebnisse verwirfst ?
            } 
            else 
            { 
                DWORD error = GetLastError(); 
    			wchar_t errorText[1024]; 
                std::wstring errorMessage; 
    
                //erst FormatMessage und dann nochmal formatieren über den stringstream ?
                FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, NULL, errorText, 1024, NULL); 
                errorMessage = errorText; //wozu noch eine extra variable ?
                retValue << "Error by getting System Times:" << std::endl << errorMessage << std::endl; 
            } 
            Sleep(1000); 
        } 
        retValue << std::setprecision(2) << load << "%" << std::endl; 
    
        return retValue.str(); 
    }
    


  • Der string stream wird schon dort oben erstellt, weil er sonst nur im Fehlerfall erstellt wird. zumindest wenn man die Fehlerbehandlung drin lässt.
    Die Funktion sollte mindestens 2 mal aufgerufen werden, damit die Statics einen Wert beinhalten, der nicht 0 ist und somit ein korrekter Wert zurückgegeben wird. Eigentlich müsste ich ab dem 2.mal einen Mittelwert bilden, soweit gebe ich dir recht. Wenn du nicht wartest, zwischen den aufrufen, wird das ganze o schnell abgehandelt, dass es im Endeffekt quasi gleichzeitig passiert, deswegen die Aussage mit dem Mittelwert oben drüber.
    Die zweite Variable habe ich deshalb, weil ich sonst im Stringstream entweder nur das 1. Zeichen stehen habe, oder den Speicherort, nie das Gesamte Array, mag sein, dass das Compilerabhängig ist, ich hatte dieses Verhalten zur genüge (MSVC2013).
    Die zweite Formatierung ist sicher persönlicher Geschmack, ich kann damit sagen, wo der Fehler aufgetreten ist und weiß, wo ich suchen muss, im Gegensatz zu der System Fehlermeldung, die mir nur sagt weclher Fehler aufgetreten ist, aber nicht wo.
    Den Fehlercode gebe ich an der Stelle nicht zurück. Da ich ja mehrere durchläufe mache und jemand der GetLastError aufrufen wöllte, dann eventuell kein vernünftiges Ergebnis bekommt. Außerdem ist das wohl auch der Implementierung in meinem Gesamtprogramm geschuldet. Es soltle aber jedem, der den Code liest ein leichtes sein, statt des Strings einen Fehlercode zurück zu geben.
    Das mit den Headern und der Funktion war eine Nachlässigkeit meiner Seits, danke für die Ergänzung.



  • Khalidjian schrieb:

    Die Funktion sollte mindestens 2 mal aufgerufen werden, damit die Statics einen Wert beinhalten, der nicht 0 ist und somit ein korrekter Wert zurückgegeben wird. Eigentlich müsste ich ab dem 2.mal einen Mittelwert bilden, soweit gebe ich dir recht. Wenn du nicht wartest, zwischen den aufrufen, wird das ganze o schnell abgehandelt, dass es im Endeffekt quasi gleichzeitig passiert, deswegen die Aussage mit dem Mittelwert oben drüber.

    Aber 10mal den Wert für eine Sekunde lang messen und dann den Mittelwert bilden statt gleich den Wert 10 Sekunden lang zu messen ?
    Ist doch genau das selbe.

    Khalidjian schrieb:

    Die zweite Formatierung ist sicher persönlicher Geschmack, ich kann damit sagen, wo der Fehler aufgetreten ist und weiß, wo ich suchen muss, im Gegensatz zu der System Fehlermeldung, die mir nur sagt weclher Fehler aufgetreten ist, aber nicht wo.
    Den Fehlercode gebe ich an der Stelle nicht zurück. Da ich ja mehrere durchläufe mache und jemand der GetLastError aufrufen wöllte, dann eventuell kein vernünftiges Ergebnis bekommt. Außerdem ist das wohl auch der Implementierung in meinem Gesamtprogramm geschuldet. Es soltle aber jedem, der den Code liest ein leichtes sein, statt des Strings einen Fehlercode zurück zu geben.

    Nunja, ich wollte nur anmerken, dass GetSystemTimes eigentlich nie fehlschlagen sollte (vorausgesetzt die Parameter sind richtig), ich also den Fehlercheck weglassen würde.
    Und generell finde ich die Rückgabe einer Zahl für diese Funktion ganz einfach praktischer, lässt sich einfacher nutzen als ein string. Schon allein wegen dem string/wstring Problem. 😃


Anmelden zum Antworten