簡單來說就是通過讀取/proc下面的文件來進行,然後進行操作的。
感覺也就那回事 分別讀取了 /proc/stat /proc/loadavg /proc/meminfo
還有就是/proc/進程ID/stat這幾個文件 全部都是純文本操作
其中
/proc/loadavg可以讀取5、10、15分鐘內CPU的平均均衡、運行的進程數、進程總數、最後一次運行的進程ID
/proc/stat 可以獲取用戶態(不含ROOT身份)運行時間、用戶態(ROOT身份)運行時間、核心態運行時間、磁盤IO和非磁盤IO等待的時間還有什麼軟硬中斷時候運行的時間。。。據說最新版本的還有在虛擬機中系統運行的時間和虛擬機中CPU運行時間這兩個東西
/proc/meminfo 可以讀取內存上限、剩余內存、給驅動開發用的Buffer大小、交換區大小、RAM中替換出去在磁盤上數據的大小等等
/proc/進程ID/stat這個文件更變態,基本上所有進程的狀態信息都在裡面。進程ID,名字,狀態,父進程ID,線程組號,會話組號ID 還有什麼終端設備號、缺頁次數….虛擬空間大小….駐留的虛擬中間大小…還有什麼SP指針 PC指針 運行在哪個CPU上 結束時候給父進程發送什麼信號 被交換的頁數 優先級 甚至調度策略 信號位圖之類的 都完完全全在上面了.
感覺也就那回事,,,有以下想不到的或者是收獲
1.用statfs這個函數來做預處理,看文件系統有沒有裝載,沒有裝載就直接退出。
2.else 後面跟while循環 老外不是else {while{}} 而是 else while 寫在同一行看起來很漂亮
3.代碼命名
4.老外會在代碼中不自覺使用{}並且把代碼寫進去,好處一可以限制變量的生命周期和作用域(及時釋放內存)
就這麼多了….
主循環裡面執行
[code]
int main()
{
struct statics stat;
machine_init(&stat);//stat已經指向全局靜態數組
struct system_info info;//
get_system_info(&info);//讀取loadavg文件 查看最近CPU平均負載
struct top_proc proc;
for(;;)
{
printf("Used CPU:%.1f%%\n",(float)info.cpustates[0]/10);
printf("Nice CPU:%.1f%%\n",(float)info.cpustates[1]/10);
printf("System CPU:%.1f%%\n",(float)info.cpustates[2]/10);
printf("Idle CPU:%.1f%%\n",(float)info.cpustates[3]/10);
printf("total memroy:%d\n", info.memory[0]);
printf("free memroy:%d\n", info.memory[1]);
printf("buffers:%d\n", info.memory[2]);
printf("cached:%d\n", info.memory[3]);
printf("total swap:%d\n", info.memory[4]);
printf("free swap:%d\n", info.memory[5]);
sleep(2);
printf("..................................\n");
get_system_info(&info);
read_one_proc_stat( (pid_t)7443, &proc);//獲取進程狀態
struct top_proc *p = &proc;
printf("%s\n",format_next_process(p));
}
return 0;
}其中的三個結構體statics system_info 為:[code]struct statics
{
char **procstate_names;
char **cpustate_names;
char **memory_names;
#ifdef ORDER
char **order_names;
#endif
};
struct system_info
{
int last_pid;
double load_avg[3];
int p_total;
int p_active; /* number of procs considered "active" */
int *procstates;
int *cpustates;
int *memory;
};
struct top_proc
{
pid_t pid;
uid_t uid;
char name[64];
int pri, nice;
unsigned long size, rss; /* in k */
int state;
unsigned long time;
double pcpu, wcpu;
};然後回到main中,看到第一個函數machine_init,其主要功能是對statics 進行初始化,讓其指向一些全局的靜態的東西。[code]int machine_init(struct statics * statics)//進入目錄 設置好全局的變量
{
//確定文件系統已經安裝
{
struct statfs sb;
if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC)//PROC_SUPER_MAGIC用於認知文件系統,宏的具體數字為0x9fa0
{
fprintf(stderr, " proc filesystem not mounted on " PROCFS "\n");
return -1;
}
}
/* chdir to the proc filesystem to make things easier */
chdir(PROCFS);//進入 proc
/* fill in the statics information */
//指向全局的靜態數組信息
statics->procstate_names = procstatenames;
statics->cpustate_names = cpustatenames;
statics->memory_names = memorynames;
/* all done! */
return 0;
}get_system_info(&info);//讀取loadavg文件 查看最近CPU平均負載[code]void get_system_info(struct system_info *info)
{
char buffer[4096+1];
int fd, len;
char *p;
int i;
/*
/proc # cat loadavg
1.0 1.00 0.93 2/19 301
lavg_1 (1.0) 1-分鐘平均負載
lavg_5 (1.00) 5-分鐘平均負載
lavg_15(0.93) 15-分鐘平均負載
nr_running (2) 在采樣時刻,運行隊列的任務的數目,與/proc/stat的procs_running表示相同意思
nr_threads (19) 在采樣時刻,系統中活躍的任務的個數(不包括運行已經結束的任務)
last_pid(301) 最大的pid值,包括輕量級進程,即線程。
*/
/* get load averages */
{
fd = open("loadavg", O_RDONLY);
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
buffer[len] = '\0';
//strtod將字符串轉換成浮點數
info->load_avg[0] = strtod(buffer, &p);//5分鐘內的平均負載
info->load_avg[1] = strtod(p, &p);//10分鐘內的平均負載
info->load_avg[2] = strtod(p, &p);//15分鐘內的平均負載
p = skip_token(p); /* skip 是正在運行的進程數 分母是進程總數*/
p = skip_ws(p); //最後一個是最近運行的進程ID號
if (*p)
info->last_pid = atoi(p);
else
info->last_pid = -1;
}
/* get the cpu time info */
{
fd = open("stat", O_RDONLY);
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
buffer[len] = '\0';
/*
cpu 5484 160 6158 212335 16934 126 190 0 0
cpu0 5484 160 6158 212335 16934 126 190 0 0
intr 233270 194 357 0 2 1108 0 0 0 1 0 0 0 1303 0 0 0 2090 18850 75 266 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1228 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 342349
btime 1459309158
processes 6089
procs_running 1
procs_blocked 0
softirq 338409 0 151659 572 208 19816 0 948 0 536 164670
*/
p = skip_token(buffer); /* "cpu" */ //跳過CPU
cp_time[0] = strtoul(p, &p, 0);//nptr字符串根據參數base來轉換成無符號的長整型數。
//user (5484) 從系統啟動開始累計到當前時刻,用戶態的CPU時間(單位:jiffies) ,不包含 nice值為負進程。1jiffies=0.01秒
cp_time[1] = strtoul(p, &p, 0);
//nice (160) 從系統啟動開始累計到當前時刻,nice值為負的進程所占用的CPU時間(單位:jiffies)
cp_time[2] = strtoul(p, &p, 0);
//system (6158) 從系統啟動開始累計到當前時刻,核心時間(單位:jiffies)
cp_time[3] = strtoul(p, &p, 0);
//idle (212335) 從系統啟動開始累計到當前時刻,除硬盤IO等待時間以外其它等待時間(單位:jiffies)
//iowait (16934) 從系統啟動開始累計到當前時刻,硬盤IO等待時間(單位:jiffies) ,
//irq (126) 從系統啟動開始累計到當前時刻,硬中斷時間(單位:jiffies)
//softirq (190) 從系統啟動開始累計到當前時刻,軟中斷時間(單位:jiffies)
/*
stealstolen(0):
虛擬系統中的運行時間(since 2.6.11)
guest(0) :
//虛擬CPU 分配給虛擬機的CPU
which is the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel(since 2.6.24)
*/
/* convert cp_time counts to percentages */
percentages(4, cpu_states, cp_time, cp_old, cp_diff);
}
/* get system wide memory usage */
{
char *p;
fd = open("meminfo", O_RDONLY);
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
buffer[len] = '\0';
p = buffer;
p = skip_token(p);//跳過
memory_stats[0] = strtoul(p, &p, 10); /* 內存上限 */ ///10為進制數
p = strchr(p, '\n');//extern char *strchr(const char *s,char c);查找字符串s中首次出現字符c的位置。
p = skip_token(p);
memory_stats[1] = strtoul(p, &p, 10); /* 剩余內存 */
p = strchr(p, '\n');
p = skip_token(p);
memory_stats[2] = strtoul(p, &p, 10);
//用來給塊設備做的緩沖大小(只記錄文件系統的metadata以及 tracking in-flight pages,就是說 buffers是用來存儲,
//目錄裡面有什麼內容,權限等等。)
p = strchr(p, '\n');
p = skip_token(p);
memory_stats[3] = strtoul(p, &p, 10); /* cached memory */
//Cached: 用來給文件做緩沖大小(直接用來記憶我們打開的文件). 它不包括SwapCached
for(i = 0; i< 8 ;i++) {
p++;
p = strchr(p, '\n');///跳過8個
}
p = skip_token(p);
memory_stats[4] = strtoul(p, &p, 10); /* total swap */
// SwapTotal: 交換空間的總和
p = strchr(p, '\n');
p = skip_token(p);
memory_stats[5] = strtoul(p, &p, 10); /* free swap */
//SwapFree: 從RAM中被替換出暫時存在磁盤上的空間大小
}
/*
MemTotal: 所有可用RAM大小 (即物理內存減去一些預留位和內核的二進制代碼大小)
MemFree: LowFree與HighFree的總和
Buffers: 用來給塊設備做的緩沖大小(只記錄文件系統的metadata以及 tracking in-flight pages,就是說 buffers是用來存儲,目錄裡面有什麼內容,權限等等。)
Cached: 用來給文件做緩沖大小(直接用來記憶我們打開的文件). 它不包括SwapCached
SwapCached: 已經被交換出來的內存,但仍然被存放在swapfile中。用來在需要的時候很快的被替換而不需要再次打開I/O端口。
Active: 最近經常被使用的內存,除非非常必要否則不會被移作他用.
Inactive: 最近不經常被使用的內存,非常用可能被用於其他途徑.
HighTotal:
HighFree: 高位內存是指所有在860MB以上的內存空間,該區域主要用於用戶空間的程序或者是緩存頁面。內核必須使用不同的手法使用該段內存,因此它比低位內存要慢一些。
LowTotal:
LowFree: 低位可以達到高位內存一樣的作用,而且它還能夠被內核用來記錄一些自己的數據結構。
Among many other things, it is where everything from the Slab is
allocated. Bad things happen when you're out of lowmem.
SwapTotal: 交換空間的總和
SwapFree: 從RAM中被替換出暫時存在磁盤上的空間大小
Dirty: 等待被寫回到磁盤的內存大小。
Writeback: 正在被寫回到磁盤的內存大小。
Mapped: 影射文件的大小。
Slab: 內核數據結構緩存
VmallocTotal: vmalloc內存大小
VmallocUsed: 已經被使用的虛擬內存大小。
VmallocChunk: largest contigious block of vmalloc area which is free
CommitLimit:
Committed_AS:
*/
/* set arrays and strings */
info->cpustates = cpu_states;
info->memory = memory_stats;
}
/*
/proc/1 # cat stat
3348 (xdg-screensaver) S 1 2790 2790 0 -1 4202560 30551 330530 0 0 19 77 100 391 20 0 1 0 53358 5296128 171 4294967295
134508544 135361360 3214570048 3214565048 10228772 0 65536 6 65536 0 0 0 17 0 0 0 0 0 0
pid=3348 進程(包括輕量級進程,即線程)號
comm= xdg-screensaver 應用程序或命令的名字
task_state=S 任務的狀態,R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disk sleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop,Z:zombie, X:dead
ppid=1 父進程ID
pgid=2790 線程組號/////////////////
sid=2790 c該任務所在的會話組ID
tty_nr=0 (pts/3) 該任務的tty終端的設備號,INT(0/256)=主設備號,(0-主設備號)=次設備號
tty_pgrp=-1 終端的進程組號,當前運行在該任務所在終端的前台任務(包括shell 應用程序)的PID。
task->flags=4202560進程標志位,查看該任務的特性///////////////////////
min_flt=30551該任務不需要從硬盤拷數據而發生的缺頁(次缺頁)的次數@@@@@@@@@@@@@@
cmin_flt=330530 累計的該任務的所有的waited-for進程曾經發生的次缺頁的次數目
maj_flt=0 該任務需要從硬盤拷數據而發生的缺頁(主缺頁)的次數
cmaj_flt=0 累計的該任務的所有的waited-for進程曾經發生的主缺頁的次數目
utime=19 該任務在用戶態運行的時間,單位為jiffies
stime=77 該任務在核心態運行的時間,單位為jiffies
cutime=100 累計的該任務的所有的waited-for進程曾經在用戶態運行的時間,單位為jiffies
cstime=391 累2計的該任務的所有的waited-for進程曾經在核心態運行的時間,單位為jiffies
priority=20 任務的動態優先級
nice=0 任務的靜態優先級
num_threads=1 該任務所在的線程組裡線程的個數
it_real_value=0 由於計時間隔導致的下一個 SIGALRM 發送進程的時延,以 jiffy 為單位.
start_time=53358 該任務啟動的時間,單位為jiffies
vsize=5296128(bytes) 該任務的虛擬地址空間大小
rss=171(page) 該任務當前駐留物理地址空間的大小
Number of pages the process has in real memory,minu 3 for administrative purpose.
這些頁可能用於代碼,數據和棧。
//4294967295
rlim=4294967295=0xFFFFFFFF(bytes) 該任務能駐留物理地址空間的最大值
start_code=134508544=0x8000 該任務在虛擬地址空間的代碼段的起始地址(由連接器決定)
end_code=135361360該任務在虛擬地址空間的代碼段的結束地址
start_stack=3214570048=0Xbeb0ff30該任務在虛擬地址空間的棧的開始地址
kstkesp=3214565048 sp(32 位堆棧指針) 的當前值, 與在進程的內核堆棧頁得到的一致.
kstkeip=10228772 =0X10FD58 指向將要執行的指令的指針, PC(32 位指令指針)的當前值.
pendingsig=0 待處理信號的位圖,記錄發送給進程的普通信號
block_sig=65536 阻塞信號的位圖
sigign=6 忽略的信號的位圖
sigcatch=65536被俘獲的信號的位圖
wchan=0 如果該進程是睡眠狀態,該值給出調度的調用點
nswap=0 被swapped的頁數
cnswap=0 所有子進程被swapped的頁數的和
exit_signal=17 該進程結束時,向父進程所發送的信號
task_cpu(task)=0 運行在哪個CPU上
task_rt_priority=0 實時進程的相對優先級別
task_policy=0 進程的調度策略,0=非實時進程,1=FIFO實時進程;2=RR實時進程
*/然後是一堆的打印。。。忽略掉。。。再看一個函數是讀取進程信息的函數[code]void read_one_proc_stat(pid_t pid, struct top_proc *proc)
{
char buffer[4096], *p;
/* grab the proc stat info in one go */
{
int fd, len;
sprintf(buffer, "%d/stat", pid);
fd = open(buffer, O_RDONLY);//打開%d/stat
len = read(fd, buffer, sizeof(buffer)-1);
close(fd);
buffer[len] = '\0';
}
proc->uid = proc_owner(pid);///
/* parse out the status */
p = buffer;
p = strchr(p, '(')+1; /* skip pid */
{
char *q = strrchr(p, ')');//跳過pid和進程名稱
int len = q-p;
if (len >= sizeof(proc->name))///進程名字過長 比結構體中長要限制
len = sizeof(proc->name)-1;
memcpy(proc->name, p, len);//拷貝進程名字
proc->name[len] = 0;
p = q+1;
}
//R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disk sleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop,Z:zombie, X:dead
p = skip_ws(p);
switch (*p++)
{
case 'R': proc->state = 1; break;//R:runnign,
case 'S': proc->state = 2; break;//S:sleeping TASK_INTERRUPTIBLE
case 'D': proc->state = 3; break;// D:disk sleep (TASK_UNINTERRUPTIBLE)
case 'Z': proc->state = 4; break;//Z:zombie僵死進程
case 'T': proc->state = 5; break;//T: stopped
case 'W': proc->state = 6; break;//等待???Wait NO swap切出交換區
}
p = skip_token(p); /* skip ppid父進程ID */
p = skip_token(p); /* skip pgrp 線程組號 */
p = skip_token(p); /* skip session該任務所在的會話組ID */
p = skip_token(p); /* skip tty該任務的tty終端的設備號 */
p = skip_token(p); /* skip tty pgrp 終端的進程組號,當前運行在該任務所在終端的前台任務(包括shell 應用程序)的PID */
p = skip_token(p); /* skip flags進程標志位 */
p = skip_token(p); /* skip min flt 該任務不需要從硬盤拷數據而發生的缺頁(次缺頁)的次數*/
p = skip_token(p); /* skip cmin flt 累計的該任務的所有的waited-for進程曾經發生的次缺頁的次數目*/
p = skip_token(p); /* skip maj flt 該任務需要從硬盤拷數據而發生的缺頁(主缺頁)的次數*/
p = skip_token(p); /* skip cmaj flt 累計的該任務的所有的waited-for進程曾經發生的主缺頁的次數目*/
proc->time = strtoul(p, &p, 10); /* utime在用戶態運行的時間, */
proc->time += strtoul(p, &p, 10); /* stime在核心態運行的時間, */
p = skip_token(p); /* skip cutime 累計的該任務的所有的waited-for進程曾經在用戶態運行的時間*/
p = skip_token(p); /* skip cstime 累計的該任務的所有的waited-for進程曾經在核心態運行的時間,單位為jiffies*/
proc->pri = strtol(p, &p, 10); /* priority任務的動態優先級 */
proc->nice = strtol(p, &p, 10); /* nice任務的靜態優先級 */
//該任務所在的線程組裡線程的個數 沒有!!!
p = skip_token(p); /* skip timeout該任務所在的線程組裡線程的個數 */
p = skip_token(p); /* skip it_real_val 由於計時間隔導致的下一個 SIGALRM 發送進程的時延,以 jiffy 為單位*/
p = skip_token(p); /* skip start_time 該任務啟動的時間*/
proc->size = bytetok(strtoul(p, &p, 10)); /* vsize 該任務的虛擬地址空間大小 */
proc->rss = pagetok(strtoul(p, &p, 10)); /* rss 該任務當前駐留物理地址空間的大小*/
#if 0
/* for the record, here are the rest of the fields */
p = skip_token(p); /* skip rlim 該任務能駐留物理地址空間的最大值*/
p = skip_token(p); /* skip start_code 該任務在虛擬地址空間的代碼段的起始地址(由連接器決定)*/
p = skip_token(p); /* skip end_code該任務在虛擬地址空間的代碼段的結束地址 */
p = skip_token(p); /* skip start_stack 該任務在虛擬地址空間的棧的開始地址*/
p = skip_token(p); /* skip sp sp(32 位堆棧指針) 的當前值, 與在進程的內核堆棧頁得到的一致.*/
p = skip_token(p); /* skip pc 指向將要執行的指令的指針, PC(32 位指令指針)的當前值.*/
p = skip_token(p); /* skip signal 待處理信號的位圖,記錄發送給進程的普通信號*/
p = skip_token(p); /* skip sigblocked 阻塞信號的位圖*/
p = skip_token(p); /* skip sigignore 忽略的信號的位圖*/
p = skip_token(p); /* skip sigcatch被俘獲的信號的位圖 */
p = skip_token(p); /* skip wchan 如果該進程是睡眠狀態,該值給出調度的調用點*/
///////////////新版本系統有的
p = skip_token(p); /* nswap=0 被swapped的頁數 */
p = skip_token(p); /* cnswap=0 所有子進程被swapped的頁數的和 */
p = skip_token(p); /* exit_signal=0 該進程結束時,向父進程所發送的信號*/
p = skip_token(p); /* task_cpu(task)=0 運行在哪個CPU上*/
p = skip_token(p); /* task_rt_priority=0 實時進程的相對優先級別*/
p = skip_token(p); /*task_policy=0 進程的調度策略,0=非實時進程,1=FIFO實時進程;2=RR實時進程 */
#endif
}