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

我曾经负责从正在运行的应用程序中确定以下性能参数:

  • 总虚拟可用存储器
  • 当前使用的虚拟内存
  • 我的进程当前使用的虚拟内存
  • 可用RAM总数
  • 当前使用的RAM
  • 我的进程当前使用的RAM
  • 当前使用的CPU%
  • 我的进程当前使用的%CPU

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

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

398545 次浏览

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;
    }
    

待办事项:其他平台

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

Linux

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

但在这里可以找到您想要的信息:

/proc/meminfo包含您查找的大部分系统范围的信息。在这里,它看起来像在我的系统上;我想你对MemTotalMemFree小单金额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个令牌是进程在用户模式下执行的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”开头的条目是有趣的条目:

  • VM峰值是进程使用的最大虚拟内存空间,以kB(1024字节)为单位。
  • vmsize是进程当前使用的虚拟内存空间,以kB为单位。在我的示例中,它非常大:651,352 kB,或约636兆字节。
  • vmrss是已映射到进程地址空间的内存量,或其常驻集大小。这要小得多(420,296 kB,约410兆字节)。区别在于:我的程序通过mmap()映射了636 MB,但只访问了其中的410 MB,因此只有410 MB的页面被分配给它。

我唯一不确定的是我的进程当前使用的Swapspace。我不知道这个是否可用。

macosx

总虚拟内存

这个在Mac OS X上很棘手,因为它不使用像Linux这样的预设交换分区或文件。

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

因此,如果您想知道还有多少虚拟内存可用,您需要获取根分区的大小。您可以这样做:

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

当前使用的虚拟总数

使用“vm.swapusage”键调用系统提供了有关交换使用情况的有趣信息:

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);

当前使用的RAM

您可以从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中有五种类型的内存页。它们如下所示:

  1. 有线页面被锁定在适当的位置,不能被交换出去
  2. 活跃正在加载到物理内存中并且相对难以交换的页面
  3. 不活动页面已加载到内存中,但最近没有使用,甚至可能根本不需要。这些是潜在的交换候选者。此内存可能需要刷新。
  4. 缓存页面已经被缓存了一些可能很容易重用的页面。缓存的内存可能不需要刷新。缓存的页面仍然有可能被重新激活
  5. 免费页面是完全免费的,随时可以使用。

值得注意的是,仅仅因为Mac OS X有时可能会显示很少的实际可用内存,所以它可能无法很好地指示在短时间内准备使用多少内存。

我的进程当前使用的RAM

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

在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;
}

QNX

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

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

#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;
}

Linux

读取内存和加载号的便携式方法是sysinfo调用

用法

   #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.

我在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);

为了Linux

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

查看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)

Mac OS X-CPU

整体CPU使用率:

来自在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;
}

在Linux,你不能/不应该得到“总可用物理内存”与SysInfo的freeram或做一些算术上的极值。

推荐的方法是阅读proc/meminfo,引用内核/git/torvalds/linux.git,/proc/meminfo:提供估计的可用内存

许多负载平衡和工作负载放置程序检查 /proc/meminfo 估计有多少空闲内存可用。他们通常通过 将“免费”和“缓存”相加,十年前还不错,但现在 今天肯定是错的。

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

一种方法是Adam Rosenfield对的回答如何确定C++中Linux系统RAM的数量?/em>建议:读取文件,并使用fscanf抓取行(但不是使用MemTotal,而是使用Mem可用)

同样地,如果你想得到使用的物理内存总量,这取决于你所说的“使用”是什么意思,你可能不想从极速内存中减去freeram,而是从mem的总内存中减去可用内存,以获得top或htop告诉你的信息。