ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【C++】Rusage(一) [打印本页]

作者: 瑞星    时间: 前天 21:45
标题: 【C++】Rusage(一)
本文介绍C++中几个统计程序内存数据的方式:<sys/resource.h>(Unix/Linux)、GetProcessTimes(Windows)
<sys/resource.h>

介绍

<sys/resource.h> 是一个 Unix 或类 Unix 系统(如 Linux、macOS)提供的头文件,用于获取进程资源使用环境等信息。实测它无法在Windows上用,就算你用的MingW也不行。

rusage 布局体的定义如下:
  1. struct rusage {
  2.     struct timeval ru_utime
  3. ; /* user CPU time used */
  4.     struct timeval ru_stime
  5. ; /* system CPU time used */
  6.     long   ru_maxrss;        /* maximum resident set size */
  7.     long   ru_ixrss;         /* integral shared memory size */
  8.     long   ru_idrss;         /* integral unshared data size */
  9.     long   ru_isrss;         /* integral unshared stack size */
  10.     long   ru_minflt;        /* page reclaims (soft page faults) */
  11.     long   ru_majflt;        /* page faults (hard page faults) */
  12.     long   ru_nswap;         /* swaps */
  13.     long   ru_inblock;       /* block input operations */
  14.     long   ru_oublock;       /* block output operations */
  15.     long   ru_msgsnd;        /* messages sent */
  16.     long   ru_msgrcv;        /* messages received */
  17.     long   ru_nsignals;      /* signals received */
  18.     long   ru_nvcsw;         /* voluntary context switches */
  19.     long   ru_nivcsw;        /* involuntary context switches */
  20. };
复制代码
每一个成员都对应一个当前进程的内容,比如:
  1. struct timeval ru_utime
复制代码

  1. struct timeval ru_stime
复制代码

  1. long ru_maxrss
复制代码

  1. long ru_ixrss
复制代码

  1. long ru_idrss
复制代码

  1. long ru_isrss
复制代码

  1. long ru_minflt
复制代码

  1. long ru_majflt
复制代码

  1. long ru_nswap
复制代码

  1. long ru_inblock
复制代码

  1. long ru_oublock
复制代码

  1. long ru_msgsnd
复制代码

  1. long ru_msgrcv
复制代码

  1. long ru_nsignals
复制代码

  1. long ru_nvcsw
复制代码

  1. long ru_nivcsw
复制代码

使用

getrusage 函数用于获取指定进程的资源使用信息,其源代码(接口)如下:
  1. /* Return resource usage information on process indicated by WHO
  2.    and put it in *USAGE.  Returns 0 for success, -1 for failure.  */
  3. extern int getrusage (__rusage_who_t __who, struct rusage *__usage) __THROW;
复制代码

返回值为0时调用成功,-1时失败。可以写个简单的代码测试调用:
  1. #include <iostream>
  2. #include <sys/resource.h>
  3. #include <sys/time.h>
  4. // 打印 rusage 结构体中的信息
  5. void print_rusage(const struct rusage& usage) {
  6.     // 用户模式下使用的 CPU 时间
  7.     std::cout << "用户模式下使用的 CPU 时间:"
  8.               << usage.ru_utime.tv_sec << " 秒 "
  9.               << usage.ru_utime.tv_usec << " 微秒" << std::endl;
  10.     // 内核模式下使用的 CPU 时间
  11.     std::cout << "内核模式下使用的 CPU 时间:"
  12.               << usage.ru_stime.tv_sec << " 秒 "
  13.               << usage.ru_stime.tv_usec << " 微秒" << std::endl;
  14.     // 进程使用的最大驻留集大小(以 KB 为单位)
  15.     std::cout << "进程使用的最大驻留集大小:" << usage.ru_maxrss << " KB" << std::endl;
  16.     // 进程使用的共享内存的积分值
  17.     std::cout << "进程使用的共享内存的积分值:" << usage.ru_ixrss << std::endl;
  18.     // 进程使用的非共享数据段的积分值
  19.     std::cout << "进程使用的非共享数据段的积分值:" << usage.ru_idrss << std::endl;
  20.     // 进程使用的非共享栈段的积分值
  21.     std::cout << "进程使用的非共享栈段的积分值:" << usage.ru_isrss << std::endl;
  22.     // 软页面错误(Page Reclaims)的次数
  23.     std::cout << "软页面错误的次数:" << usage.ru_minflt << std::endl;
  24.     // 硬页面错误(Page Faults)的次数
  25.     std::cout << "硬页面错误的次数:" << usage.ru_majflt << std::endl;
  26.     // 进程被交换出物理内存的次数
  27.     std::cout << "进程被交换出物理内存的次数:" << usage.ru_nswap << std::endl;
  28.     // 进程执行的块输入操作次数
  29.     std::cout << "进程执行的块输入操作次数:" << usage.ru_inblock << std::endl;
  30.     // 进程执行的块输出操作次数
  31.     std::cout << "进程执行的块输出操作次数:" << usage.ru_oublock << std::endl;
  32.     // 进程发送的消息数量
  33.     std::cout << "进程发送的消息数量:" << usage.ru_msgsnd << std::endl;
  34.     // 进程接收的消息数量
  35.     std::cout << "进程接收的消息数量:" << usage.ru_msgrcv << std::endl;
  36.     // 进程接收到的信号数量
  37.     std::cout << "进程接收到的信号数量:" << usage.ru_nsignals << std::endl;
  38.     // 进程自愿进行上下文切换的次数
  39.     std::cout << "进程自愿进行上下文切换的次数:" << usage.ru_nvcsw << std::endl;
  40.     // 进程非自愿进行上下文切换的次数
  41.     std::cout << "进程非自愿进行上下文切换的次数:" << usage.ru_nivcsw << std::endl;
  42. }
  43. int main() {
  44.     struct rusage usage;
  45.     // 获取当前进程的资源使用信息
  46.     if (getrusage(RUSAGE_SELF, &usage) == 0) {
  47.         std::cout << "当前进程的资源使用信息:" << std::endl;
  48.         print_rusage(usage);
  49.     } else {
  50.         std::cerr << "获取资源使用信息失败。" << std::endl;
  51.         return 1;
  52.     }
  53.     return 0;
  54. }
复制代码
一次运行的效果:

<windows.h>

Windows上并没有雷同rusage这种工具,但是也提供了一些工具来辅助分析程序。比如可以使用GetProcessTimes函数来获取进程的用户模式和内核模式 CPU 时间:
  1. WINBASEAPI
  2. BOOL
  3. WINAPI
  4. GetProcessTimes(
  5.     _In_ HANDLE hProcess,
  6.     _Out_ LPFILETIME lpCreationTime,
  7.     _Out_ LPFILETIME lpExitTime,
  8.     _Out_ LPFILETIME lpKernelTime,
  9.     _Out_ LPFILETIME lpUserTime
  10.     );
  11. WINBASEAPI
  12. HANDLE
  13. WINAPI
  14. GetCurrentProcess(
  15.     VOID
  16.     );
复制代码
GetProcessTimes函数用于获取指定进程的创建时间、退出时间、内核模式 CPU 时间和用户模式 CPU 时间。数据泉源是进程的handler指针,可以通过GetCurrentProcess获得。
FILETIME 布局体用于表现一个特定的时间,使用两个 32 位的 DWORD 值(dwLowDateTime 和 dwHighDateTime)来表现一个 64 位的时间戳。为了方便处理这个 64 位时间戳,通常会将 FILETIME 布局体的值转换为 ULARGE_INTEGER 范例,其定义如下:
  1. typedef struct _FILETIME {
  2.     DWORD dwLowDateTime;
  3.     DWORD dwHighDateTime;
  4. } FILETIME, *PFILETIME, *LPFILETIME;
复制代码
ULARGE_INTEGER 是 Windows API 中定义的一个布局体,用于表现一个 64 位无符号整数。其定义如下:
  1. typedef union _ULARGE_INTEGER {
  2.     struct {
  3.         DWORD LowPart;
  4.         DWORD HighPart;
  5.     } DUMMYSTRUCTNAME;
  6.     struct {
  7.         DWORD LowPart;
  8.         DWORD HighPart;
  9.     } u;
  10.     ULONGLONG QuadPart;
  11. } ULARGE_INTEGER;
复制代码
从定义可以看出,ULARGE_INTEGER 是一个团结体(union),这意味着 LowPart、HighPart 和 QuadPart 共享同一块内存空间。具体关系如下:

在早期的 Windows 系统中,部分硬件平台可能不直接支持 64 位整数运算。通过将 64 位整数拆分为高 32 位(HighPart)和低 32 位(LowPart),可以在不支持 64 位运算的环境下,使用 32 位运算来模仿 64 位运算。如允许以确保代码在差别的硬件平台和操作系统版本上都能正常工作。
最后我们可以写出如下的代码:
  1. #include <iostream>
  2. #include <windows.h>
  3. void printProcessCPUTime() {
  4.     HANDLE hProcess = GetCurrentProcess();
  5.     FILETIME creationTime, exitTime, kernelTime, userTime;
  6.     if (GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime)) {
  7.         ULARGE_INTEGER kernelTimeValue, userTimeValue;
  8.         kernelTimeValue.LowPart = kernelTime.dwLowDateTime;
  9.         kernelTimeValue.HighPart = kernelTime.dwHighDateTime;
  10.         userTimeValue.LowPart = userTime.dwLowDateTime;
  11.         userTimeValue.HighPart = userTime.dwHighDateTime;
  12.         std::cout << "Kernel mode CPU time: " << kernelTimeValue.QuadPart / 10000000.0 << " seconds" << std::endl;
  13.         std::cout << "User mode CPU time: " << userTimeValue.QuadPart / 10000000.0 << " seconds" << std::endl;
  14.     } else {
  15.         std::cerr << "Failed to get process CPU time." << std::endl;
  16.     }
  17. }
  18. int main() {
  19.     printProcessCPUTime();
  20.     return 0;
  21. }
复制代码
一个运行的效果如下:


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4