3 static regex_t *exclusion_expression = 0;
4 static unsigned int g_time = 0;
5 static int previous_total = 0;
6 static struct process *first_process = 0;
8 static struct process *find_process(pid_t pid)
10 struct process *p = first_process;
20 * Create a new process object and insert it into the process list
22 static struct process *new_process(int p)
24 struct process *process;
25 process = malloc(sizeof(struct process));
28 * Do stitching necessary for doubly linked list
31 process->previous = 0;
32 process->next = first_process;
34 process->next->previous = process;
35 first_process = process;
38 process->time_stamp = 0;
39 process->previous_user_time = INT_MAX;
40 process->previous_kernel_time = INT_MAX;
43 /* process_find_name(process);*/
48 /******************************************/
50 /******************************************/
52 static int process_parse_stat(struct process *);
53 static int update_process_table(void);
54 static int calculate_cpu(struct process *);
55 static void process_cleanup(void);
56 static void delete_process(struct process *);
57 /*inline void draw_processes(void);*/
58 static int calc_cpu_total(void);
59 static void calc_cpu_each(int);
60 void process_find_top(struct process **);
63 /******************************************/
64 /* Extract information from /proc */
65 /******************************************/
68 * These are the guts that extract information out of /proc.
69 * Anyone hoping to port wmtop should look here first.
71 static int process_parse_stat(struct process *process)
73 struct information *cur;
75 char line[BUFFER_LEN], filename[BUFFER_LEN], procname[BUFFER_LEN];
77 int user_time, kernel_time;
80 char deparenthesised_name[BUFFER_LEN];
84 snprintf(filename, sizeof(filename), PROCFS_TEMPLATE,
87 ps = open(filename, O_RDONLY);
90 * The process must have finished in the last few jiffies!
95 * Mark process as up-to-date.
97 process->time_stamp = g_time;
99 rc = read(ps, line, sizeof(line));
105 * Extract cpu times from data in /proc filesystem
108 "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d %*s %*s %*s %d %*s %*s %*s %d %d",
109 procname, &process->user_time, &process->kernel_time,
110 &nice_val, &process->vsize, &process->rss);
114 * Remove parentheses from the process name stored in /proc/ under Linux...
117 /* remove any "kdeinit: " */
118 if (r == strstr(r, "kdeinit")) {
119 snprintf(filename, sizeof(filename),
120 PROCFS_CMDLINE_TEMPLATE, process->pid);
122 ps = open(filename, O_RDONLY);
125 * The process must have finished in the last few jiffies!
129 endl = read(ps, line, sizeof(line));
132 /* null terminate the input */
134 /* account for "kdeinit: " */
135 if ((char *) line == strstr(line, "kdeinit: "))
136 r = ((char *) line) + 9;
140 q = deparenthesised_name;
142 while (*r && *r != ' ')
146 q = deparenthesised_name;
147 while (*r && *r != ')')
154 process->name = strdup(deparenthesised_name);
155 process->rss *= getpagesize();
158 update_total_processes();
160 process->totalmem = ( (float) process->rss / cur->memmax ) / 10;
162 if (process->previous_user_time == INT_MAX)
163 process->previous_user_time = process->user_time;
164 if (process->previous_kernel_time == INT_MAX)
165 process->previous_kernel_time = process->kernel_time;
167 /* store the difference of the user_time */
168 user_time = process->user_time - process->previous_user_time;
169 kernel_time = process->kernel_time - process->previous_kernel_time;
171 /* backup the process->user_time for next time around */
172 process->previous_user_time = process->user_time;
173 process->previous_kernel_time = process->kernel_time;
175 /* store only the difference of the user_time here... */
176 process->user_time = user_time;
177 process->kernel_time = kernel_time;
183 /******************************************/
184 /* Update process table */
185 /******************************************/
187 static int update_process_table()
190 struct dirent *entry;
192 if (!(dir = opendir("/proc")))
198 * Get list of processes from /proc directory
200 while ((entry = readdir(dir))) {
205 * Problem reading list of processes
211 if (sscanf(entry->d_name, "%d", &pid) > 0) {
213 p = find_process(pid);
215 p = new_process(pid);
217 /* compute each process cpu usage */
227 /******************************************/
228 /* Get process structure for process pid */
229 /******************************************/
232 * This function seems to hog all of the CPU time. I can't figure out why - it
235 static int calculate_cpu(struct process *process)
239 /* compute each process cpu usage by reading /proc/<proc#>/stat */
240 rc = process_parse_stat(process);
243 /*rc = process_parse_statm(process);
248 * Check name against the exclusion list
250 if (process->counted && exclusion_expression
251 && !regexec(exclusion_expression, process->name, 0, 0, 0))
252 process->counted = 0;
257 /******************************************/
258 /* Strip dead process entries */
259 /******************************************/
261 static void process_cleanup()
264 struct process *p = first_process;
266 struct process *current = p;
268 #if defined(PARANOID)
269 assert(p->id == 0x0badfeed);
270 #endif /* defined(PARANOID) */
274 * Delete processes that have died
276 if (current->time_stamp != g_time)
277 delete_process(current);
281 /******************************************/
282 /* Destroy and remove a process */
283 /******************************************/
285 static void delete_process(struct process *p)
287 #if defined(PARANOID)
288 assert(p->id == 0x0badfeed);
291 * Ensure that deleted processes aren't reused.
294 #endif /* defined(PARANOID) */
297 * Maintain doubly linked list.
300 p->next->previous = p->previous;
302 p->previous->next = p->next;
304 first_process = p->next;
311 /******************************************/
312 /* Calculate cpu total */
313 /******************************************/
315 static int calc_cpu_total()
320 char line[BUFFER_LEN];
321 int cpu, nice, system, idle;
323 ps = open("/proc/stat", O_RDONLY);
324 rc = read(ps, line, sizeof(line));
328 sscanf(line, "%*s %d %d %d %d", &cpu, &nice, &system, &idle);
329 total = cpu + nice + system + idle;
331 t = total - previous_total;
332 previous_total = total;
340 /******************************************/
341 /* Calculate each processes cpu */
342 /******************************************/
344 inline static void calc_cpu_each(int total)
346 struct process *p = first_process;
348 /*p->amount = total ?
349 (100.0 * (float) (p->user_time + p->kernel_time) /
351 p->amount = (100.0 * (p->user_time + p->kernel_time) / total);
353 /* if (p->amount > 100)
359 /******************************************/
360 /* Find the top processes */
361 /******************************************/
364 * Result is stored in decreasing order in best[0-9].
367 static struct process **sorttmp;
369 inline void process_find_top(struct process **best)
372 if (sorttmp == NULL) {
373 sorttmp = malloc(sizeof(struct process)*10);
374 assert(sorttmp != NULL);
379 total = calc_cpu_total(); /* calculate the total of the processor */
381 update_process_table(); /* update the table with process list */
382 calc_cpu_each(total); /* and then the percentage for each task */
383 process_cleanup(); /* cleanup list from exited processes */
386 * this is really ugly,
387 * not to mention probably not too efficient.
388 * the main problem is that there could be any number of processes,
389 * however we have to use a fixed size for the "best" array.
390 * right now i can't think of a better way to do this,
391 * although i'm sure there is one.
392 * Perhaps just using a linked list would be more effecient?
393 * I'm too fucking lazy to do that right now.
398 if(i<300 && pr->counted) {
403 /*ERR("too many processes, you will get innaccurate results from top");*/
412 while (sorttmp[i+1]->amount > sorttmp[i]->amount)
415 sorttmp[i] = sorttmp[i+1];
426 while (sorttmp[i]->amount > sorttmp[i-1]->amount)
429 sorttmp[i] = sorttmp[i-1];
439 best[i] = sorttmp[i];
446 while (sorttmp[i+1]->totalmem > sorttmp[i]->totalmem)
449 sorttmp[i] = sorttmp[i+1];
460 while (sorttmp[i]->totalmem > sorttmp[i-1]->totalmem)
463 sorttmp[i] = sorttmp[i-1];
473 best[i] = sorttmp[i];