wmcpuwatch: wmcpuwatch.c Source File

| 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 }
clear_widgets
void clear_widgets(void)
Clear both widgets.
Definition: wmcpuwatch.c:230
stat_dev::idle_last
ullong * idle_last
Values for last idle cpu times.
Definition: wmcpuwatch.c:71
stat_dev::statlast
ullong statlast
Field for the last value of the average cpu load.
Definition: wmcpuwatch.c:64
initialize_stat_device
void initialize_stat_device(stat_dev *, int, const char *)
Initialize stat_device struct.
Definition: wmcpuwatch.c:253
stat_dev
Struct to keep CPU load data.
Definition: wmcpuwatch.c:62
update_stat_cpu
void update_stat_cpu(FILE *, stat_dev *, ullong *, ullong *, int)
Update CPU stats.
Definition: wmcpuwatch.c:278
main
int main(int argc, char *argv[])
Main function.
Definition: wmcpuwatch.c:108
stat_dev::idle_stat
long * idle_stat
Fields for all cpu idle times.
Definition: wmcpuwatch.c:70
usage
void usage(char *)
Definition: wmcpuwatch.c:417
print_version
void print_version(void)
Definition of current version.
Definition: wmcpuwatch.c:441
MAX_HEIGHT
#define MAX_HEIGHT
Definition: wmcpuwatch.c:52
MAX_CPU
#define MAX_CPU
Definition: wmcpuwatch.c:51
get_width
unsigned long get_width(long, long, long)
Get widht of active part.
Definition: wmcpuwatch.c:364
get_number_of_CPU
int get_number_of_CPU(FILE *)
Returns the number of CPUs.
Definition: wmcpuwatch.c:394
stat_dev::rt_idle
long rt_idle
Field for current average cpu idle time.
Definition: wmcpuwatch.c:65
stat_dev::idlelast
ullong idlelast
Field for the last average idle time value of the cpu.
Definition: wmcpuwatch.c:66
stat_dev::rt_stat
long rt_stat
Field for current average cpu load.
Definition: wmcpuwatch.c:63
wmcpuwatch
void wmcpuwatch(int, char **)
Actual function for the dockapp.
Definition: wmcpuwatch.c:151
stat_dev::cpu_last
ullong * cpu_last
Values for last cpu load.
Definition: wmcpuwatch.c:69
get_statistics
void get_statistics(FILE *, ullong *, ullong *, ullong *, ullong *)
Parses /proc/stat and gets required values.
Definition: wmcpuwatch.c:311
stat_dev::cpu_stat
long * cpu_stat
Fields for all cpu loads.
Definition: wmcpuwatch.c:68