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 */
62typedef 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 */
77void usage(char*);
78void print_version(void);
79void wmcpuwatch(int, char **);
80void clear_widgets(void);
81void initialize_stat_device(stat_dev *, int, const char *);
82int get_number_of_CPU(FILE *);
83void get_statistics(FILE *, ullong *, ullong *, ullong *, ullong *);
84void update_stat_cpu(FILE *, stat_dev *, ullong *, ullong *, int);
85unsigned long get_width(long, long, long);
86
87
108int 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' :
131 return 0;
132 default:
133 usage(name);
134 return 1;
135 }
136 }
137
138 wmcpuwatch(argc, argv);
139 exit(0);
140}
141
142
151void 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 */
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
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
253void 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
278void 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
311void 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
364unsigned 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
394int 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
417void 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
442{
443 printf("wmcpuwatch version %s\n", PACKAGE_VERSION);
444}
Struct to keep CPU load data.
Definition: wmcpuwatch.c:62
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
long * cpu_stat
Fields for all cpu loads.
Definition: wmcpuwatch.c:68
ullong idlelast
Field for the last average idle time value of the cpu.
Definition: wmcpuwatch.c:66
long * idle_stat
Fields for all cpu idle times.
Definition: wmcpuwatch.c:70
long rt_idle
Field for current average cpu idle time.
Definition: wmcpuwatch.c:65
long rt_stat
Field for current average cpu load.
Definition: wmcpuwatch.c:63
ullong * cpu_last
Values for last cpu load.
Definition: wmcpuwatch.c:69
int main(int argc, char *argv[])
Main function.
Definition: wmcpuwatch.c:108
#define MAX_CPU
Definition: wmcpuwatch.c:51
void update_stat_cpu(FILE *, stat_dev *, ullong *, ullong *, int)
Update CPU stats.
Definition: wmcpuwatch.c:278
void get_statistics(FILE *, ullong *, ullong *, ullong *, ullong *)
Parses /proc/stat and gets required values.
Definition: wmcpuwatch.c:311
void wmcpuwatch(int, char **)
Actual function for the dockapp.
Definition: wmcpuwatch.c:151
int get_number_of_CPU(FILE *)
Returns the number of CPUs.
Definition: wmcpuwatch.c:394
unsigned long get_width(long, long, long)
Get widht of active part.
Definition: wmcpuwatch.c:364
#define MAX_HEIGHT
Definition: wmcpuwatch.c:52
void initialize_stat_device(stat_dev *, int, const char *)
Initialize stat_device struct.
Definition: wmcpuwatch.c:253
void print_version(void)
Definition of current version.
Definition: wmcpuwatch.c:441
void clear_widgets(void)
Clear both widgets.
Definition: wmcpuwatch.c:230
void usage(char *)
Definition: wmcpuwatch.c:417