2 * Conky, a system monitor, based on torsmo
4 * This program is licensed under BSD license, read COPYING
11 static regex_t *exclusion_expression = 0;
12 static unsigned int g_time = 0;
13 static int previous_total = 0;
14 static struct process *first_process = 0;
16 static struct process *find_process(pid_t pid)
18 struct process *p = first_process;
28 * Create a new process object and insert it into the process list
30 static struct process *new_process(int p)
32 struct process *process;
33 process = (struct process*)malloc(sizeof(struct process));
36 * Do stitching necessary for doubly linked list
39 process->previous = 0;
40 process->next = first_process;
42 process->next->previous = process;
43 first_process = process;
46 process->time_stamp = 0;
47 process->previous_user_time = INT_MAX;
48 process->previous_kernel_time = INT_MAX;
51 /* process_find_name(process); */
56 /******************************************/
58 /******************************************/
60 static int process_parse_stat(struct process *);
61 static int update_process_table(void);
62 static int calculate_cpu(struct process *);
63 static void process_cleanup(void);
64 static void delete_process(struct process *);
65 /*inline void draw_processes(void);*/
66 static int calc_cpu_total(void);
67 static void calc_cpu_each(int);
70 /******************************************/
71 /* Extract information from /proc */
72 /******************************************/
75 * These are the guts that extract information out of /proc.
76 * Anyone hoping to port wmtop should look here first.
78 static int process_parse_stat(struct process *process)
80 struct information *cur;
82 char line[BUFFER_LEN], filename[BUFFER_LEN], procname[BUFFER_LEN];
84 int user_time, kernel_time;
87 char deparenthesised_name[BUFFER_LEN];
91 snprintf(filename, sizeof(filename), PROCFS_TEMPLATE,
94 ps = open(filename, O_RDONLY);
97 * The process must have finished in the last few jiffies!
102 * Mark process as up-to-date.
104 process->time_stamp = g_time;
106 rc = read(ps, line, sizeof(line));
112 * Extract cpu times from data in /proc filesystem
115 "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d %*s %*s %*s %d %*s %*s %*s %d %d",
116 procname, &process->user_time, &process->kernel_time,
117 &nice_val, &process->vsize, &process->rss);
121 * Remove parentheses from the process name stored in /proc/ under Linux...
124 /* remove any "kdeinit: " */
125 if (r == strstr(r, "kdeinit")) {
126 snprintf(filename, sizeof(filename),
127 PROCFS_CMDLINE_TEMPLATE, process->pid);
129 ps = open(filename, O_RDONLY);
132 * The process must have finished in the last few jiffies!
136 endl = read(ps, line, sizeof(line));
139 /* null terminate the input */
141 /* account for "kdeinit: " */
142 if ((char *) line == strstr(line, "kdeinit: "))
143 r = ((char *) line) + 9;
147 q = deparenthesised_name;
149 while (*r && *r != ' ')
153 q = deparenthesised_name;
154 while (*r && *r != ')')
161 process->name = strdup(deparenthesised_name);
162 process->rss *= getpagesize();
165 update_total_processes();
167 process->totalmem = ((float) process->rss / cur->memmax) / 10;
169 if (process->previous_user_time == INT_MAX)
170 process->previous_user_time = process->user_time;
171 if (process->previous_kernel_time == INT_MAX)
172 process->previous_kernel_time = process->kernel_time;
174 /* store the difference of the user_time */
175 user_time = process->user_time - process->previous_user_time;
176 kernel_time = process->kernel_time - process->previous_kernel_time;
178 /* backup the process->user_time for next time around */
179 process->previous_user_time = process->user_time;
180 process->previous_kernel_time = process->kernel_time;
182 /* store only the difference of the user_time here... */
183 process->user_time = user_time;
184 process->kernel_time = kernel_time;
190 /******************************************/
191 /* Update process table */
192 /******************************************/
194 static int update_process_table()
197 struct dirent *entry;
199 if (!(dir = opendir("/proc")))
205 * Get list of processes from /proc directory
207 while ((entry = readdir(dir))) {
212 * Problem reading list of processes
218 if (sscanf(entry->d_name, "%d", &pid) > 0) {
220 p = find_process(pid);
222 p = new_process(pid);
224 /* compute each process cpu usage */
234 /******************************************/
235 /* Get process structure for process pid */
236 /******************************************/
239 * This function seems to hog all of the CPU time. I can't figure out why - it
242 static int calculate_cpu(struct process *process)
246 /* compute each process cpu usage by reading /proc/<proc#>/stat */
247 rc = process_parse_stat(process);
250 /*rc = process_parse_statm(process);
255 * Check name against the exclusion list
257 if (process->counted && exclusion_expression
258 && !regexec(exclusion_expression, process->name, 0, 0, 0))
259 process->counted = 0;
264 /******************************************/
265 /* Strip dead process entries */
266 /******************************************/
268 static void process_cleanup()
271 struct process *p = first_process;
273 struct process *current = p;
275 #if defined(PARANOID)
276 assert(p->id == 0x0badfeed);
277 #endif /* defined(PARANOID) */
281 * Delete processes that have died
283 if (current->time_stamp != g_time)
284 delete_process(current);
288 /******************************************/
289 /* Destroy and remove a process */
290 /******************************************/
292 static void delete_process(struct process *p)
294 #if defined(PARANOID)
295 assert(p->id == 0x0badfeed);
298 * Ensure that deleted processes aren't reused.
301 #endif /* defined(PARANOID) */
304 * Maintain doubly linked list.
307 p->next->previous = p->previous;
309 p->previous->next = p->next;
311 first_process = p->next;
318 /******************************************/
319 /* Calculate cpu total */
320 /******************************************/
322 static int calc_cpu_total()
327 char line[BUFFER_LEN];
328 int cpu, nice, system, idle;
330 ps = open("/proc/stat", O_RDONLY);
331 rc = read(ps, line, sizeof(line));
335 sscanf(line, "%*s %d %d %d %d", &cpu, &nice, &system, &idle);
336 total = cpu + nice + system + idle;
338 t = total - previous_total;
339 previous_total = total;
347 /******************************************/
348 /* Calculate each processes cpu */
349 /******************************************/
351 inline static void calc_cpu_each(int total)
353 struct process *p = first_process;
355 /*p->amount = total ?
356 (100.0 * (float) (p->user_time + p->kernel_time) /
359 (100.0 * (p->user_time + p->kernel_time) / total);
361 /* if (p->amount > 100)
367 /******************************************/
368 /* Find the top processes */
369 /******************************************/
372 * Result is stored in decreasing order in best[0-9].
374 #define MAX_TOP_SIZE 400 /* this is plenty big */
375 static struct process **sorttmp;
376 static size_t sorttmp_size = 10;
378 int comparecpu(const void * a, const void * b)
380 if ((*(struct process **)a)->amount > (*(struct process **)b)->amount) {
383 if ((*(struct process **)a)->amount < (*(struct process **)b)->amount) {
389 int comparemem(const void * a, const void * b)
391 if ((*(struct process **)a)->totalmem > (*(struct process **)b)->totalmem) {
394 if ((*(struct process **)a)->totalmem < (*(struct process **)b)->totalmem) {
400 inline void process_find_top(struct process **cpu, struct process **mem)
403 if (sorttmp == NULL) {
404 sorttmp = malloc(sizeof(struct process) * sorttmp_size);
405 assert(sorttmp != NULL);
410 total = calc_cpu_total(); /* calculate the total of the processor */
412 update_process_table(); /* update the table with process list */
413 calc_cpu_each(total); /* and then the percentage for each task */
414 process_cleanup(); /* cleanup list from exited processes */
417 * this is really ugly,
418 * not to mention probably not too efficient.
419 * the main problem is that there could be any number of processes,
420 * however we have to use a fixed size for the "best" array.
421 * right now i can't think of a better way to do this,
422 * although i'm sure there is one.
423 * Perhaps just using a linked list would be more effecient?
424 * I'm too fucking lazy to do that right now.
430 if (i < sorttmp_size && pr->counted) {
433 } else if (i == sorttmp_size && pr->counted && sorttmp_size < MAX_TOP_SIZE) {
437 sizeof(struct process) *
444 if (i + 1 < sorttmp_size) {
448 sizeof(struct process) * sorttmp_size);
450 qsort(sorttmp, i, sizeof(struct process *), comparecpu);
451 for (i = 0; i < 10; i++) {
459 if (i < sorttmp_size && pr->counted) {
462 } else if (i == sorttmp_size && pr->counted && sorttmp_size < MAX_TOP_SIZE) {
466 sizeof(struct process) *
473 if (i + 1 < sorttmp_size) {
477 sizeof(struct process) * sorttmp_size);
479 qsort(sorttmp, i, sizeof(struct process *), comparemem);
480 for (i = 0, j = 0; i < sorttmp_size && j < 10; i++) {
481 if (j == 0 || sorttmp[i]->totalmem != mem[j-1]->totalmem
482 || strncmp(sorttmp[i]->name, mem[j-1]->name,128)) {
483 mem[j++] = sorttmp[i];