kenhero
kenhero

Reputation: 105

CPU Usage of every process

I found this code on google that calculate of % of usage of current process on win10,but what i'm looking for is a list of % of CPU Usage of every process. I use GetCurrentProcess() to have the handle of the current process. Is there a way to retrieve the handle of every processes?i'm working on a code that lists running process and calculate usage memory for everyone. Then i need to calculate cpu usage for everyone but i didn't find anything on google.

    static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
    static int numProcessors;
    static HANDLE self;

    void init(){
    SYSTEM_INFO sysInfo;
    FILETIME ftime, fsys, fuser;

    GetSystemInfo(&sysInfo);
    numProcessors = sysInfo.dwNumberOfProcessors;

    GetSystemTimeAsFileTime(&ftime);
    memcpy(&lastCPU, &ftime, sizeof(FILETIME));

    self = GetCurrentProcess();
    GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);
    memcpy(&lastSysCPU, &fsys, sizeof(FILETIME));
    memcpy(&lastUserCPU, &fuser, sizeof(FILETIME));
    }

    double getCurrentValue(){
    FILETIME ftime, fsys, fuser;
    ULARGE_INTEGER now, sys, user;
    long double  percent;

    GetSystemTimeAsFileTime(&ftime);
    memcpy(&now, &ftime, sizeof(FILETIME));

    GetProcessTimes(GetCurrentProcess(), &ftime, &ftime, &fsys, &fuser);
    memcpy(&sys, &fsys, sizeof(FILETIME));
    memcpy(&user, &fuser, sizeof(FILETIME));
    percent = (sys.QuadPart - lastSysCPU.QuadPart) +
    (user.QuadPart - lastUserCPU.QuadPart);
    percent /= (now.QuadPart - lastCPU.QuadPart);
    percent /= numProcessors;
    lastCPU = now;
    lastUserCPU = user;
    lastSysCPU = sys;

    return percent * 100;
    }

I'm able to have the list of all running processes but i'm looking for to
calculate cpu usage for every process.
Suggestions?

Upvotes: 0

Views: 1840

Answers (1)

RbMm
RbMm

Reputation: 33716

ok, for effective coding this task need use NtQueryInformationProcess with SystemProcessInformation info class. we got here array of SYSTEM_PROCESS_INFORMATION. here we already have:

LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;

when in PROCESSENTRY32 no this members. toolhelp functions simply drop this member. without it we need open every process, call GetProcessTimes, etc. with NtQueryInformationProcess all become much more effective and simply. general idea - we need maintain list of processes, and periodic call NtQueryInformationProcess for add new created processes and remove died.

// for debug only 0 <= cpuUsage <= 1000

void PrintCpuUsage(ULONG cpuUsage, PCUNICODE_STRING Name)
{
    ULONG p = cpuUsage / 10;
    DbgPrint("%02u.%u %wZ\n", p, cpuUsage - p * 10, Name);
}

struct PROCESS_ENTRY : LIST_ENTRY, UNICODE_STRING
{
    LARGE_INTEGER _CreateTime, _RunTime;
    union {
        LARGE_INTEGER _Delta;
        ULONG _cpuUsage;
    };
    HANDLE _UniqueProcessId;
    HANDLE _InheritedFromUniqueProcessId;
    BOOLEAN _bEnumerated;

    PROCESS_ENTRY()
    {
        RtlInitUnicodeString(this, 0);
        InitializeListHead(this);
        _RunTime.QuadPart = 0;
        _UniqueProcessId = 0;
    }

    ~PROCESS_ENTRY()
    {
        DbgPrint("--%08x(%08x) %wZ\n", _UniqueProcessId, _InheritedFromUniqueProcessId, static_cast<UNICODE_STRING*>(this));
        RtlFreeUnicodeString(this);
        RemoveEntryList(this);
    }

    NTSTATUS Init(PSYSTEM_PROCESS_INFORMATION pspi)
    {
        _UniqueProcessId = pspi->UniqueProcessId;
        _InheritedFromUniqueProcessId = pspi->InheritedFromUniqueProcessId;
        _CreateTime = pspi->CreateTime;
        DbgPrint("++%08x(%08x) %wZ\n", _UniqueProcessId, _InheritedFromUniqueProcessId, &pspi->ImageName);
        return RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &pspi->ImageName, this);
    }

    LONGLONG UpdateProcess(PSYSTEM_PROCESS_INFORMATION pspi)
    {
        _bEnumerated = TRUE;

        pspi->KernelTime.QuadPart += pspi->UserTime.QuadPart;
        _Delta.QuadPart = pspi->KernelTime.QuadPart - _RunTime.QuadPart;
        _RunTime.QuadPart = pspi->KernelTime.QuadPart;

        return _Delta.QuadPart;
    }

    void CalcCpuUsage(LONGLONG QuadPart)
    {
        _bEnumerated = FALSE;

        _cpuUsage = (ULONG)((_Delta.QuadPart * 1000) / QuadPart );

        if (_cpuUsage && _UniqueProcessId)
        {
            PrintCpuUsage(_cpuUsage, this);
        }
    }
};

struct PROCES_LIST : public LIST_ENTRY 
{
    LIST_ENTRY _ListHead;
    PROCESS_ENTRY IdleProcess;
    BOOL _bValid;

    PROCES_LIST()
    {
        InitializeListHead(&_ListHead);
        _bValid = FALSE;
    }

    LONGLONG UpdateOrAddNewProcess(PSYSTEM_PROCESS_INFORMATION pspi);

    void RemoveDiedEntries(LONGLONG QuadPart);

    void EnumPro();

    ~PROCES_LIST()
    {
        RemoveDiedEntries(0);
    }
};

LONGLONG PROCES_LIST::UpdateOrAddNewProcess(PSYSTEM_PROCESS_INFORMATION pspi)
{
    PROCESS_ENTRY* pe;
    PLIST_ENTRY head = &_ListHead, entry = head;
    HANDLE UniqueProcessId = pspi->UniqueProcessId;

    while ((entry = entry->Flink) != head)
    {
        pe = static_cast<PROCESS_ENTRY*>(entry);

        if (pe->_UniqueProcessId == UniqueProcessId && pe->_CreateTime.QuadPart == pspi->CreateTime.QuadPart)
        {
            return pe->UpdateProcess(pspi);
        }
    }

    if (pe = new PROCESS_ENTRY)
    {
        if (0 <= pe->Init(pspi))
        {
            InsertTailList(head, pe);
            return pe->UpdateProcess(pspi);
        }
        delete pe;
    }

    return 0;
}

void PROCES_LIST::RemoveDiedEntries(LONGLONG QuadPart)
{
    PLIST_ENTRY head = &_ListHead, entry = head->Flink;

    while (entry != head)
    {
        PROCESS_ENTRY* pe = static_cast<PROCESS_ENTRY*>(entry);

        entry = entry->Flink;

        if (pe->_bEnumerated)
        {
            pe->CalcCpuUsage(QuadPart);
        }
        else
        {
            delete pe;
        }
    }
}

void PROCES_LIST::EnumPro()
{
    ULONG cb = 0, rcb = 0x10000;
    PVOID stack = alloca(guz);// volatile UCHAR guz;

    union {
        PVOID buf;
        PBYTE pb;
        PSYSTEM_PROCESS_INFORMATION pspi;
    };

    NTSTATUS status;

    do 
    {
        if (cb < rcb)
        {
            cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
        }

        if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &rcb)))
        {
            LONGLONG QuadPart = 0;

            ULONG NextEntryOffset = 0;
            do 
            {
                pb += NextEntryOffset;

                if (pspi->UniqueProcessId)
                {
                    QuadPart += UpdateOrAddNewProcess(pspi);
                }
                else
                {
                    QuadPart += IdleProcess.UpdateProcess(pspi);
                }

            } while (NextEntryOffset = pspi->NextEntryOffset);

            RemoveDiedEntries(QuadPart);
            IdleProcess.CalcCpuUsage(QuadPart);

            if (_bValid)
            {
                static UNICODE_STRING empty;
                PrintCpuUsage(1000 - IdleProcess._cpuUsage, &empty);
            }
            else
            {
                _bValid = TRUE;
            }
        }

    } while (status == STATUS_INFO_LENGTH_MISMATCH);
}

Upvotes: 2

Related Questions