選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

340 行
9.1 KiB

3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
3年前
  1. //#define mytop_h
  2. #include <stdio.h>
  3. #include <unistd.h>
  4. #include <pwd.h>
  5. #include <curses.h>
  6. #include <stdlib.h>
  7. #include <limits.h>
  8. #include <termcap.h>
  9. #include <termios.h>
  10. #include <time.h>
  11. #include <string.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <dirent.h>
  16. #include <assert.h>
  17. typedef int endpoint_t;
  18. typedef uint64_t u64_t;
  19. typedef long unsigned int vir_bytes;
  20. #define USED 0x1
  21. #define IS_TASK 0x2
  22. #define IS_SYSTEM 0x4
  23. #define BLOCKED 0x8
  24. #define TYPE_TASK 'T'
  25. #define TYPE_SYSTEM 'S'
  26. #define STATE_RUN 'R'
  27. #define MAX_NR_TASKS 1023
  28. #define SELF ((endpoint_t) 0x8ace)
  29. #define _MAX_MAGIC_PROC (SELF)
  30. #define _ENDPOINT_GENERATION_SIZE (MAX_NR_TASKS+_MAX_MAGIC_PROC+1)
  31. #define _ENDPOINT_P(e) \
  32. ((((e)+MAX_NR_TASKS) % _ENDPOINT_GENERATION_SIZE) - MAX_NR_TASKS)
  33. #define SLOT_NR(e) (_ENDPOINT_P(e) + 5)
  34. #define _PATH_PROC "/proc"
  35. #define CPUTIME(m, i) (m & (1L << (i)))
  36. const char *cputimenames[] = { "user", "ipc", "kernelcall" };
  37. #define CPUTIMENAMES (sizeof(cputimenames)/sizeof(cputimenames[0]))
  38. unsigned int nr_procs, nr_tasks;
  39. int nr_total=0;
  40. struct proc {
  41. int p_flags;
  42. endpoint_t p_endpoint;
  43. pid_t p_pid;
  44. u64_t p_cpucycles[CPUTIMENAMES];
  45. int p_priority;
  46. endpoint_t p_blocked;
  47. time_t p_user_time;
  48. vir_bytes p_memory;
  49. uid_t p_effuid;
  50. int p_nice;
  51. char p_name[16+1];
  52. };
  53. struct proc *proc = NULL, *prev_proc = NULL;
  54. //u64_t 64位 high和low32位 拼接成64位 high+low
  55. static inline u64_t make64(unsigned long lo, unsigned long hi)
  56. {
  57. return ((u64_t)hi << 32) | (u64_t)lo;
  58. }
  59. //把每个pid/psinfo的信息读出来
  60. //判断读取信息是否可用
  61. void parse_file(pid_t pid)
  62. {
  63. char path[PATH_MAX], name[256], type, state;
  64. int version, endpt, effuid;
  65. unsigned long cycles_hi, cycles_lo;
  66. FILE *fp;
  67. struct proc *p;
  68. int slot;
  69. int i;
  70. sprintf(path, "/proc/%d/psinfo", pid);
  71. if ((fp = fopen(path, "r")) == NULL)
  72. return;
  73. if (fscanf(fp, "%d", &version) != 1) {
  74. fclose(fp);
  75. return;
  76. }
  77. if (version != 0) {
  78. fputs("procfs version mismatch!\n", stderr);
  79. exit(1);
  80. }
  81. if (fscanf(fp, " %c %d", &type, &endpt) != 2) {
  82. fclose(fp);
  83. return;
  84. }
  85. //统计总file数
  86. //filenum+=1;
  87. //原来的slot超出了nr_total
  88. slot = SLOT_NR(endpt);
  89. slot++;
  90. //slot=slot_a;
  91. //slot_a+=1;//赋值需保证在数组中不会重复
  92. //判断endpoint的值是否合理 在0到nr_total的范围内
  93. if(slot < 0 || slot >= nr_total) {
  94. //fprintf(stderr, "top: unreasonable endpoint number %d\n", endpt);
  95. fclose(fp);
  96. return;
  97. }
  98. //slot为该进程结构体在数组中的位置
  99. p = &proc[slot];//把slot地址赋值给p
  100. if (type == TYPE_TASK)
  101. //标示task进程
  102. p->p_flags |= IS_TASK;
  103. else if (type == TYPE_SYSTEM)
  104. //标示system进程
  105. p->p_flags |= IS_SYSTEM;
  106. //将endpt和pid存入对应进程结构体
  107. p->p_endpoint = endpt;
  108. p->p_pid = pid;
  109. //读入名字 状态 阻塞状态 动态优先级 进程时间 高周期 低周期
  110. if (fscanf(fp, " %255s %c %d %d %lu %*u %lu %lu",
  111. name, &state, &p->p_blocked, &p->p_priority,
  112. &p->p_user_time, &cycles_hi, &cycles_lo) != 7) {
  113. fclose(fp);
  114. return;
  115. }
  116. //将指定长度的字符串复制到字符数组中
  117. strncpy(p->p_name, name, sizeof(p->p_name)-1);
  118. //数组置0
  119. p->p_name[sizeof(p->p_name)-1] = 0;
  120. if (state != STATE_RUN)//如果不是run的进程
  121. p->p_flags |= BLOCKED;//标志阻塞
  122. //拼接成64位,放在p_cpucycles[]数组中
  123. p->p_cpucycles[0] = make64(cycles_lo, cycles_hi);
  124. p->p_memory = 0L;
  125. //判断是否为有效用户ID
  126. if (!(p->p_flags & IS_TASK)) {
  127. int j;
  128. //读如内存 有效用户ID 和静态优先级
  129. if ((j=fscanf(fp, " %lu %*u %*u %*c %*d %*u %u %*u %d %*c %*d %*u",
  130. &p->p_memory, &effuid, &p->p_nice)) != 3) {
  131. fclose(fp);
  132. return;
  133. }
  134. p->p_effuid = effuid;
  135. } else p->p_effuid = 0;
  136. //连续读CPUTIMENAMES次cycles_hi,cycle_lo
  137. for(i = 1; i < CPUTIMENAMES; i++) {
  138. if(fscanf(fp, " %lu %lu",
  139. &cycles_hi, &cycles_lo) == 2) {
  140. //拼接成64位,放在p_cpucycles[]数组中
  141. p->p_cpucycles[i] = make64(cycles_lo, cycles_hi);
  142. } else {
  143. p->p_cpucycles[i] = 0;
  144. }
  145. }
  146. //读如内存 存入进程结构体
  147. if ((p->p_flags & IS_TASK)) {
  148. if(fscanf(fp, " %lu", &p->p_memory) != 1) {
  149. p->p_memory = 0;
  150. }
  151. }
  152. //按位或
  153. p->p_flags |= USED;
  154. fclose(fp);
  155. }
  156. void parse_dir(void)
  157. {
  158. DIR *p_dir;
  159. struct dirent *p_ent;
  160. pid_t pid;
  161. char *end;
  162. if ((p_dir = opendir("/proc/")) == NULL) {
  163. perror("opendir on /proc");
  164. exit(1);
  165. }
  166. p_ent=readdir(p_dir);
  167. while(p_ent != NULL){
  168. pid=strtol(p_ent->d_name,&end,10);
  169. if(pid!=0 && !end[0]){
  170. parse_file(pid);
  171. }
  172. p_ent=readdir(p_dir);
  173. }
  174. closedir(p_dir);
  175. }
  176. int print_memory(void)
  177. {
  178. FILE *fp;
  179. unsigned int pagesize;
  180. unsigned long total, free, largest, cached;
  181. if ((fp = fopen("/proc/meminfo", "r")) == NULL)
  182. return 0;
  183. if (fscanf(fp, "%u %lu %lu %lu %lu", &pagesize, &total, &free,
  184. &largest, &cached) != 5) {
  185. fclose(fp);
  186. return 0;
  187. }
  188. fclose(fp);
  189. printf("main memory: %ldK total, %ldK free, %ldK contig free, "
  190. "%ldK cached\n",
  191. (pagesize * total)/1024, (pagesize * free)/1024,
  192. (pagesize * largest)/1024, (pagesize * cached)/1024);
  193. return 1;
  194. }
  195. struct tp {
  196. struct proc *p;
  197. u64_t ticks;
  198. };
  199. //计算cputicks 用到当前进程和其他进程的,还涉及CPUTIME
  200. //滴答并不是简单的结构体中的滴答,因为在写文件的时候需要更新。需要通过当前进程来和该进程一起计算
  201. u64_t cputicks(struct proc *p1, struct proc *p2, int timemode)
  202. {
  203. int i;
  204. u64_t t = 0;
  205. //计算每个进程proc的滴答,通过proc和当前进程prev_proc做比较,如果endpoint相等,则在循环中分别计算
  206. for(i = 0; i < CPUTIMENAMES; i++) {
  207. if(!CPUTIME(timemode, i))
  208. continue;
  209. if(p1->p_endpoint == p2->p_endpoint) {
  210. t = t + p2->p_cpucycles[i] - p1->p_cpucycles[i];
  211. } else {
  212. t = t + p2->p_cpucycles[i];
  213. }
  214. }
  215. return t;
  216. }
  217. void print_procs(
  218. struct proc *proc1, struct proc *proc2, int cputimemode)
  219. {
  220. int p, nprocs;
  221. u64_t idleticks = 0;
  222. u64_t kernelticks = 0;
  223. u64_t systemticks = 0;
  224. u64_t userticks = 0;
  225. u64_t total_ticks = 0;
  226. int blockedseen = 0;
  227. static struct tp *tick_procs = NULL;
  228. if (tick_procs == NULL) {
  229. tick_procs = malloc(nr_total * sizeof(tick_procs[0]));
  230. if (tick_procs == NULL) {
  231. fprintf(stderr, "Out of memory!\n");
  232. exit(1);
  233. }
  234. }
  235. for(p = nprocs = 0; p < nr_total; p++) {
  236. u64_t uticks;
  237. //如果当前进程标志不是used就continue 看下一个进程。
  238. if(!(proc2[p].p_flags & USED))
  239. continue;
  240. tick_procs[nprocs].p = proc2 + p;
  241. tick_procs[nprocs].ticks = cputicks(&proc1[p], &proc2[p], cputimemode);
  242. //更新实时uticks
  243. uticks = cputicks(&proc1[p], &proc2[p], 1);
  244. //算出总的ticks
  245. total_ticks = total_ticks + uticks;
  246. //判断是否为idletick
  247. //为0一直continue 不用计算
  248. if(p-5 == 317) {
  249. idleticks = uticks;
  250. continue;
  251. }
  252. //判断是否为kerneltick
  253. if(p-5 == ((endpoint_t) -1)) {
  254. kernelticks = uticks;
  255. }
  256. if(!(proc2[p].p_flags & IS_TASK)) {
  257. if(proc2[p].p_flags & IS_SYSTEM)
  258. systemticks = systemticks + tick_procs[nprocs].ticks;
  259. else
  260. userticks = userticks + tick_procs[nprocs].ticks;
  261. }
  262. nprocs++;
  263. }
  264. if (total_ticks == 0)
  265. return;
  266. printf("CPU states: %6.2f%% user, ", 100.0 * userticks / total_ticks);
  267. printf("%6.2f%% system, ", 100.0 * systemticks / total_ticks);
  268. printf("%6.2f%% kernel, ", 100.0 * kernelticks/ total_ticks);
  269. printf("%6.2f%% idle",100.00-(100.0 * (kernelticks+userticks+systemticks)/ total_ticks));
  270. printf("\n");
  271. }
  272. void get_procs(void)
  273. {
  274. struct proc *p;
  275. int i;
  276. p = prev_proc;
  277. prev_proc = proc;
  278. proc = p;
  279. if (proc == NULL) {
  280. proc = malloc(nr_total * sizeof(proc[0]));
  281. if (proc == NULL) {
  282. fprintf(stderr, "Out of memory!\n");
  283. exit(1);
  284. }
  285. }
  286. for (i = 0; i < nr_total; i++)
  287. proc[i].p_flags = 0;
  288. parse_dir();
  289. }
  290. void getkinfo(void)
  291. {
  292. FILE *fp;
  293. if ((fp = fopen("/proc/kinfo", "r")) == NULL) {
  294. exit(1);
  295. }
  296. if (fscanf(fp, "%u %u", &nr_procs, &nr_tasks) != 2) {
  297. exit(1);
  298. }
  299. fclose(fp);
  300. nr_total = (int) (nr_procs + nr_tasks);
  301. }
  302. void mytop()
  303. {
  304. if (chdir("/proc") != 0) {
  305. perror("chdir to /proc" );
  306. return 1;
  307. }
  308. print_memory();
  309. getkinfo();
  310. get_procs();
  311. if(prev_proc==NULL)
  312. get_procs();
  313. print_procs(prev_proc,proc,1);
  314. return 0;
  315. }