linux下監控一個進程的cpu使用率
2015/11/14 15:31
瀏覽218
迴響0
推薦0
引用0
一、問題的提出:
前一陣子由於工作的需要正在學習關於系統資源監控方面的一些知識!由於本人的水平比較的有限,所以也是翻閱了比較多的書籍,包括查閱了top命令的源代碼,大致上知道我們要獲取的監控數據,完全可以從proc中讀取出來,現為了簡單的描述一下解決問題的過程,在這裏我們假設有這樣一個問題:如何監控firefox這個應用程序的cpu使用率?
二、問題的分析:
問題提出來了,我們應該如何著手呢?
首先,我們通過查閱相關的資料知道了可以從proc中獲取我們的數據。所以我就先去proc下面去看看我們要找的東西在哪裏?
cd /proc
ls
我們會看到如下的一些東西:
1 1541 1899 2062 2365 35 7 cpuinfo modules
10 16 19 2064 2391 3539 75 crypto mounts
1006 1682 1901 2077 24 36 76 devices mtrr
1018 1693 1919 2096 2440 363 768 diskstats net
1042 17 1921 2098 2451 369 77 dma pagetypeinfo
1072 1728 1922 2099 2480 37 8 dri partitions
1077 1742 1926 21 2493 38 814 driver sched_debug
1088 1780 1932 2102 256 39 82 execdomains schedstat
1090 1791 1936 2121 257 40 840 fb scsi
1092 1828 1939 2127 26 431 885 filesystems self
1105 1837 1952 2128 27 445 886 fs slabinfo
1118 1840 1956 2169 28 48 889 interrupts softirqs
1121 1841 1960 2179 2828 490 890 iomem stat
1123 1845 1962 2195 29 491 928 ioports swaps
1129 1847 1977 2196 3 50 940 irq sys
1130 1854 1979 2198 30 503 941 kallsyms sysrq-trigger
1139 1859 1981 22 3051 51 959 kcore sysvipc
1142 1869 1988 2200 3073 517 967 key-users timer_list
12 1877 1989 2208 31 52 973 kmsg timer_stats
1218 1882 1990 2215 32 53 977 kpagecount tty
13 1883 2 2274 3249 54 acpi kpageflags uptime
1387 1884 20 2280 3256 55 asound latency_stats version
140 1891 2016 23 3257 562 buddyinfo loadavg version_signature
1402 1893 2033 2302 34 567 bus locks vmallocinfo
1411 1894 2054 2308 3466 6 cgroups mdstat vmstat
1428 1896 2058 2315 3475 615 cmdline meminfo zoneinfo
15 1897 2060 2325 3481 694 consoles misc
這些都是一些什麽玩意呢?看得有點暈,仔細看一下,這個有編號的就是我們系統中正在運行的進程的pid呀?我們們隨便打開一個看看這編號的文件夾下面都是什麽東西呢?
cd 1121
我們會看到如下東西:
attr clear_refs cpuset fd limits mountinfo ns pagemap schedstat stat task
autogroup cmdline cwd fdinfo loginuid mounts oom_adj personality sessionid statm wchan
auxv comm environ io maps mountstats oom_score root smaps status
cgroup coredump_filter exe latency mem net oom_score_adj sched stack syscall
在裏面我們可以看到一個叫做“stat”的文件,上網搜索一下這個文件內容,我們知道stat中記錄了我們cpu的使用情況!這個真是大快人心呀,這麽簡單就把這個關鍵給找到了,下一步我們只需要找到firefox的進程id然後進入到目錄下讀取stat文件中的內容,然後按照之前有一篇文章(http://blog.chinaunix.net/uid-27103408-id-3255096.html)中記錄的計算cpu使用率的方法,把它計算出來!我們不禁要問一下是不是這樣問題就解決了呢?
我們更一步的想一下,有兩點值得我們註意:
1、該進程pid目錄下的stat文件記錄的是該進程的cpu使用情況不假,但是假如該進程有子進程怎麽辦呢?
2、就是上一篇文章的計算方法存在缺陷:就是他計算的是一個從開機都現在平均使用率,而我們更多是需要關註的是一個進程的實時的資源使用情況,如何獲取一個實時的統計?
顯然到了這裏我們要實現一個應用程序的資源使用情況的監控,必須要解決這兩個問題:
對於第一個問題,既然/proc下記錄了所有進程的資源使用情況,我們是不是可以把一個進程的所有子進程的資源使用情況做和,就能夠得到該進程的總的資源使用情況呢?答案是肯定的!但是如何來獲取一個進程的子進程呢?更進一步來說如何通過一個進程的pid來獲取它的所有子進程的pid呢?這顯然是一個遞歸的問題,因為一個進程的子進程下還有可能會有子進程,我們通過什麽樣的方法才能把這些子進程都給他找出來呢?
這裏就用到了我們的shell命令:
ps h --ppid 2325 -o pid
我們通過這個命令就可以得到進程2325的子進程,要得到一個進程的所有子進程我們只需要遞歸的執行這條命令就可以了,如何來遞歸的實現呢,其實並不是很困難,我們只需要寫一個遞歸的函數,然後在裏面循環的調用這條shell命令就行了:
void child(const pid_t pid, vector<pid_t> &pvec)
{
FILE *file;
char buf[MAXLINE];
pid_t cpid;
stringstream ss;
stringstream shell;
pvec.push_back(pid);
shell.str("");
shell.clear();
shell << "ps h --ppid ";
shell << pid;
shell << " -o pid";
file = popen(shell.str().c_str(),"r");
if(file != NULL)
{
while(fgets(buf,MAXLINE,file) != NULL)
{
ss << buf;
}
while(ss >> cpid)
{
child(cpid,pvec);
}
}
}
通過上述的執行之後我們就可以得到一個進程的所有子進程,這樣就解決了第一個問題!下面來考慮第二個問題!
既然我們要盡可能的得到一個實時的資源監控,我們就需要在一定的時間間隔之內不斷的讀取cpu的使用情況來計算cpu的使用率,既然stat中記錄的是該進程啟動開始到提取時刻的cpu使用情況,我們就需要記錄上次監控的數據,然後兩次做差!
三、問題的實現:
有了上面的分析我們來實現這個程序,就不算困難了:
定義一個通用的資源監控對象:
/*
*當前版本:2.0
*作 者:ddx
*完成日期:2012年10月19日
*/
#ifndef JSFPROBER_H
#define JSFPROBER_H
#include<string>
using namespace std;
class JsfProber
{
public:
virtual double probe(){return 0.0;}
virtual double probe(const pid_t pid){return 0.0;}
string name;
};
JsfProber* getProber();
#endif
具體實現:
/*************************************************************************
> File Name: jobcpuprober.cpp
> Author: dongdaoxiang
> Mail: dongdaoxiang@ncic.ac.cn
> Created Time: 2012年09月25日 星期二 14時10分54秒
************************************************************************/
#include <stdio.h>
#include "jsfprober.h"
#include <iostream>
#include <vector>
#include <sstream>
#include <string>
#include <cstring>
using namespace std;
#define MAXLINE 1024
void child(const pid_t pid, vector<pid_t> &pvec)
{
FILE *file;
char buf[MAXLINE];
pid_t cpid;
stringstream ss;
stringstream shell;
pvec.push_back(pid);
shell.str("");
shell.clear();
shell << "ps h --ppid ";
shell << pid;
shell << " -o pid";
file = popen(shell.str().c_str(),"r");
if(file != NULL)
{
while(fgets(buf,MAXLINE,file) != NULL)
{
ss << buf;
}
while(ss >> cpid)
{
child(cpid,pvec);
}
}
}
class JobCpuProber:public JsfProber
{
public:
JobCpuProber();
double probe(const pid_t pid);
private:
string jobname;
double ljobtotal;
double ltotal;
};
JobCpuProber::JobCpuProber()
{
jobname = "jobname";
ljobtotal = 0;
ltotal = 0;
}
double JobCpuProber::probe(const pid_t pid)
{
stringstream ss,shell;
double cutime; //current time job spending in user mode
double cstime; //current time job spending in sys mode
double starttime; //the start time of the job
double total = 0.0; //the total cpu time
double temp = 0.0;
double cjobtotal = 0.0; //the total job time
double result = 0.0;
FILE *file;
vector<pid_t> pvec;
char buf[MAXLINE];
child(pid,pvec);
for(vector<pid_t>::iterator it = pvec.begin(); it != pvec.end(); it++)
{
shell.str("");
shell.clear();
shell << "cat /proc/";
shell << *it;
shell << "/stat | cut -d ' ' -f14,15";
file = popen(shell.str().c_str(),"r"); //get the process children's cutime cstime
if(file == NULL)
{
cout << "popen err please check 83th row" << endl;
return -1;
}
memset(buf,0,sizeof(char)*MAXLINE);
ss.str("");
ss.clear();
if(fgets(buf,MAXLINE,file) != NULL)
{
ss << buf;
}
pclose(file);
ss >> cutime;
ss >> cstime;
cjobtotal += cutime + cstime; //get the cjobtotal
}
shell.str("");
shell.clear();
shell << "grep -w cpu /proc/stat | cut -d ' ' -f3,4,5,6,7,8,9";
file = popen(shell.str().c_str(),"r"); //get the total cpu time
if(file == NULL)
{
cout << "popen err please check the 104th row!!" << endl;
return -1;
}
memset(buf,0,sizeof(char)*MAXLINE);
ss.str("");
ss.clear();
if(fgets(buf,MAXLINE,file) != NULL)
{
ss << buf;
}
while(ss >> temp)
{
total += temp;
}
cout << "total: " << total << endl;
cout << "cjobtotal: " << cjobtotal << endl;
result = ((cjobtotal - ljobtotal)/(total - ltotal))*100; //calc the job cpurate
ljobtotal = cjobtotal;
ltotal = total;
return result;
}
JsfProber* getProber()
{
JsfProber* p = new JobCpuProber();
return p;
}
這樣我們就實現了我們的監控,希望可以對大家有些啟發!!!
你可能會有興趣的文章:
限會員,要發表迴響,請先登入


