ChatGPT解决这个技术问题 Extra ChatGPT

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

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

可用的总虚拟内存

当前使用的虚拟内存

我的进程当前使用的虚拟内存

可用总 RAM

当前使用的内存

我的进程当前使用的 RAM

当前使用的 CPU 百分比

我的进程当前使用的 CPU 百分比

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

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

“可用的总虚拟内存”在现代操作系统上毫无意义。
为什么没有意义?它会使这里的答案无效吗? stackoverflow.com/questions/3296211/… ...请不要在评论时留下悬念,这不是电视节目。
@MindaugasBernatavičius:链接的问题是关于“总物理内存”,这是操作系统已知的硬件事实。您可以通过将所有内存模块的大小相加来获得总数。另一方面,“可用的总虚拟内存”是什么意思?那是理论上可以创建的所有进程的组合虚拟地址空间吗?这个数字大约是 2^80 字节,所以毫无意义。
@MSalters - 感谢参与。我相信询问 OP 的想法比说某事毫无意义(没有解释)要友善和健康得多。如果您注意到,答案也假设了一个特定的位置:虚拟内存 = RAM + SWAP(或 PAGEFILE) - 这是一个合理的假设。由此我们知道它不是没有意义的,因为对这个术语有特定的解释(这可能不是技术上最正确的,一种口语)是有意义的。
@MindaugasBernatavičius:这会忽略未分页的内存映射文件和代码。Linux 具有未提交的内存分配(不受 RAM 或交换支持),而 Windows 具有未提交的堆栈。

P
Peter Mortensen

视窗

上面的一些值很容易从适当的 Win32 API 中获得,为了完整起见,我只是在这里列出它们。然而,其他的则需要从 Performance Data Helper 库 (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;静态 PDH_HCOUNTER cpuTotal; void init(){ PdhOpenQuery(NULL, NULL, &cpuQuery); // 您也可以使用 L"\\Processor(*)\\% Processor Time" 并使用 PdhGetFormattedCounterArray() PdhAddEnglishCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, 获取单个 CPU 值&cpu总); PdhCollectQueryData(cpuQuery); } 双 getCurrentValue(){ PDH_FMT_COUNTERVALUE counterVal; PdhCollectQueryData(cpuQuery); PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);返回counterVal.doubleValue; }

当前进程当前使用的CPU:#include "windows.h" static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;静态整数处理器;静态处理自我; void init(){ SYSTEM_INFO sysInfo; FILETIME ftime, fsys, fuser;获取系统信息(&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 现在,系统,用户;双倍百分比; GetSystemTimeAsFileTime(&ftime); memcpy(&now, &ftime, sizeof(FILETIME)); GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser); memcpy(&sys, &fsys, sizeof(FILETIME)); memcpy(&user, &fuser, sizeof(FILETIME));百分比 = (sys.QuadPart - lastSysCPU.QuadPart) + (user.QuadPart - lastUserCPU.QuadPart);百分比 /= (now.QuadPart - lastCPU.QuadPart);百分比/= numProcessors;最后一个 CPU = 现在; lastUserCPU = 用户; lastSysCPU = 系统;返回百分比* 100; }

Linux

在 Linux 上,一开始似乎很明显的选择是使用 POSIX API,如 getrusage() 等。我花了一些时间试图让它工作,但从未得到有意义的值。当我最终自己检查内核源代码时,我发现显然这些 API 在 Linux 内核 2.6 中还没有完全实现!?

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

总虚拟内存:#include "sys/types.h" #include "sys/sysinfo.h" struct sysinfo memInfo;系统信息(&memInfo); long long totalVirtualMem = memInfo.totalram; //在下一条语句中添加其他值以避免右侧的int溢出... totalVirtualMem += memInfo.totalswap; totalVirtualMem *= memInfo.mem_unit;

当前使用的虚拟内存:与“总虚拟内存”中的代码相同,然后 long long virtualMemUsed = memInfo.totalram - memInfo.freeram; //在下一条语句中添加其他值以避免右侧的int溢出... virtualMemUsed += memInfo.totalswap - memInfo.freeswap; virtualMemUsed *= memInfo.mem_unit;

当前进程当前使用的虚拟内存:#include "stdlib.h" #include "stdio.h" #include "string.h" int parseLine(char* line){ // 这假设将找到一个数字并且该行以“Kb”结尾。 int i = strlen(线); const char* p = 行;而 (*p <'0' || *p > '9') p++;行[i-3] = '\0'; i = atoi(p);返回我; } int getValue(){ //注意:这个值以 KB 为单位! FILE* file = fopen("/proc/self/status", "r");整数结果 = -1;字符线[128]; while (fgets(line, 128, file) != NULL){ if (strncmp(line, "VmSize:", 7) == 0){ result = parseLine(line);休息; } } fclose(文件);返回结果; }

总物理内存 (RAM):与“总虚拟内存”中的代码相同,然后是 long long totalPhysMem = memInfo.totalram; //在下一条语句中相乘以避免右侧的int溢出... totalPhysMem *= memInfo.mem_unit;

当前使用的物理内存:与“总虚拟内存”中的代码相同,然后 long long physMemUsed = memInfo.totalram - memInfo.freeram; //在下一条语句中相乘以避免 int 在右侧溢出... physMemUsed *= memInfo.mem_unit;

当前进程当前使用的物理内存:将“当前进程当前使用的虚拟内存”中的getValue()更改为: int getValue(){ //注意:此值以KB为单位! FILE* file = fopen("/proc/self/status", "r");整数结果 = -1;字符线[128]; while (fgets(line, 128, file) != NULL){ if (strncmp(line, "VmRSS:", 6) == 0){ result = parseLine(line);休息; } } fclose(文件);返回结果; }

当前使用的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(文件); } double getCurrentValue(){ double percent;文件*文件; unsigned long long totalUser,totalUserLow,totalSys,totalIdle,total;文件 = fopen("/proc/stat", "r"); fscanf(file, "cpu %llu %llu %llu %llu", &totalUser, &totalUserLow, &totalSys, &totalIdle); fclose(文件); if (totalUser < lastTotalUser || totalUserLow < lastTotalUserLow || totalSys < lastTotalSys || totalIdle < lastTotalIdle){ //溢出检测。跳过这个值。百分比 = -1.0; } else{ 总计 = (totalUser - lastTotalUser) + (totalUserLow - lastTotalUserLow) + (totalSys - lastTotalSys);百分比 = 总数;总计 += (totalIdle - lastTotalIdle);百分比/=总数;百分比 *= 100; } lastTotalUser = 总用户; lastTotalUserLow = totalUserLow;最后一个总系统 = 总系统;最后总空闲 = 总空闲;回报百分比; }

当前进程当前使用的CPU:#include "stdlib.h" #include "stdio.h" #include "string.h" #include "sys/times.h" #include "sys/vtimes.h" static clock_t lastCPU,最后一个系统CPU,最后一个用户CPU;静态整数处理器;无效初始化(){文件*文件;结构 tms timeSample;字符线[128]; lastCPU = 次(&timeSample); lastSysCPU = timeSample.tms_stime; lastUserCPU = timeSample.tms_utime;文件 = fopen("/proc/cpuinfo", "r"); numProcessors = 0; while(fgets(line, 128, file) != NULL){ if (strncmp(line, "processor", 9) == 0) numProcessors++; } fclose(文件); } 双 getCurrentValue(){ 结构 tms timeSample;现在时钟;双倍百分比;现在 = 次(&timeSample); if (now <= lastCPU || timeSample.tms_stime < lastSysCPU || timeSample.tms_utime < lastUserCPU){ //溢出检测。跳过这个值。百分比 = -1.0; } else{ 百分比 = (timeSample.tms_stime - lastSysCPU) + (timeSample.tms_utime - lastUserCPU);百分比 /= (现在 - lastCPU);百分比/= numProcessors;百分比 *= 100; } 最后一个 CPU = 现在; lastSysCPU = timeSample.tms_stime; lastUserCPU = timeSample.tms_utime;回报百分比; }

TODO:其他平台

我会假设,一些 Linux 代码也适用于 Unix,除了读取 /proc 伪文件系统的部分。也许在 Unix 上,这些部分可以用 getrusage() 和类似的函数代替?


警告:在 PdhAddCounter 中,查询必须本地化,否则它将仅在英语本地系统上运行。对于 Vista/2008 和更高版本的系统,最好使用 PdhAddEnglishCounter 以避免本地化问题。
@NunoAniceto 使用 PROCESS_MEMORY_COUNTERS 时,您如何获取“当前进程当前使用的虚拟内存”? PrivateUsage is not a member of PROCESS_MEMORY_COUNTERS 是我收到的编译器错误!
为什么使用 "quotes like these" 来包含系统标头?
@CinCout 你需要一个铸造.. 替换 GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));使用 GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
@Lanzelot 因为,我们远远高于 Linux Kernel 3.0。你能更新你对 POSIX API 的 Linux 答案吗?如果可能,通过将 GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); 替换为 GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); 来更正 Windows 答案
P
Peter Mortensen

Mac OS X

总虚拟内存

这在 Mac OS X 上很棘手,因为它不使用预设的交换分区或 Linux 之类的文件。这是 Apple 文档中的一个条目:

注意:与大多数基于 Unix 的操作系统不同,Mac OS X 不为虚拟内存使用预先分配的交换分区。相反,它使用机器引导分区上的所有可用空间。

所以,如果你想知道还有多少虚拟内存可用,你需要得到根分区的大小。你可以这样做:

struct statfs stats;
if (0 == statfs("/", &stats))
{
    myFreeSwap = (uint64_t)stats.f_bsize * stats.f_bfree;
}

当前使用的虚拟总数

使用“vm.swapusage”键调用 systcl 可以提供有关交换使用的有趣信息:

sysctl -n vm.swapusage
vm.swapusage: total = 3072.00M  used = 2511.78M  free = 560.22M  (encrypted)

并不是说如果需要更多交换,此处显示的总交换使用量可能会改变,如上一节所述。所以总数实际上是当前的交换总数。在 C++ 中,可以这样查询这些数据:

xsw_usage vmusage = {0};
size_t size = sizeof(vmusage);
if( sysctlbyname("vm.swapusage", &vmusage, &size, NULL, 0)!=0 )
{
   perror( "unable to get swap usage by calling sysctlbyname(\"vm.swapusage\",...)" );
}

请注意,在 sysctl.h 中声明的“xsw_usage”似乎没有记录在案,我怀疑有一种更便携的方式来访问这些值。

我的进程当前使用的虚拟内存

您可以使用 task_info 函数获取有关当前进程的统计信息。这包括进程的当前驻留大小和当前虚拟大小。

#include<mach/mach.h>

struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;

if (KERN_SUCCESS != task_info(mach_task_self(),
                              TASK_BASIC_INFO, (task_info_t)&t_info,
                              &t_info_count))
{
    return -1;
}
// resident size is in t_info.resident_size;
// virtual size is in t_info.virtual_size;

可用总 RAM

使用 sysctl 系统函数可以获得系统中可用的物理 RAM 量,如下所示:

#include <sys/types.h>
#include <sys/sysctl.h>
...
int mib[2];
int64_t physical_memory;
mib[0] = CTL_HW;
mib[1] = HW_MEMSIZE;
length = sizeof(int64_t);
sysctl(mib, 2, &physical_memory, &length, NULL, 0);

当前使用的内存

您可以从 host_statistics 系统函数获取一般内存统计信息。

#include <mach/vm_statistics.h>
#include <mach/mach_types.h>
#include <mach/mach_init.h>
#include <mach/mach_host.h>

int main(int argc, const char * argv[]) {
    vm_size_t page_size;
    mach_port_t mach_port;
    mach_msg_type_number_t count;
    vm_statistics64_data_t vm_stats;

    mach_port = mach_host_self();
    count = sizeof(vm_stats) / sizeof(natural_t);
    if (KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
        KERN_SUCCESS == host_statistics64(mach_port, HOST_VM_INFO,
                                        (host_info64_t)&vm_stats, &count))
    {
        long long free_memory = (int64_t)vm_stats.free_count * (int64_t)page_size;

        long long used_memory = ((int64_t)vm_stats.active_count +
                                 (int64_t)vm_stats.inactive_count +
                                 (int64_t)vm_stats.wire_count) *  (int64_t)page_size;
        printf("free memory: %lld\nused memory: %lld\n", free_memory, used_memory);
    }

    return 0;
}

这里需要注意的一点是,Mac OS X 中有五种内存页面。它们如下:

锁定在适当位置且无法换出的有线页面 正在加载到物理内存中并且相对难以换出的活动页面 已加载到内存中但最近没有使用过,甚至可能不需要全部。这些是交换的潜在候选人。可能需要刷新此内存。缓存的页面已经被缓存了一些,很可能很容易被重用。缓存内存可能不需要刷新。缓存页面仍有可能被重新激活 完全空闲并可以使用的空闲页面。

需要注意的是,仅仅因为 Mac OS X 有时可能会显示非常少的实际可用内存,这可能并不能很好地表明有多少可以在短时间内使用。

我的进程当前使用的 RAM

请参阅上面的“我的进程当前使用的虚拟内存”。相同的代码适用。


您离开 #include 以在“我的进程当前使用的虚拟内存”部分中定义 task_info()。需要包含此标头以定义该功能。
关于获取 CPU 使用率的任何想法?
@Michael Taylor,非常感谢,但是关于当前用于 OS X 的 RAM 的问题,您似乎获得的是 VM 统计信息,而不是物理内存。这里真的是这样吗?
我们如何计算 APP 内存和缓存内存,如活动监视器?我使用 vm_stats.inactive_page_count *page_size t 计算文件缓存,但它与活动监视器不同步。提前致谢
原作者似乎对“虚拟内存”感到困惑——在某些情况下,它不是指交换到磁盘的内存,而是指虚拟地址空间,它可能不是完全分页的。找到一个不使用任何交换的系统,您会发现大多数进程的“virt”大小都比“rss”大。在“我的进程当前使用的虚拟内存”部分中,这就是“虚拟内存”所指的 - 地址空间,而不是交换到磁盘的内存。
M
Martin Del Vecchio

Linux

在 Linux 中,此信息在 /proc 文件系统中可用。我不太喜欢使用的文本文件格式,因为每个 Linux 发行版似乎都至少自定义了一个重要文件。快速查看“ps”的来源会发现混乱。

但在这里可以找到您寻求的信息:

/proc/meminfo 包含您寻找的大部分系统范围的信息。这里看起来像在我的系统上;我认为您对 MemTotal、MemFree、SwapTotal 和 SwapFree 感兴趣:

Anderson cxc # more /proc/meminfo
MemTotal:      4083948 kB
MemFree:       2198520 kB
Buffers:         82080 kB
Cached:        1141460 kB
SwapCached:          0 kB
Active:        1137960 kB
Inactive:       608588 kB
HighTotal:     3276672 kB
HighFree:      1607744 kB
LowTotal:       807276 kB
LowFree:        590776 kB
SwapTotal:     2096440 kB
SwapFree:      2096440 kB
Dirty:              32 kB
Writeback:           0 kB
AnonPages:      523252 kB
Mapped:          93560 kB
Slab:            52880 kB
SReclaimable:    24652 kB
SUnreclaim:      28228 kB
PageTables:       2284 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:   4138412 kB
Committed_AS:  1845072 kB
VmallocTotal:   118776 kB
VmallocUsed:      3964 kB
VmallocChunk:   112860 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

对于 CPU 利用率,您必须做一些工作。 Linux 提供自系统启动以来的整体 CPU 利用率;这可能不是您感兴趣的。如果您想知道最后一秒或 10 秒的 CPU 利用率是多少,那么您需要查询信息并自行计算。

信息可在 /proc/stat 中找到,在 http://www.linuxhowtos.org/System/procstat.htm 中有很好的记录;这是我的 4 核盒子上的样子:

Anderson cxc #  more /proc/stat
cpu  2329889 0 2364567 1063530460 9034 9463 96111 0
cpu0 572526 0 636532 265864398 2928 1621 6899 0
cpu1 590441 0 531079 265949732 4763 351 8522 0
cpu2 562983 0 645163 265796890 682 7490 71650 0
cpu3 603938 0 551790 265919440 660 0 9040 0
intr 37124247
ctxt 50795173133
btime 1218807985
processes 116889
procs_running 1
procs_blocked 0

首先,您需要确定系统中有多少 CPU(或处理器,或处理内核)可用。为此,请计算“cpuN”条目的数量,其中 N 从 0 开始并递增。不要计算 'cpu' 行,它是 cpuN 行的组合。在我的示例中,您可以看到 cpu0 到 cpu3,总共有 4 个处理器。从现在开始,您可以忽略 cpu0..cpu3,而只关注“cpu”行。

接下来,您需要知道这些行中的第四个数字是空闲时间的度量,因此“cpu”行上的第四个数字是自引导时间以来所有处理器的总空闲时间。这个时间以 Linux 的“jiffies”来衡量,每个时间是 1/100 秒。

但是您并不关心总空闲时间;您关心给定时间段内的空闲时间,例如最后一秒。计算一下,您需要读取此文件两次,相隔 1 秒。然后您可以对该行的第四个值进行比较。例如,如果您取样并获得:

cpu  2330047 0 2365006 1063853632 9035 9463 96114 0

然后一秒钟后你得到这个样本:

cpu  2330047 0 2365007 1063854028 9035 9463 96114 0

减去这两个数字,你会得到 396 的差异,这意味着你的 CPU 在最后 1.00 秒中空闲了 3.96 秒。当然,诀窍是您需要除以处理器的数量。 3.96 / 4 = 0.99,还有你的空闲百分比; 99% 空闲,1% 忙。

在我的代码中,我有一个包含 360 个条目的环形缓冲区,并且我每秒都会读取这个文件。这让我可以快速计算 1 秒、10 秒等的 CPU 利用率,一直到 1 小时。

对于特定于进程的信息,您必须查看 /proc/pid;如果你不关心你的 pid,你可以查看 /proc/self.

您的进程使用的 CPU 在 /proc/self/stat 中可用。这是一个由一行组成的看起来很奇怪的文件;例如:

19340 (whatever) S 19115 19115 3084 34816 19115 4202752 118200 607 0 0 770 384 2
 7 20 0 77 0 266764385 692477952 105074 4294967295 134512640 146462952 321468364
8 3214683328 4294960144 0 2147221247 268439552 1276 4294967295 0 0 17 0 0 0 0

这里的重要数据是第 13 个和第 14 个令牌(这里是 0 和 770)。第 13 个 token 是进程在用户态执行的 jiffies 数,第 14 个是进程在内核态执行的 jiffies 数。将两者相加,就得到了它的总 CPU 利用率。

同样,您必须定期对该文件进行采样,并计算差异,以确定进程随时间的 CPU 使用率。

编辑:请记住,当您计算进程的 CPU 利用率时,您必须考虑 1)进程中的线程数,以及 2)系统中的处理器数。例如,如果您的单线程进程仅使用 25% 的 CPU,那可能是好是坏。在单处理器系统上很好,但在 4 处理器系统上不好;这意味着您的进程不断运行,并使用 100% 的可用 CPU 周期。

对于特定于进程的内存信息,您可以查看 /proc/self/status,如下所示:

Name:   whatever
State:  S (sleeping)
Tgid:   19340
Pid:    19340
PPid:   19115
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0 1 2 3 4 6 10 11 20 26 27
VmPeak:   676252 kB
VmSize:   651352 kB
VmLck:         0 kB
VmHWM:    420300 kB
VmRSS:    420296 kB
VmData:   581028 kB
VmStk:       112 kB
VmExe:     11672 kB
VmLib:     76608 kB
VmPTE:      1244 kB
Threads:        77
SigQ:   0/36864
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: fffffffe7ffbfeff
SigIgn: 0000000010001000
SigCgt: 20000001800004fc
CapInh: 0000000000000000
CapPrm: 00000000ffffffff
CapEff: 00000000fffffeff
Cpus_allowed:   0f
Mems_allowed:   1
voluntary_ctxt_switches:        6518
nonvoluntary_ctxt_switches:     6598

以“Vm”开头的条目是有趣的:

VmPeak 是进程使用的最大虚拟内存空间,以 kB(1024 字节)为单位。

VmSize 是进程当前使用的虚拟内存空间,以 kB 为单位。在我的示例中,它非常大:651,352 kB,或大约 636 MB。

VmRss 是已映射到进程地址空间的内存量,或它的驻留集大小。这要小得多(420,296 kB,或大约 410 兆字节)。区别:我的程序通过 mmap() 映射了 636 MB,但只访问了其中的 410 MB,因此只分配了 410 MB 的页面。

我不确定的唯一项目是我的进程当前使用的交换空间。我不知道这是否可用。


谢谢 Martin,如果我将所有这些信息收集在一个地方,它会为我节省几个不眠之夜......但是,对于当前进程的 CPU,我认为 times() 函数是一种更简单、更可靠的方法。顺便说一句:当前进程的交换空间 = VmSize - VmRSS,不是吗?
M
Mark Lakata

Linux

sysinfo call

用法

   #include <sys/sysinfo.h>

   int sysinfo(struct sysinfo *info);

描述

   Until Linux 2.3.16, sysinfo() used to return information in the
   following structure:

       struct sysinfo {
           long uptime;             /* Seconds since boot */
           unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
           unsigned long totalram;  /* Total usable main memory size */
           unsigned long freeram;   /* Available memory size */
           unsigned long sharedram; /* Amount of shared memory */
           unsigned long bufferram; /* Memory used by buffers */
           unsigned long totalswap; /* Total swap space size */
           unsigned long freeswap;  /* swap space still available */
           unsigned short procs;    /* Number of current processes */
           char _f[22];             /* Pads structure to 64 bytes */
       };

   and the sizes were given in bytes.

   Since Linux 2.3.23 (i386), 2.3.48 (all architectures) the structure
   is:

       struct sysinfo {
           long uptime;             /* Seconds since boot */
           unsigned long loads[3];  /* 1, 5, and 15 minute load averages */
           unsigned long totalram;  /* Total usable main memory size */
           unsigned long freeram;   /* Available memory size */
           unsigned long sharedram; /* Amount of shared memory */
           unsigned long bufferram; /* Memory used by buffers */
           unsigned long totalswap; /* Total swap space size */
           unsigned long freeswap;  /* swap space still available */
           unsigned short procs;    /* Number of current processes */
           unsigned long totalhigh; /* Total high memory size */
           unsigned long freehigh;  /* Available high memory size */
           unsigned int mem_unit;   /* Memory unit size in bytes */
           char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding to 64 bytes */
       };

   and the sizes are given as multiples of mem_unit bytes.

P
Peter Mortensen

在 Windows 中,您可以通过以下代码获取 CPU 使用率:

#include <windows.h>
#include <stdio.h>

//------------------------------------------------------------------------------------------------------------------
// Prototype(s)...
//------------------------------------------------------------------------------------------------------------------
CHAR cpuusage(void);

//-----------------------------------------------------
typedef BOOL ( __stdcall * pfnGetSystemTimes)( LPFILETIME lpIdleTime, LPFILETIME lpKernelTime, LPFILETIME lpUserTime );
static pfnGetSystemTimes s_pfnGetSystemTimes = NULL;

static HMODULE s_hKernel = NULL;
//-----------------------------------------------------
void GetSystemTimesAddress()
{
    if(s_hKernel == NULL)
    {
        s_hKernel = LoadLibrary(L"Kernel32.dll");
        if(s_hKernel != NULL)
        {
            s_pfnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(s_hKernel, "GetSystemTimes");
            if(s_pfnGetSystemTimes == NULL)
            {
                FreeLibrary(s_hKernel);
                s_hKernel = NULL;
            }
        }
    }
}
//----------------------------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------------------------
// cpuusage(void)
// ==============
// Return a CHAR value in the range 0 - 100 representing actual CPU usage in percent.
//----------------------------------------------------------------------------------------------------------------
CHAR cpuusage()
{
    FILETIME               ft_sys_idle;
    FILETIME               ft_sys_kernel;
    FILETIME               ft_sys_user;

    ULARGE_INTEGER         ul_sys_idle;
    ULARGE_INTEGER         ul_sys_kernel;
    ULARGE_INTEGER         ul_sys_user;

    static ULARGE_INTEGER     ul_sys_idle_old;
    static ULARGE_INTEGER  ul_sys_kernel_old;
    static ULARGE_INTEGER  ul_sys_user_old;

    CHAR usage = 0;

    // We cannot directly use GetSystemTimes in the C language
    /* Add this line :: pfnGetSystemTimes */
    s_pfnGetSystemTimes(&ft_sys_idle,    /* System idle time */
        &ft_sys_kernel,  /* system kernel time */
        &ft_sys_user);   /* System user time */

    CopyMemory(&ul_sys_idle  , &ft_sys_idle  , sizeof(FILETIME)); // Could been optimized away...
    CopyMemory(&ul_sys_kernel, &ft_sys_kernel, sizeof(FILETIME)); // Could been optimized away...
    CopyMemory(&ul_sys_user  , &ft_sys_user  , sizeof(FILETIME)); // Could been optimized away...

    usage  =
        (
        (
        (
        (
        (ul_sys_kernel.QuadPart - ul_sys_kernel_old.QuadPart)+
        (ul_sys_user.QuadPart   - ul_sys_user_old.QuadPart)
        )
        -
        (ul_sys_idle.QuadPart-ul_sys_idle_old.QuadPart)
        )
        *
        (100)
        )
        /
        (
        (ul_sys_kernel.QuadPart - ul_sys_kernel_old.QuadPart)+
        (ul_sys_user.QuadPart   - ul_sys_user_old.QuadPart)
        )
        );

    ul_sys_idle_old.QuadPart   = ul_sys_idle.QuadPart;
    ul_sys_user_old.QuadPart   = ul_sys_user.QuadPart;
    ul_sys_kernel_old.QuadPart = ul_sys_kernel.QuadPart;

    return usage;
}


//------------------------------------------------------------------------------------------------------------------
// Entry point
//------------------------------------------------------------------------------------------------------------------
int main(void)
{
    int n;
    GetSystemTimesAddress();
    for(n=0; n<20; n++)
    {
        printf("CPU Usage: %3d%%\r", cpuusage());
        Sleep(2000);
    }
    printf("\n");
    return 0;
}

这可以修改为我以后可以在 c# 中调用的外部 DLL 函数吗?
usage = 的格式是我一段时间以来见过的最有创意的东西,完全不可读但很有创意
警告:上面代码中计算“使用量”的表达式已经过时了。如果系统空闲,它将除以零。如果空闲时间等于用户+内核时间,它将产生 0 而不是预期的 50%。
另外请记住,根据当前的 MSDN,内核时间还包括空闲时间!
@sayyedmohsenzahraee:我没有研究它的逻辑,只是对代码本身的评论。 1) 使用普通的 64 位变量而不是联合,即 VS 的 ULONGLONG 而不是 ULARGE_INTEGER。 2) 调用 CopyMemory() 使事情变得过于复杂,只需执行 ULONGLONG ul_sys_idle = *(ULONGLONG*)&ft_sys_idle;。它将被翻译成单个 CPU mov(或 lea)指令。
C
Community

QNX

由于这就像一个“代码维基页面”,我想从 QNX 知识库添加一些代码(注意:这不是我的工作,但我检查了它,它在我的系统上运行良好):

如何以 % 为单位获取 CPU 使用率:http://www.qnx.com/support/knowledgebase.html?id=50130000000P9b5

#include <atomic.h>
#include <libc.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/iofunc.h>
#include <sys/neutrino.h>
#include <sys/resmgr.h>
#include <sys/syspage.h>
#include <unistd.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/debug.h>
#include <sys/procfs.h>
#include <sys/syspage.h>
#include <sys/neutrino.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <devctl.h>
#include <errno.h>

#define MAX_CPUS 32

static float Loads[MAX_CPUS];
static _uint64 LastSutime[MAX_CPUS];
static _uint64 LastNsec[MAX_CPUS];
static int ProcFd = -1;
static int NumCpus = 0;


int find_ncpus(void) {
    return NumCpus;
}

int get_cpu(int cpu) {
    int ret;
    ret = (int)Loads[ cpu % MAX_CPUS ];
    ret = max(0,ret);
    ret = min(100,ret);
    return( ret );
}

static _uint64 nanoseconds( void ) {
    _uint64 sec, usec;
    struct timeval tval;
    gettimeofday( &tval, NULL );
    sec = tval.tv_sec;
    usec = tval.tv_usec;
    return( ( ( sec * 1000000 ) + usec ) * 1000 );
}

int sample_cpus( void ) {
    int i;
    debug_thread_t debug_data;
    _uint64 current_nsec, sutime_delta, time_delta;
    memset( &debug_data, 0, sizeof( debug_data ) );
    
    for( i=0; i<NumCpus; i++ ) {
        /* Get the sutime of the idle thread #i+1 */
        debug_data.tid = i + 1;
        devctl( ProcFd, DCMD_PROC_TIDSTATUS,
        &debug_data, sizeof( debug_data ), NULL );
        /* Get the current time */
        current_nsec = nanoseconds();
        /* Get the deltas between now and the last samples */
        sutime_delta = debug_data.sutime - LastSutime[i];
        time_delta = current_nsec - LastNsec[i];
        /* Figure out the load */
        Loads[i] = 100.0 - ( (float)( sutime_delta * 100 ) / (float)time_delta );
        /* Flat out strange rounding issues. */
        if( Loads[i] < 0 ) {
            Loads[i] = 0;
        }
        /* Keep these for reference in the next cycle */
        LastNsec[i] = current_nsec;
        LastSutime[i] = debug_data.sutime;
    }
    return EOK;
}

int init_cpu( void ) {
    int i;
    debug_thread_t debug_data;
    memset( &debug_data, 0, sizeof( debug_data ) );
/* Open a connection to proc to talk over.*/
    ProcFd = open( "/proc/1/as", O_RDONLY );
    if( ProcFd == -1 ) {
        fprintf( stderr, "pload: Unable to access procnto: %s\n",strerror( errno ) );
        fflush( stderr );
        return -1;
    }
    i = fcntl(ProcFd,F_GETFD);
    if(i != -1){
        i |= FD_CLOEXEC;
        if(fcntl(ProcFd,F_SETFD,i) != -1){
            /* Grab this value */
            NumCpus = _syspage_ptr->num_cpu;
            /* Get a starting point for the comparisons */
            for( i=0; i<NumCpus; i++ ) {
                /*
                * the sutime of idle thread is how much
                * time that thread has been using, we can compare this
                * against how much time has passed to get an idea of the
                * load on the system.
                */
                debug_data.tid = i + 1;
                devctl( ProcFd, DCMD_PROC_TIDSTATUS, &debug_data, sizeof( debug_data ), NULL );
                LastSutime[i] = debug_data.sutime;
                LastNsec[i] = nanoseconds();
            }
            return(EOK);
        }
    }
    close(ProcFd);
    return(-1);
}

void close_cpu(void){
    if(ProcFd != -1){
        close(ProcFd);
        ProcFd = -1;
    }
}

int main(int argc, char* argv[]){
    int i,j;
    init_cpu();
    printf("System has: %d CPUs\n", NumCpus);
    for(i=0; i<20; i++) {
        sample_cpus();
        for(j=0; j<NumCpus;j++)
        printf("CPU #%d: %f\n", j, Loads[j]);
        sleep(1);
    }
    close_cpu();
}

如何获得空闲 (!) 内存:http://www.qnx.com/support/knowledgebase.html?id=50130000000mlbx

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <err.h>
#include <sys/stat.h>
#include <sys/types.h>

int main( int argc, char *argv[] ){
    struct stat statbuf;
    paddr_t freemem;
    stat( "/proc", &statbuf );
    freemem = (paddr_t)statbuf.st_size;
    printf( "Free memory: %d bytes\n", freemem );
    printf( "Free memory: %d KB\n", freemem / 1024 );
    printf( "Free memory: %d MB\n", freemem / ( 1024 * 1024 ) );
    return 0;
} 

P
Peter Mortensen

Mac OS X - 中央处理器

总体 CPU 使用率:

来自 Retrieve system information on Mac OS X

#include <mach/mach_init.h>
#include <mach/mach_error.h>
#include <mach/mach_host.h>
#include <mach/vm_map.h>

static unsigned long long _previousTotalTicks = 0;
static unsigned long long _previousIdleTicks = 0;

// Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
// You'll need to call this at regular intervals, since it measures the load between
// the previous call and the current one.
float GetCPULoad()
{
   host_cpu_load_info_data_t cpuinfo;
   mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
   if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuinfo, &count) == KERN_SUCCESS)
   {
      unsigned long long totalTicks = 0;
      for(int i=0; i<CPU_STATE_MAX; i++) totalTicks += cpuinfo.cpu_ticks[i];
      return CalculateCPULoad(cpuinfo.cpu_ticks[CPU_STATE_IDLE], totalTicks);
   }
   else return -1.0f;
}

float CalculateCPULoad(unsigned long long idleTicks, unsigned long long totalTicks)
{
  unsigned long long totalTicksSinceLastTime = totalTicks-_previousTotalTicks;
  unsigned long long idleTicksSinceLastTime  = idleTicks-_previousIdleTicks;
  float ret = 1.0f-((totalTicksSinceLastTime > 0) ? ((float)idleTicksSinceLastTime)/totalTicksSinceLastTime : 0);
  _previousTotalTicks = totalTicks;
  _previousIdleTicks  = idleTicks;
  return ret;
}

P
Peter Mortensen

对于 Linux

您还可以使用 /proc/self/statm 获取包含关键进程内存信息的单行数字,这比从 proc/self/status 获得的一长串报告信息处理起来更快

请参阅proc(5)

/proc/[pid]/statm

    Provides information about memory usage, measured in pages.
    The columns are:

        size       (1) total program size
                   (same as VmSize in /proc/[pid]/status)
        resident   (2) resident set size
                   (same as VmRSS in /proc/[pid]/status)
        shared     (3) number of resident shared pages (i.e., backed by a file)
                   (same as RssFile+RssShmem in /proc/[pid]/status)
        text       (4) text (code)
        lib        (5) library (unused since Linux 2.6; always 0)
        data       (6) data + stack
        dt         (7) dirty pages (unused since Linux 2.6; always 0)

有人知道页面中报告的总大小有多可靠吗?这是内存中的实际足迹吗?
P
Peter Mortensen

在 Linux 上,您不能/不应该使用 SysInfo 的 freeram 或通过对 totalram 进行一些算术来获得“总可用物理内存”。

推荐的方法是阅读 proc/meminfo,引用 kernel/git/torvalds/linux.git, /proc/meminfo: provide estimated available memory

许多负载平衡和工作负载放置程序检查 /proc/meminfo 以估计有多少可用内存。他们通常通过将“免费”和“缓存”相加来做到这一点,十年前这很好,但今天几乎可以保证是错误的。

在 /proc/meminfo 中提供这样的估计会更方便。如果将来事情发生变化,我们只需在一个地方进行更改。

一种方法是按照 Adam Rosenfield's answer to How do you determine the amount of Linux system RAM in C++? 的建议:读取文件,然后使用 fscanf 抓取该行(但不要使用 MemTotal,而是使用 MemAvailable)

同样,如果您想获得使用的物理内存总量,具体取决于“使用”的含义,您可能不想从 totalram 中减去 freeram,而是从 memtotal 中减去 memavailable 以获得 top 或 htop 告诉您的内容。


M
Michael Benjamin

我在我的 C++ 项目中使用了以下代码,它运行良好:

static HANDLE self;
static int numProcessors;
SYSTEM_INFO sysInfo;

double percent;

numProcessors = sysInfo.dwNumberOfProcessors;

//Getting system times information
FILETIME SysidleTime;
FILETIME SyskernelTime; 
FILETIME SysuserTime; 
ULARGE_INTEGER SyskernelTimeInt, SysuserTimeInt;
GetSystemTimes(&SysidleTime, &SyskernelTime, &SysuserTime);
memcpy(&SyskernelTimeInt, &SyskernelTime, sizeof(FILETIME));
memcpy(&SysuserTimeInt, &SysuserTime, sizeof(FILETIME));
__int64 denomenator = SysuserTimeInt.QuadPart + SyskernelTimeInt.QuadPart;  

//Getting process times information
FILETIME ProccreationTime, ProcexitTime, ProcKernelTime, ProcUserTime;
ULARGE_INTEGER ProccreationTimeInt, ProcexitTimeInt, ProcKernelTimeInt, ProcUserTimeInt;
GetProcessTimes(self, &ProccreationTime, &ProcexitTime, &ProcKernelTime, &ProcUserTime);
memcpy(&ProcKernelTimeInt, &ProcKernelTime, sizeof(FILETIME));
memcpy(&ProcUserTimeInt, &ProcUserTime, sizeof(FILETIME));
__int64 numerator = ProcUserTimeInt.QuadPart + ProcKernelTimeInt.QuadPart;
//QuadPart represents a 64-bit signed integer (ULARGE_INTEGER)

percent = 100*(numerator/denomenator);

您没有通过这种机制获得 0.00% 和超过 100% 的值吗?
这适用于 Mac OS 吗?
@RuLoViC 适用于 Windows。
也为我工作。我正在使用 Win64,Ver10
我一直只得到0.00。在 x64 应用程序上在 Win 10 x64 上测试。