簡單來說就是通過讀取/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 }