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

2023-11-24

我曾经承担过从正在运行的应用程序内部确定以下性能参数的任务:

  • 可用虚拟内存总量
  • 当前使用的虚拟内存
  • Virtual memory currently used by my process
  • 可用内存总量
  • 当前使用的内存
  • RAM currently used by my process
  • 当前使用的CPU百分比
  • 我的进程当前使用的 CPU 百分比

该代码必须在 Windows 和 Linux 上运行。尽管这似乎是一项标准任务,但在手册(WIN32 API、GNU 文档)以及互联网上找到必要的信息花了我几天的时间,因为关于这个主题的信息太多不完整/不正确/过时的信息。在那里发现的。

为了避免其他人遇到同样的麻烦,我认为最好将所有零散的信息以及我在这里反复试验发现的信息收集到一个地方。


Windows

上面的一些值可以很容易地从适当的 Win32 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(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
    SIZE_T virtualMemUsedByMe = pmc.PrivateUsage;
    
  • 总物理内存 (RAM):

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

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

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

    DWORDLONG 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 从 Linux 内核 2.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()以及类似的功能?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何从进程内部确定 CPU 和内存消耗 的相关文章

随机推荐

  • Xcode 界面生成器。这些自动调整大小蒙版设置有何不同?

    我现在很习惯在 IB 中使用自动调整大小蒙版 但是有两个自动调整大小设置 我不清楚它们有何不同 设置1 使用上下锚点自动调整大小http dl dropbox com u 11270323 stackoverflow autosize ma
  • 登录系统生成的PHP空会话文件

    最近我注意到正在创建许多空白会话 我不确定为什么 但我相信我正在以正确的方式做所有事情 目前我们创建一个会话 当用户logs in or 寄存器 然后我们检查用户是否使用isset COOKIE auth 属于登录或注册期间创建的会话 如果
  • 按值分组 RAND()

    有可能获得组的随机值吗 nID val A XXX A YYY B L B M B N B P 使用此 SQL SELECT nID VAL FROM T1 GROUP BY nID 我的结果总是 nID val A XXX B L 但我想
  • 如何在使用自定义窗口镶边时向 WPF 标题栏添加按钮?

    我正在尝试创建一个简单的按钮模板 其中按钮通常看起来像一条水平线 但是当鼠标悬停在按钮上时 按钮后面会显示一个 矩形 颜色填充 这是我的代码 但我似乎无法触发触发器
  • 如何让子窗口保持在最上面?

    我在用window open从父窗口打开子窗口 我希望子窗口保持在顶部 以便用户在父窗口中进行输入时可以参考它 这可以做到吗 我目前使用的是 Firefox 但如果它能在所有浏览器中运行 那就太好了 怎么样使用一个弹出div而不是打开一个新
  • GitHub Packages Docker - 拉取映像配置时出错:未知 blob

    GitHub 包开始返回error pulling image configuration unknown blob这个周末尝试拉取 docker 镜像时 它仍然可以将图像推送到注册表 我在 GitHub 上没有找到任何指向问题的信息 00
  • MySQL 与实体框架 - 我做错了什么?

    我对实体框架甚至 ADO NET 完全陌生 通常不会对数据库做太多工作 我下载并安装了MySQL 连接器 NET 6 3 5 我在 Visual Studio 2010 中创建了一个新的 C 项目 我向我的项目添加了一个新的 ADO NET
  • 使用 Facebook4j api 从页面获取帖子

    我想知道是否有一种方法可以使用 Facebook4J API 从 Facebook 页面获取所有 甚至最近 帖子 我知道可以从用户的墙或提要中获取所有帖子 但我在 API 或文档中找不到任何显示如何从页面获取帖子的内容 看着http fac
  • 如何检查bash脚本中特定目录中是否存在文件?

    这是我一直在尝试的 但没有成功 如果我想检查 example 目录中是否存在文件 FILE 1 if e FILE example then echo File exists else echo File does not exist fi
  • 迭代字典时如何避免 swift 中的重复键错误

    我正在练习 swift 我正在尝试迭代字典来打印密钥 但它给了我一个 致命错误 字典文字包含重复的键 如何消除错误 let people age 14 age 15 age 75 age 43 age 103 age 87 age 12 f
  • 获取 svg 路径上点的 y 坐标

    我想我需要添加一些解释 我想问这个问题 因为太短的问题不符合质量标准 有趣 所以 问题是 如何获取 svg 路径上特定 x 坐标处点的 y 坐 标 这并不简单 因为一条路径可能有多个具有指定的点x协调 SVG DOM 中没有内置函数可以执行
  • 提取 DOCX 注释

    我是一名教师 我想要一份对我布置的论文发表评论的所有学 生以及他们所说内容的列表 Drive API 的东西对我来说太具有挑战性 但我想我可以将它们下载为 zip 并解析 XML 评论被标记为w comment标签 与w t对于评论文本和
  • 在视图中自动布局“打开”时无法移动 UILabel 的 Y 位置

    我一定在这里遗漏了一些非常明显的东西 但这是一个让我沮丧了好几天的问题 在 xcode 4 5 上的 iOS 项目中 我在 XIB 中有几个标签 一个在另一个之上 在一个UIScrollView占据一个UIView 每个标签与视图一样宽 并
  • 在Python循环中使用迭代器作为变量名

    我一直想知道是否有一种方法可以在 Python 循环中使用迭代器作为变量名 例如 如果我想创建对象v0 v1 v2 有没有办法做这样的事情 for i in range 3 v str i i 2 我知道语法是错误的 但想法应该很清楚 相当
  • 编译32位时出现__int128错误

    c random h 106 error expected unqualified id before int128 当我编译 32 位程序时 上面是我得到的错误 我在用着http sourceforge net projects ming
  • 使用Scala宏生成方法

    我想在 Scala 2 11 中使用注释宏生成方法的别名 我什至不确定这是否可能 如果是 怎么办 示例 鉴于下面的内容 我希望注释宏扩展到 class Socket alias aliases Seq ask read def load n
  • 将 .gz 文件添加到 .zip 存档而不解压并重新压缩?

    假设 gzip 文件和 zip 存档都使用 DEFLATE 由于两者都会为特定文件存储相同的原始压缩数据 是否可以将预压缩的 gz 文件添加到现有的 zip 存档中 一些元数据可能会丢失 或不可用 但我更关心原始文件数据 Yes 我不记得为
  • 将 numpy int16 音频数组转换为 float32

    我有原始二进制 int16 数据 我正在使用它转换为 numpy 数组 audio np fromstring raw data dtype np int16 该数据是音频数据 当我将数据转换为 float32 时 音频变得失真 audio
  • 如何修复 由于目标计算机主动拒绝而无法建立连接 127.0.0.1:64527

    我有一个 MVC 应用程序 它依赖于 Web API 应用程序 我将这两个应用程序托管在共享托管环境上 子域上的 API 和主域上的 MVC API 是 api mydomain com MVC 是 mydomain com 每当我在邮递员
  • 如何从进程内部确定 CPU 和内存消耗

    我曾经承担过从正在运行的应用程序内部确定以下性能参数的任务 可用虚拟内存总量 当前使用的虚拟内存 Virtual memory currently used by my process 可用内存总量 当前使用的内存 RAM currentl