为了账号安全,请及时绑定邮箱和手机立即绑定

如何从进程内部确定CPU和内存消耗?

如何从进程内部确定CPU和内存消耗?

慕桂英546537 2019-06-06 10:44:36
如何从进程内部确定CPU和内存消耗?我曾经负责从运行中的应用程序中确定以下性能参数:可用虚拟内存总量当前使用的虚拟内存我的进程当前使用的虚拟内存可用内存总数Ram目前使用我的进程目前使用的RAM目前使用的CPU百分比我的进程当前使用的CPU%代码必须在Windows和Linux上运行。尽管这似乎是一项标准任务,但在手册(Win 32 API,GNU docs)中以及在Internet上找到必要的信息花了我几天的时间,因为关于这个主题有很多不完整/不正确/过时的信息要找出来。为了避免其他人经历同样的麻烦,我认为收集所有零散的信息,再加上我在一个地方经过反复试验发现的信息,是个好主意。
查看完整描述

3 回答

?
侃侃无极

TA贡献2051条经验 获得超10个赞

上面的一些值很容易从适当的Win 32 API中获得,我只是在这里列出它们的完整性。然而,另一些则需要从性能数据帮助库(PDH)中获得,这有点“不直观”,需要大量痛苦的尝试和错误才能开始工作。(至少花了我一段时间,也许我只是有点傻.)

注意:为了清楚起见,以下代码省略了所有错误检查。检查返回码.!


  • 总虚拟内存:

    #include "windows.h"MEMORYSTATUSEX memInfo;memInfo.dwLength = sizeof(MEMORYSTATUSEX);GlobalMemoryStatusEx(&memInfo);
    DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;

    注意:这里的名字“TotalPageFile”有点误导。实际上,这个参数给出了“虚拟内存大小”,即交换文件加上已安装RAM的大小。

  • 当前使用的虚拟内存:

    与“总虚拟内存”中的代码相同,然后

    DWORDLONG virtualMemUsed = memInfo.ullTotalPageFile - memInfo.ullAvailPageFile;
  • 当前进程当前使用的虚拟内存:

    #include "windows.h"#include "psapi.h"PROCESS_MEMORY_COUNTERS_EX pmc;GetProcessMemoryInfo(GetCurrentProcess(), 
    &pmc, sizeof(pmc));SIZE_T virtualMemUsedByMe = pmc.PrivateUsage;



  • 总物理内存(RAM):

    与“总虚拟内存”中的代码相同,然后

    DWORDLONG totalPhysMem = memInfo.ullTotalPhys;
  • 目前使用的物理内存:

    Same code as in "Total Virtual Memory" and thenDWORDLONG physMemUsed = memInfo.ullTotalPhys - memInfo.ullAvailPhys;
  • 当前进程当前使用的物理内存:

    与“当前进程当前使用的虚拟内存”中的代码相同,然后

    SIZE_T physMemUsedByMe = pmc.WorkingSetSize;



  • 目前使用的CPU:

    #include "TCHAR.h"#include "pdh.h"static PDH_HQUERY cpuQuery;static PDH_HCOUNTER cpuTotal;void init(){
        PdhOpenQuery(NULL, NULL, &cpuQuery);
        // You can also use L"\\Processor(*)\\% Processor Time" and get individual CPU values with
         PdhGetFormattedCounterArray()
        PdhAddEnglishCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
        PdhCollectQueryData(cpuQuery);}double getCurrentValue(){
        PDH_FMT_COUNTERVALUE counterVal;
    
        PdhCollectQueryData(cpuQuery);
        PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
        return counterVal.doubleValue;}
  • 当前进程当前使用的CPU:

    #include "windows.h"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;
        double percent;
    
        GetSystemTimeAsFileTime(&ftime);
        memcpy(&now, &ftime, sizeof(FILETIME));
    
        GetProcessTimes(self, &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;}

linux

在linux上,一开始似乎很明显的选择是使用POSIX API,如getrusage()等。我花了一些时间试着让它发挥作用,但却没有得到有意义的价值。当我最终检查内核源代码时,我发现这些API显然还没有在Linux2.6内核中完全实现!

最后,我通过合并读取伪文件系统获得了所有的值。/proc和内核调用。

  • 总虚拟内存:

    #include "sys/types.h"#include "sys/sysinfo.h"struct sysinfo memInfo;sysinfo (&memInfo);long long totalVirtualMem 
    = memInfo.totalram;//Add other values in next statement to avoid int overflow on right hand 
    side...totalVirtualMem += memInfo.totalswap;totalVirtualMem *= memInfo.mem_unit;
  • 当前使用的虚拟内存:

    与“总虚拟内存”中的代码相同,然后

    long long virtualMemUsed = memInfo.totalram - memInfo.freeram;//Add other values in next statement to avoid 
    int overflow on right hand side...virtualMemUsed += memInfo.totalswap - memInfo.freeswap;virtualMemUsed *= memInfo.mem_unit;
  • 当前进程当前使用的虚拟内存:

    #include "stdlib.h"#include "stdio.h"#include "string.h"int parseLine(char* line){
        // This assumes that a digit will be found and the line ends in " Kb".
        int i = strlen(line);
        const char* p = line;
        while (*p <'0' || *p > '9') p++;
        line[i-3] = '\0';
        i = atoi(p);
        return i;}int getValue(){ //Note: this value is in KB!
        FILE* file = fopen("/proc/self/status", "r");
        int result = -1;
        char line[128];
    
        while (fgets(line, 128, file) != NULL){
            if (strncmp(line, "VmSize:", 7) == 0){
                result = parseLine(line);
                break;
            }
        }
        fclose(file);
        return result;}



  • 总物理内存(RAM):

    与“总虚拟内存”中的代码相同,然后

    long long totalPhysMem = memInfo.totalram;//Multiply in next statement to avoid int overflow on right hand
     side...totalPhysMem *= memInfo.mem_unit;
  • 目前使用的物理内存:

    与“总虚拟内存”中的代码相同,然后

    long long physMemUsed = memInfo.totalram - memInfo.freeram;//Multiply in next statement to avoid int overflow 
    on right hand side...physMemUsed *= memInfo.mem_unit;
  • 当前进程当前使用的物理内存:

    在“当前进程当前使用的虚拟内存”中更改getValue()如下:

    int getValue(){ //Note: this value is in KB!
        FILE* file = fopen("/proc/self/status", "r");
        int result = -1;
        char line[128];
    
        while (fgets(line, 128, file) != NULL){
            if (strncmp(line, "VmRSS:", 6) == 0){
                result = parseLine(line);
                break;
            }
        }
        fclose(file);
        return result;}




  • 目前使用的CPU:

    #include "stdlib.h"#include "stdio.h"#include "string.h"static unsigned long long lastTotalUser, lastTotalUserLow, 
    lastTotalSys, lastTotalIdle;void init(){
        FILE* file = fopen("/proc/stat", "r");
        fscanf(file, "cpu %llu %llu %llu %llu", &lastTotalUser, &lastTotalUserLow,
            &lastTotalSys, &lastTotalIdle);
        fclose(file);}double getCurrentValue(){
        double percent;
        FILE* file;
        unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total;
    
        file = fopen("/proc/stat", "r");
        fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow,
            &totalSys, &totalIdle);
        fclose(file);
    
        if (totalUser < lastTotalUser || totalUserLow < lastTotalUserLow ||
            totalSys < lastTotalSys || totalIdle < lastTotalIdle){
            //Overflow detection. Just skip this value.
            percent = -1.0;
        }
        else{
            total = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) +
                (totalSys - lastTotalSys);
            percent = total;
            total += (totalIdle - lastTotalIdle);
            percent /= total;
            percent *= 100;
        }
    
        lastTotalUser = totalUser;
        lastTotalUserLow = totalUserLow;
        lastTotalSys = totalSys;
        lastTotalIdle = totalIdle;
    
        return percent;}
  • 当前进程当前使用的CPU:

    #include "stdlib.h"#include "stdio.h"#include "string.h"#include "sys/times.h"#include "sys/vtimes.h"static clock_t lastCPU,
     lastSysCPU, lastUserCPU;static int numProcessors;void init(){
        FILE* file;
        struct tms timeSample;
        char line[128];
    
        lastCPU = times(&timeSample);
        lastSysCPU = timeSample.tms_stime;
        lastUserCPU = timeSample.tms_utime;
    
        file = fopen("/proc/cpuinfo", "r");
        numProcessors = 0;
        while(fgets(line, 128, file) != NULL){
            if (strncmp(line, "processor", 9) == 0) numProcessors++;
        }
        fclose(file);}double getCurrentValue(){
        struct tms timeSample;
        clock_t now;
        double percent;
    
        now = times(&timeSample);
        if (now <= lastCPU || timeSample.tms_stime < lastSysCPU ||
            timeSample.tms_utime < lastUserCPU){
            //Overflow detection. Just skip this value.
            percent = -1.0;
        }
        else{
            percent = (timeSample.tms_stime - lastSysCPU) +
                (timeSample.tms_utime - lastUserCPU);
            percent /= (now - lastCPU);
            percent /= numProcessors;
            percent *= 100;
        }
        lastCPU = now;
        lastSysCPU = timeSample.tms_stime;
        lastUserCPU = timeSample.tms_utime;
    
        return percent;}

Todo:其他平台

我假设,除了读取/proc伪文件系统的部分之外,一些Linux代码也适用于unix。也许在unix上,这些部件可以由getrusage()还有类似的功能?如果有Unix技术的人可以编辑这个答案并填写详细信息?!


查看完整回答
反对 回复 2019-06-06
  • 3 回答
  • 0 关注
  • 889 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信