首页 文章

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

提问于
浏览
505

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

  • 可用的虚拟内存总量

  • 当前使用的虚拟内存

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


  • 总RAM可用

  • 目前使用的RAM

  • 我的进程当前使用的RAM


  • %CPU当前使用

  • %我的进程当前使用的CPU

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

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

9 回答

  • 551

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

    http://man7.org/linux/man-pages/man5/proc.5.html

    /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)
    
  • 130

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

    Mac OS X - CPU

    总CPU使用率:

    来自Retrieve system information on MacOS 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;
    }
    
  • 0

    Mac OS X.

    我希望也能为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);
    

    目前使用的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中有五种类型的内存页面 . 它们如下:

    • Wired 已锁定到位且无法换出的页面

    • Active 页面正在加载到物理内存中并且相对难以换出

    • Inactive 页面已加载到内存中,但最近未使用过,甚至可能根本不需要 . 这些是交换的潜在候选人 . 这个内存可能需要刷新 .

    • Cached 页面已经过一些可能很容易被重用的缓存 . 缓存内存可能不需要刷新 . 仍然可以重新激活缓存页面

    • Free 页面完全免费且可以使用 .

    值得注意的是,仅仅因为Mac OS X有时可能显示的实际空闲内存非常少,因此可能无法很好地指示在短时间内可以使用多少内存 .

    我的进程当前使用的RAM

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

  • 11

    Linux

    在Linux中,此信息在/ proc文件系统中可用 . 我不是所用文本文件格式的忠实粉丝,因为每个Linux发行版似乎都自定义了至少一个重要文件 . 快速浏览“ps”的来源可以揭示混乱局面 .

    但是,这里可以找到您寻找的信息:

    /proc/meminfo 包含您寻求的大多数系统范围的信息 . 在我的系统上看起来像;我想你对 MemTotalMemFreeSwapTotalSwapFree 感兴趣:

    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条目的环形缓冲区,我每秒都读取这个文件 . 这让我可以快速计算CPU利用率1秒,10秒等,一直到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使用情况 .

    Edit: 请记住,在计算进程的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兆字节 .

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

    我不确定的唯一项目是 Swapspace currently used by my process . 我不知道这是否可用 .

  • 0

    Windows

    上面的一些值可以从相应的WIN32 API轻松获得,我只是在这里列出它们的完整性 . 然而,其他人需要从性能数据助手库(PDH)获得,这有点“不直观”并且需要大量痛苦的试验和错误才能开始工作 . (至少它花了我一段时间,也许我只是有点愚蠢......)

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

    • 虚拟内存总量:
    #include "windows.h"
    
    MEMORYSTATUSEX memInfo;
    memInfo.dwLength = sizeof(MEMORYSTATUSEX);
    GlobalMemoryStatusEx(&memInfo);
    DWORDLONG totalVirtualMem = memInfo.ullTotalPageFile;
    

    注意:名称“TotalPageFile”在这里有点误导 . 实际上,此参数提供“虚拟内存大小”,即交换文件的大小加上已安装的RAM .

    • 目前使用的虚拟内存:

    与“Total Virtual Memory”中的代码相同,然后

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

    与“Total Virtual Memory”中的代码相同,然后

    DWORDLONG totalPhysMem = memInfo.ullTotalPhys;
    
    • 物理目前使用的内存:
    Same code as in "Total Virtual Memory" and then
    
    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;
    
    • 目前使用的虚拟内存:

    与“Total Virtual Memory”中的代码相同,然后

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

    与“Total Virtual Memory”中的代码相同,然后

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

    与“Total Virtual Memory”中的代码相同,然后

    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技术人员可以编辑这个答案并填写详细信息?!

  • 3

    in windows you can get cpu usage by code bellow:

    #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 on 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;
        }
    
  • 1

    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.
    
  • 57

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

相关问题