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);
62 /******************************************/
63 /* Extract information from /proc */
64 /******************************************/
67 * These are the guts that extract information out of /proc.
68 * Anyone hoping to port wmtop should look here first.
70 static int process_parse_stat(struct process *process)
72 struct information *cur;
74 char line[BUFFER_LEN], filename[BUFFER_LEN], procname[BUFFER_LEN];
76 int user_time, kernel_time;
79 char deparenthesised_name[BUFFER_LEN];
83 snprintf(filename, sizeof(filename), PROCFS_TEMPLATE,
86 ps = open(filename, O_RDONLY);
89 * The process must have finished in the last few jiffies!
94 * Mark process as up-to-date.
96 process->time_stamp = g_time;
98 rc = read(ps, line, sizeof(line));
104 * Extract cpu times from data in /proc filesystem
107 "%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d %*s %*s %*s %d %*s %*s %*s %d %d",
108 procname, &process->user_time, &process->kernel_time,
109 &nice_val, &process->vsize, &process->rss);
113 * Remove parentheses from the process name stored in /proc/ under Linux...
116 /* remove any "kdeinit: " */
117 if (r == strstr(r, "kdeinit")) {
118 snprintf(filename, sizeof(filename),
119 PROCFS_CMDLINE_TEMPLATE, process->pid);
121 ps = open(filename, O_RDONLY);
124 * The process must have finished in the last few jiffies!
128 endl = read(ps, line, sizeof(line));
131 /* null terminate the input */
133 /* account for "kdeinit: " */
134 if ((char *) line == strstr(line, "kdeinit: "))
135 r = ((char *) line) + 9;
139 q = deparenthesised_name;
141 while (*r && *r != ' ')
145 q = deparenthesised_name;
146 while (*r && *r != ')')
153 process->name = strdup(deparenthesised_name);
154 process->rss *= getpagesize();
157 update_total_processes();
159 process->totalmem = ( (float) process->rss / cur->memmax ) / 10;
161 if (process->previous_user_time == INT_MAX)
162 process->previous_user_time = process->user_time;
163 if (process->previous_kernel_time == INT_MAX)
164 process->previous_kernel_time = process->kernel_time;
166 /* store the difference of the user_time */
167 user_time = process->user_time - process->previous_user_time;
168 kernel_time = process->kernel_time - process->previous_kernel_time;
170 /* backup the process->user_time for next time around */
171 process->previous_user_time = process->user_time;
172 process->previous_kernel_time = process->kernel_time;
174 /* store only the difference of the user_time here... */
175 process->user_time = user_time;
176 process->kernel_time = kernel_time;
182 /******************************************/
183 /* Update process table */
184 /******************************************/
186 static int update_process_table()
189 struct dirent *entry;
191 if (!(dir = opendir("/proc")))
197 * Get list of processes from /proc directory
199 while ((entry = readdir(dir))) {
204 * Problem reading list of processes
210 if (sscanf(entry->d_name, "%d", &pid) > 0) {
212 p = find_process(pid);
214 p = new_process(pid);
216 /* compute each process cpu usage */
226 /******************************************/
227 /* Get process structure for process pid */
228 /******************************************/
231 * This function seems to hog all of the CPU time. I can't figure out why - it
234 static int calculate_cpu(struct process *process)
238 /* compute each process cpu usage by reading /proc/<proc#>/stat */
239 rc = process_parse_stat(process);
242 /*rc = process_parse_statm(process);
247 * Check name against the exclusion list
249 if (process->counted && exclusion_expression
250 && !regexec(exclusion_expression, process->name, 0, 0, 0))
251 process->counted = 0;
256 /******************************************/
257 /* Strip dead process entries */
258 /******************************************/
260 static void process_cleanup()
263 struct process *p = first_process;
265 struct process *current = p;
267 #if defined(PARANOID)
268 assert(p->id == 0x0badfeed);
269 #endif /* defined(PARANOID) */
273 * Delete processes that have died
275 if (current->time_stamp != g_time)
276 delete_process(current);
280 /******************************************/
281 /* Destroy and remove a process */
282 /******************************************/
284 static void delete_process(struct process *p)
286 #if defined(PARANOID)
287 assert(p->id == 0x0badfeed);
290 * Ensure that deleted processes aren't reused.
293 #endif /* defined(PARANOID) */
296 * Maintain doubly linked list.
299 p->next->previous = p->previous;
301 p->previous->next = p->next;
303 first_process = p->next;
310 /******************************************/
311 /* Calculate cpu total */
312 /******************************************/
314 static int calc_cpu_total()
319 char line[BUFFER_LEN];
320 int cpu, nice, system, idle;
322 ps = open("/proc/stat", O_RDONLY);
323 rc = read(ps, line, sizeof(line));
327 sscanf(line, "%*s %d %d %d %d", &cpu, &nice, &system, &idle);
328 total = cpu + nice + system + idle;
330 t = total - previous_total;
331 previous_total = total;
339 /******************************************/
340 /* Calculate each processes cpu */
341 /******************************************/
343 inline static void calc_cpu_each(int total)
345 struct process *p = first_process;
347 /*p->amount = total ?
348 (100.0 * (float) (p->user_time + p->kernel_time) /
350 p->amount = (100.0 * (p->user_time + p->kernel_time) / total);
352 /* if (p->amount > 100)
358 /******************************************/
359 /* Find the top processes */
360 /******************************************/
363 * Result is stored in decreasing order in best[0-9].
366 static struct process **sorttmp;
367 static size_t sorttmp_size = 10;
369 inline void process_find_top(struct process **cpu, struct process **mem)
372 if (sorttmp == NULL) {
373 sorttmp = malloc(sizeof(struct process)*sorttmp_size);
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.
399 if(i<sorttmp_size && pr->counted) {
403 else if (i == sorttmp_size && pr->counted) {
405 sorttmp = realloc(sorttmp, sizeof(struct process)*sorttmp_size);
411 if (i+1 < sorttmp_size) {
412 sorttmp = realloc(sorttmp, sizeof(struct process)*sorttmp_size);
417 while (sorttmp[i+1]->amount > sorttmp[i]->amount)
420 sorttmp[i] = sorttmp[i+1];
431 while (sorttmp[i]->amount > sorttmp[i-1]->amount)
434 sorttmp[i] = sorttmp[i-1];
452 if(i<sorttmp_size && pr->counted) {
456 else if (i == sorttmp_size && pr->counted) {
458 sorttmp = realloc(sorttmp, sizeof(struct process)*sorttmp_size);
464 if (i+1 < sorttmp_size) {
465 sorttmp = realloc(sorttmp, sizeof(struct process)*sorttmp_size);
469 while (sorttmp[i+1]->totalmem > sorttmp[i]->totalmem)
472 sorttmp[i] = sorttmp[i+1];
483 while (sorttmp[i]->totalmem > sorttmp[i-1]->totalmem)
486 sorttmp[i] = sorttmp[i-1];