wmcpuwatch  0.1
Window Maker dockapp to display the cpu load of all CPUs
wmcpuwatch.c
Go to the documentation of this file.
1 /*
2  wmcpuwatch - WindowMaker dock app to watch all CPUs of a system
3  Copyright (C) 2017 Andreas Tscharner <andy@vis.ethz.ch>
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
35 #define _GNU_SOURCE
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include <sys/wait.h>
41 
42 #include <libdockapp/wmgeneral.h>
43 #include <libdockapp/misc.h>
44 
45 #include "ulllib.h"
46 #include "wmcpuwatch-master.xpm"
47 #include "wmcpuwatch-mask.xbm"
48 
49 #include "config.h"
50 
51 #define MAX_CPU (40)
52 #define MAX_HEIGHT (9)
55 /* Type definition */
56 
62 typedef struct {
63  long rt_stat;
64  ullong statlast;
65  long rt_idle;
66  ullong idlelast;
67  /* Processors stats */
68  long *cpu_stat;
69  ullong *cpu_last;
70  long *idle_stat;
71  ullong *idle_last;
72 } stat_dev;
73 
74 
75 /* Forward declarations
76  See the implementation for detailed description */
77 void usage(char*);
78 void print_version(void);
79 void wmcpuwatch(int, char **);
80 void clear_widgets(void);
81 void initialize_stat_device(stat_dev *, int, const char *);
82 int get_number_of_CPU(FILE *);
83 void get_statistics(FILE *, ullong *, ullong *, ullong *, ullong *);
84 void update_stat_cpu(FILE *, stat_dev *, ullong *, ullong *, int);
85 unsigned long get_width(long, long, long);
86 
87 
108 int main(int argc, char *argv[])
109 {
110  char *name = argv[0];
111 
112  /* Parse Command Line */
113  for (int i = 1; i < argc; i++) {
114  char *arg = argv[i];
115 
116  if (*arg=='-')
117  switch (arg[1]) {
118  case 'd' :
119  if (strcmp(arg+1, "display")) {
120  usage(name);
121  return 1;
122  }
123  break;
124  case 'g' :
125  if (strcmp(arg+1, "geometry")) {
126  usage(name);
127  return 1;
128  }
129  case 'v' :
130  print_version();
131  return 0;
132  default:
133  usage(name);
134  return 1;
135  }
136  }
137 
138  wmcpuwatch(argc, argv);
139  exit(0);
140 }
141 
142 
151 void wmcpuwatch(int argc, char **argv)
152 {
153  FILE *fp_stat;
154  XEvent Event;
155  ullong istat, idle, *istat2, *idle2;
156  stat_dev stat_device;
157  int nb_cpu;
158 
159 
160  fp_stat = fopen("/proc/stat", "r");
161  nb_cpu = get_number_of_CPU(fp_stat);
162 
163  initialize_stat_device(&stat_device, nb_cpu, argv[0]);
164 
165  istat2 = calloc(nb_cpu, sizeof(ullong));
166  idle2 = calloc(nb_cpu, sizeof(ullong));
167  if (!istat2 || !idle2) {
168  fprintf(stderr, "%s: Unable to alloc memory !!\n", argv[0]);
169  exit(1);
170  }
171 
172  openXwindow(argc, argv, wmcpuwatch_master_xpm, (char *)wmcpuwatch_mask_bits,
173  wmcpuwatch_mask_width, wmcpuwatch_mask_height);
174 
175  /* Collect information on each panel */
176  get_statistics(fp_stat, &istat, &idle, istat2, idle2);
177  stat_device.statlast = istat;
178  stat_device.idlelast = idle;
179 
180  for (int cpu = 0; cpu < nb_cpu; cpu++) {
181  stat_device.cpu_last[cpu] = istat2[cpu];
182  stat_device.idle_last[cpu] = idle2[cpu];
183  }
184 
185  while (1) {
186  waitpid(0, NULL, WNOHANG);
187 
188  update_stat_cpu(fp_stat, &stat_device, istat2, idle2, nb_cpu);
189 
190  /* Clear both widgets */
191  clear_widgets();
192 
193  /* show average CPU */
194  int j = get_width(stat_device.rt_stat, stat_device.rt_idle, 32);
195  copyXPMArea(32, 64, j, 12, 28, 4);
196 
197  /* show all CPUs */
198  int h = (MAX_CPU / nb_cpu) > MAX_HEIGHT ? MAX_HEIGHT : MAX_CPU / nb_cpu;
199  for (int cpu = 0; cpu < nb_cpu; cpu++) {
200  j = get_width(stat_device.cpu_stat[cpu], stat_device.idle_stat[cpu], 56);
201  copyXPMArea(1, 95, j, h, 5, 19 + h * cpu);
202  }
203 
204  RedrawWindow();
205 
206  while (XPending(display)) {
207  XNextEvent(display, &Event);
208  switch (Event.type) {
209  case Expose:
210  RedrawWindow();
211  break;
212  case DestroyNotify:
213  XCloseDisplay(display);
214  exit(0);
215  break;
216  }
217  }
218  usleep(250000L);
219  }
220 
221  fclose(fp_stat);
222 }
223 
224 
230 void clear_widgets(void)
231 {
232  /* Clear average load */
233  copyXPMArea(0, 64, 32, 12, 28, 4);
234 
235  /* Clear full field */
236  copyXPMArea(0, 80, 56, 10, 4, 18);
237  copyXPMArea(0, 81, 56, 9, 4, 27);
238  copyXPMArea(0, 81, 56, 9, 4, 36);
239  copyXPMArea(0, 81, 56, 9, 4, 45);
240  copyXPMArea(0, 81, 56, 4, 4, 54);
241  copyXPMArea(0, 75, 56, 1, 4, 58);
242 }
243 
253 void initialize_stat_device(stat_dev *statdevice, int cpucount, const char *dockappname)
254 {
255  statdevice->cpu_stat = calloc(cpucount, sizeof(long));
256  statdevice->cpu_last = calloc(cpucount, sizeof(ullong));
257  statdevice->idle_stat = calloc(cpucount, sizeof(long));
258  statdevice->idle_last = calloc(cpucount, sizeof(ullong));
259  if (!statdevice->cpu_stat ||
260  !statdevice->cpu_last ||
261  !statdevice->idle_stat ||
262  !statdevice->idle_last) {
263  fprintf(stderr, "%s: Unable to alloc memory !\n", dockappname);
264  exit(1);
265  }
266 }
267 
278 void update_stat_cpu(FILE *fpstat, stat_dev *st, ullong *istat2, ullong *idle2, int cpucount)
279 {
280  ullong istat, idle;
281 
282  get_statistics(fpstat, &istat, &idle, istat2, idle2);
283 
284  st->rt_idle = ullsub(&idle, &st->idlelast);
285  st->idlelast = idle;
286 
287  st->rt_stat = ullsub(&istat, &st->statlast);
288  st->statlast = istat;
289 
290  for (int cpu = 0; cpu < cpucount; cpu++) {
291  st->idle_stat[cpu] = ullsub(&idle2[cpu], &st->idle_last[cpu]);
292  st->idle_last[cpu] = idle2[cpu];
293 
294  st->cpu_stat[cpu] = ullsub(&istat2[cpu], &st->cpu_last[cpu]);
295  st->cpu_last[cpu] = istat2[cpu];
296  }
297 }
298 
299 
311 void get_statistics(FILE *fpstat, ullong *ds, ullong *idle, ullong *ds2, ullong *idle2)
312 {
313  static char *line = NULL;
314  static size_t line_size = 0;
315  char *p;
316  char *tokens = " \t\n";
317  ullong ulltmp;
318 
319 
320  ullreset(ds);
321  ullreset(idle);
322 
323  fseek(fpstat, 0, SEEK_SET);
324  while ((getline(&line, &line_size, fpstat)) > 0) {
325  if (strstr(line, "cpu")) {
326  int cpu = -1; /* by default, cumul stats => average */
327  if (!strstr(line, "cpu ")) {
328  sscanf(line, "cpu%d", &cpu);
329  ullreset(&ds2[cpu]);
330  ullreset(&idle2[cpu]);
331  }
332 
333  p = strtok(line, tokens);
334  /* 1..3, 4 == idle, we don't want idle! */
335  for (int i=0; i<3; i++) {
336  p = strtok(NULL, tokens);
337  ullparse(&ulltmp, p);
338  if (cpu == -1)
339  ulladd(ds, &ulltmp);
340  else
341  ulladd(&ds2[cpu], &ulltmp);
342  }
343 
344  p = strtok(NULL, tokens);
345  if (cpu == -1)
346  ullparse(idle, p);
347  else
348  ullparse(&idle2[cpu], p);
349  }
350  }
351 }
352 
353 
364 unsigned long get_width(long actif, long idle, long line_len)
365 {
366  /* wbk - work with a decimal value so we don't round < 1 down to zero. */
367  double j = 0;
368 
369  j = (actif + idle);
370  if (j != 0)
371  j = (actif * 100) / j;
372 
373  j = j * (double)(line_len / 100.0);
374 
375  /* round up very low positive values so they are visible. */
376  if (actif > 0 && j < 2)
377  j = 2;
378 
379  if (j > line_len)
380  j = (double)line_len;
381 
382  return (unsigned long) j;
383 }
384 
385 
394 int get_number_of_CPU(FILE *fpstat)
395 {
396  static char *line = NULL;
397  static size_t line_size = 0;
398  int cpu = 0;
399 
400  fseek(fpstat, 0, SEEK_SET);
401  while ((getline(&line, &line_size, fpstat)) > 0) {
402  if (strstr(line, "cpu") && !strstr(line, "cpu "))
403  sscanf(line, "cpu%d", &cpu);
404  }
405 
406  return cpu+1;
407 }
408 
409 
417 void usage(char *name)
418 {
419  printf("\n wmcpuwatch Copyright (C) 2017 Andreas Tscharner\n");
420  printf(" This program comes with ABSOLUTELY NO WARRANTY;\n");
421  printf(" This is free software, and you are welcome to\n");
422  printf(" redistribute it under certain conditions;\n");
423  printf("\n\n");
424  printf("Usage: %s [OPTION]...\n", name);
425  printf("WindowMaker dockapp that displays the cpu load of all CPUs.\n");
426  printf(" -display DISPLAY contact the DISPLAY X server\n");
427  printf(" -geometry GEOMETRY position the dockapp at GEOMETRY\n");
428  printf(" -h display this help and exit\n");
429  printf(" -v output version information and exit\n");
430 }
431 
432 
441 void print_version(void)
442 {
443  printf("wmcpuwatch version %s\n", PACKAGE_VERSION);
444 }
void clear_widgets(void)
Clear both widgets.
Definition: wmcpuwatch.c:230
ullong * idle_last
Values for last idle cpu times.
Definition: wmcpuwatch.c:71
ullong statlast
Field for the last value of the average cpu load.
Definition: wmcpuwatch.c:64
void initialize_stat_device(stat_dev *, int, const char *)
Initialize stat_device struct.
Definition: wmcpuwatch.c:253
Struct to keep CPU load data.
Definition: wmcpuwatch.c:62
void update_stat_cpu(FILE *, stat_dev *, ullong *, ullong *, int)
Update CPU stats.
Definition: wmcpuwatch.c:278
int main(int argc, char *argv[])
Main function.
Definition: wmcpuwatch.c:108
long * idle_stat
Fields for all cpu idle times.
Definition: wmcpuwatch.c:70
void usage(char *)
Definition: wmcpuwatch.c:417
void print_version(void)
Definition of current version.
Definition: wmcpuwatch.c:441
#define MAX_HEIGHT
Definition: wmcpuwatch.c:52
#define MAX_CPU
Definition: wmcpuwatch.c:51
unsigned long get_width(long, long, long)
Get widht of active part.
Definition: wmcpuwatch.c:364
int get_number_of_CPU(FILE *)
Returns the number of CPUs.
Definition: wmcpuwatch.c:394
long rt_idle
Field for current average cpu idle time.
Definition: wmcpuwatch.c:65
ullong idlelast
Field for the last average idle time value of the cpu.
Definition: wmcpuwatch.c:66
long rt_stat
Field for current average cpu load.
Definition: wmcpuwatch.c:63
void wmcpuwatch(int, char **)
Actual function for the dockapp.
Definition: wmcpuwatch.c:151
ullong * cpu_last
Values for last cpu load.
Definition: wmcpuwatch.c:69
void get_statistics(FILE *, ullong *, ullong *, ullong *, ullong *)
Parses /proc/stat and gets required values.
Definition: wmcpuwatch.c:311
long * cpu_stat
Fields for all cpu loads.
Definition: wmcpuwatch.c:68