使用Proc文件计算CPU使用率%
Calculating %CPU Usage Using Proc Files
我想在我的程序中指定一个线程来收集有关其性能的指标。内存使用情况,CPU等。我一直在尝试使用/proc/stat和/proc/pid/stat文件来做到这一点。我目前正在尝试测量CPU使用百分比。我的程序报告的值与"top"报告的值完全不一致。我在几个不同的linux发行版上尝试了这个,并且在每个发行版上都看到了相同的结果。
这是我用来计算百分比的代码。有人能发现问题吗?https://github.com/mmcilroy/cpu_usage#include <stdlib.h>
#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct pstat {
long unsigned int utime_ticks;
long int cutime_ticks;
long unsigned int stime_ticks;
long int cstime_ticks;
long unsigned int vsize; // virtual memory size in bytes
long unsigned int rss; //Resident Set Size in bytes
long unsigned int cpu_total_time;
};
int get_usage(const pid_t pid, struct pstat* result) {
//convert pid to string
char pid_s[20];
snprintf(pid_s, sizeof(pid_s), "%d", pid);
char stat_filepath[30] = "/proc/"; strncat(stat_filepath, pid_s,
sizeof(stat_filepath) - strlen(stat_filepath) -1);
strncat(stat_filepath, "/stat", sizeof(stat_filepath) -
strlen(stat_filepath) -1);
FILE *fpstat = fopen(stat_filepath, "r");
if (fpstat == NULL) {
perror("FOPEN ERROR ");
return -1;
}
FILE *fstat = fopen("/proc/stat", "r");
if (fstat == NULL) {
perror("FOPEN ERROR ");
fclose(fstat);
return -1;
}
//read values from /proc/pid/stat
bzero(result, sizeof(struct pstat));
long int rss;
if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu"
"%lu %ld %ld %*d %*d %*d %*d %*u %lu %ld",
&result->utime_ticks, &result->stime_ticks,
&result->cutime_ticks, &result->cstime_ticks, &result->vsize,
&rss) == EOF) {
fclose(fpstat);
return -1;
}
fclose(fpstat);
result->rss = rss * getpagesize();
//read+calc cpu total time from /proc/stat
long unsigned int cpu_time[10];
bzero(cpu_time, sizeof(cpu_time));
if (fscanf(fstat, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&cpu_time[0], &cpu_time[1], &cpu_time[2], &cpu_time[3],
&cpu_time[4], &cpu_time[5], &cpu_time[6], &cpu_time[7],
&cpu_time[8], &cpu_time[9]) == EOF) {
fclose(fstat);
return -1;
}
fclose(fstat);
for(int i=0; i < 4;i++)
result->cpu_total_time += cpu_time[i];
printf( "usage: cpu %lu, utime %lu, stime %lun", result->cpu_total_time, result->utime_ticks, result->stime_ticks );
return 0;
}
void calc_cpu_usage_pct(const struct pstat* cur_usage,
const struct pstat* last_usage,
double* usage)
{
printf( "delta: cpu %lu, utime %lu, stime %lun",
cur_usage->cpu_total_time - last_usage->cpu_total_time,
cur_usage->utime_ticks - last_usage->utime_ticks,
cur_usage->stime_ticks - last_usage->stime_ticks );
const long unsigned int cpu_diff = cur_usage->cpu_total_time - last_usage->cpu_total_time;
const long unsigned int pid_diff =
( cur_usage->utime_ticks + cur_usage->utime_ticks + cur_usage->stime_ticks - cur_usage->stime_ticks ) -
( last_usage->utime_ticks + last_usage->utime_ticks + last_usage->stime_ticks - last_usage->stime_ticks );
*usage = 100.0 * ( (double)pid_diff / (double)cpu_diff );
}
int main( int argc, char* argv[] )
{
pstat prev, curr;
double pct;
struct tms t;
times( &t );
if( argc <= 1 ) {
printf( "please supply a pidn" ); return 1;
}
while( 1 )
{
if( get_usage(atoi(argv[1]), &prev) == -1 ) {
printf( "errorn" );
}
sleep( 5 );
if( get_usage(atoi(argv[1]), &curr) == -1 ) {
printf( "errorn" );
}
calc_cpu_usage_pct(&curr, &prev, &pct);
printf("%%cpu: %.02fn", pct);
}
}
如果您想亲自尝试一下,该程序需要1个参数—要监视的进程的pid
我知道这有点老了,但我可以解释为什么你的新方程有效:(1/INTERVAL) * (pid diff)
这只是一个基本的百分比方程100 * (pid diff) / (cpu diff)
的简化,看起来像你在第一个例子中试图做的。
/proc/stat中的cpu时间(以及/proc/pid/stat中的utime和stime)以USER_HZ(或jiffies)报告。该值为,通常为 1/100秒。这意味着CPU每秒将有100个"tics",这意味着您的"CPU diff"将为INTERVAL*100
。
代入,得到:
100 * (pid diff)/(INTERVAL * 100)
消去100,剩下:
(pid diff)/INTERVAL
与您现在使用的相同。这也意味着,如果您确实纠正了上面代码中的问题,那么应该也能正常工作。pid值应该是(curr utime + curr stime) - (prev utime + prev stime)
。如果它不工作,那么也许你加CPU时间的方式是错误的?这很容易测试,因为你知道它应该是什么值(INTERVAL*100)
。
既然你现在有一个工作方程,你可能不关心找出原来的代码的问题,但请记住,如果你曾经试图在一个系统上使用它,USER_HZ是不是 1/100,方程将无效
我检查了top的源代码(来自procps)。似乎它实际上是在执行以下计算…
(1/interval) * (utime+stime)
其中interval为采样之间的秒数。Utime/stime直接从/proc/pid/stat
读取我必须承认我不明白为什么这会起作用(它不应该根据"man proc"),但我已经在许多不同的场景下测试了它,我的程序的输出总是与"top"匹配。
我有兴趣听到一些关于为什么这个工作的反馈:)
这是我的最新来源
#include <stdlib.h>
#include <sys/types.h>
#include <sys/times.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define INTERVAL 3
struct pstat {
long unsigned int utime_ticks;
long int cutime_ticks;
long unsigned int stime_ticks;
long int cstime_ticks;
long unsigned int vsize; // virtual memory size in bytes
long unsigned int rss; //Resident Set Size in bytes
};
int get_usage(const pid_t pid, struct pstat* result) {
//convert pid to string
char pid_s[20];
snprintf(pid_s, sizeof(pid_s), "%d", pid);
char stat_filepath[30] = "/proc/"; strncat(stat_filepath, pid_s,
sizeof(stat_filepath) - strlen(stat_filepath) -1);
strncat(stat_filepath, "/stat", sizeof(stat_filepath) -
strlen(stat_filepath) -1);
FILE *fpstat = fopen(stat_filepath, "r");
if (fpstat == NULL) {
perror("FOPEN ERROR ");
return -1;
}
//read values from /proc/pid/stat
bzero(result, sizeof(struct pstat));
long int rss;
if (fscanf(fpstat, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %lu"
"%lu %ld %ld %*d %*d %*d %*d %*u %lu %ld",
&result->utime_ticks, &result->stime_ticks,
&result->cutime_ticks, &result->cstime_ticks, &result->vsize,
&rss) == EOF) {
fclose(fpstat);
return -1;
}
fclose(fpstat);
result->rss = rss * getpagesize();
return 0;
}
void calc_cpu_usage_pct(const struct pstat* cur_usage,
const struct pstat* last_usage,
double* usage)
{
const long unsigned int pid_diff =
( cur_usage->utime_ticks + cur_usage->stime_ticks ) -
( last_usage->utime_ticks + last_usage->stime_ticks );
printf( "delta %lun", pid_diff );
*usage = 1/(float)INTERVAL * pid_diff;
}
int main( int argc, char* argv[] )
{
pstat prev, curr;
double pct;
struct tms t;
times( &t );
if( argc <= 1 ) {
printf( "please supply a pidn" ); return 1;
}
while( 1 )
{
if( get_usage(atoi(argv[1]), &prev) == -1 ) {
printf( "errorn" );
}
sleep( INTERVAL );
if( get_usage(atoi(argv[1]), &curr) == -1 ) {
printf( "errorn" );
}
calc_cpu_usage_pct(&curr, &prev, &pct);
printf("%%cpu: %.02fn", pct);
}
}
这个命令在linux中可能对linux有用。
# apt-get install sysstat
# up2date sysstat
# mpstat
现在您了解了如何获取命令行输出作为字符串并进行解析。您也可以使用mpstat的不同参数。也可以试试$ top
。
主循环有点不对劲:不是得到"prev",然后睡觉,然后得到"next"并计算差值,你应该在循环外得到"prev"一次,在循环内得到"curr",计算,将"curr"复制到"prev"中,然后再次循环。这修复了50%的使用时间没有被计算的部分。
尝试查看top命令源代码,源代码将在busybox中提供
编辑:将mpstat替换为top,因为mpstat显示总体使用
- 编写一个函数以使用 n 百分比的 CPU 使用率
- 对于等待以 std::future wait() 返回的函数的 CPU 使用率或检查标志在循环中休眠一段时间哪个更好?
- 如何降低应用程序的 CPU 使用率?
- 如何以编程方式获取任务管理器进程CPU使用率(不是PerfMon API)
- 一段时间后 CPU 使用率高
- 高CPU使用率,在API桌面复制中获取帧之间具有不同的超时间隔
- GetDC ReleaseDC 在特定上下文中的高 CPU 使用率
- 从 C++11 代码中获取系统内存和 CPU 使用率
- 在 Visual Studio 中记录 CPU 使用率
- C++如何允许等待而不会过多的 CPU 使用率
- Qtcreator 冻结,CPU 使用率为 100%
- 使用 fgets() c++ 读取大型 txt 文件时的 CPU 使用率为 99%
- OpenCL 的 CPU 使用率意外
- Loop Wregex始终返回false和高CPU使用率约50%
- 简单的C++SFML程序高CPU使用率
- 使用 PID 获取内存和 CPU 使用率
- 如何在TCP端口上实时传输数据期间减少CPU使用率
- WinAPI:在WM_PAINT省略 BeginPaint 和 EndPaint 会导致 100% 的 CPU 使用率
- 当CPU使用率高时,OpenCV会堆积内存吗
- 如何在运行SDL程序时降低CPU使用率