[PATCH] New package CPUsage
[openwrt/svn-archive/archive.git] / utils / cpusage / src / cpusage.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <ctype.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <signal.h>
7 #include <stdlib.h>
8 #include <sys/types.h>
9 #include <sys/time.h>
10 #include <sys/resource.h>
11 #include <time.h>
12
13 #ifdef __FreeBSD__
14 #include <sys/sysctl.h>
15 #else
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #endif
20
21 #ifdef __FreeBSD__
22 static void getsysctl(char *, void *, size_t);
23 #define CPUSTATES 5
24 #define IDLEI 3
25 char *cpustatenames[] = {
26 "user", "nice", "system", "idle", "interrupt", NULL
27 };
28 #endif
29
30 #ifdef __Linux24__
31 #define CPUSTATES 4
32 #define IDLEI 3
33 char *cpustatenames[] = {
34 "user", "nice", "system", "idle", NULL
35 };
36 #endif
37
38 #ifdef __Linux26__
39 #define CPUSTATES 7
40 #define IDLEI 3
41 /* long names:
42 * user - nice - system - idle - iowait - irq - soft irq */
43 char *cpustatenames[] = {
44 "user", "nice", "system", "idle", "iowait", "irq", "softirq", NULL
45 };
46 #endif
47
48 #define LIMIT 95
49
50 static const char usage[] =
51 "\n usage: cpusage [ -hos ] [ -a | -l limit ] [ -c CPU ]\n";
52
53 char* appname;
54
55 static float cpu_perc[CPUSTATES];
56 static float cpu_max[CPUSTATES];
57 static float cpu_min[CPUSTATES];
58
59 int cpunum; /* -1 all, 0-n CPU/Core 0-n */
60
61 int output;
62
63 int breakloop;
64
65 /* returns 1-n yielding the number of CPU's/Cores */
66 int getNumCPU()
67 {
68 #ifdef __FreeBSD__
69 return 0;
70 #else
71
72 char buffer[32768];
73 int fd, len, i;
74 char * test;
75
76 fd = open("/proc/stat", O_RDONLY);
77 if(fd<=0)
78 fprintf(stderr, "%s: cannot open /proc/stat \n", appname);
79
80 len = read(fd, buffer, sizeof(buffer)-1);
81 close(fd);
82 buffer[len] = '\0';
83
84 i=0;
85
86 test = strstr(buffer, "cpu");
87 if (test != NULL ) {
88 test += sizeof("cpu");
89 test = strstr(test, "cpu");
90 }
91
92 while ( test != NULL ) {
93 test += sizeof("cpu");
94 /* fprintf(stderr, "%s: DEBUG: %s\n", appname, test); */
95 i++;
96 test = strstr(test, "cpu");
97 }
98 return i;
99 #endif
100 }
101
102 #ifdef __FreeBSD__
103 static void getsysctl (char *name, void *ptr, size_t len) {
104 size_t nlen = len;
105 long save;
106
107 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
108 fprintf(stderr, "%s: sysctl(%s...) failed: %s\n",
109 appname, name, strerror(errno));
110 exit(1);
111 }
112 if (nlen != len) {
113 fprintf(stderr, "%s: sysctl(%s...) expected %lu, got %lu\n",
114 appname, name, (unsigned long)len, (unsigned long)nlen);
115 exit(1);
116 }
117
118 /* swapping idle and interrupt to look like linux */
119 save = ((long*) ptr)[4];
120 ((long*) ptr)[4] = ((long*) ptr)[3];
121 ((long*) ptr)[3] = save;
122 }
123 #else
124 void getSysinfo(unsigned long *ptr, size_t size)
125 {
126 char buffer[4096];
127 char match[100];
128 char * start;
129 int fd, len, j;
130
131 for (j = 0; j<size; j++)
132 ptr[j]=0;
133
134 fd = open("/proc/stat", O_RDONLY);
135 if(fd<=0)
136 fprintf(stderr, "%s: cannot open /proc/stat\n", appname );
137
138 len = read(fd, buffer, sizeof(buffer)-1);
139 close(fd);
140 buffer[len] = '\0';
141
142
143 strcpy(match, "cpu ");
144 start = buffer;
145 if ( cpunum != -1 ) {
146 sprintf(match, "cpu%d ", cpunum);
147 start = strstr(buffer, match);
148 }
149
150 #ifdef __Linux26__
151 strcat(match, "%ld %ld %ld %ld %ld %ld %ld");
152 if ( sscanf(start, match, &ptr[0],
153 &ptr[1], &ptr[2], &ptr[3], &ptr[4], &ptr[5], &ptr[6]) != 7 ) {
154 fprintf(stderr, "%s: wrong /proc/stat format\n", appname);
155 }
156 #else
157 strcat(match, "%ld %ld %ld %ld");
158 if ( sscanf(start, match,
159 &ptr[0], &ptr[1], &ptr[2], &ptr[3]) != 4) {
160 fprintf(stderr, "%s: wrong /proc/stat format\n", appname);
161 }
162 #endif
163
164 }
165 #endif
166
167 long perc(int cpustates, long *cp_time, long *cp_old, long *cp_diff) {
168
169 int i = 0;
170 long total = 0;
171
172 for ( i = 0; i < cpustates; i++ ) {
173 cp_diff[i] = cp_time[i] - cp_old[i];
174 total += cp_diff[i];
175 }
176
177 for ( i = 0; i < cpustates; i++) {
178 cpu_perc[i] = ((float)cp_diff[i]*100.0 / total);
179 /* new max ? */
180 if ( cpu_perc[i] > cpu_max[i] )
181 cpu_max[i] = cpu_perc[i];
182 /* new min ? */
183 if ( cpu_perc[i] < cpu_min[i] )
184 cpu_min[i] = cpu_perc[i];
185 }
186
187 return total;
188 }
189
190 void print_perc(float *perc, const char *head){
191 int i;
192 time_t Zeitstempel;
193 struct tm *now;
194
195 /* human readable */
196 if ( (output == 0) && (head != ""))
197 printf("%s: ", head);
198
199 /* machine readable */
200 if ( (output == 1) && (head != ""))
201 printf("%s;", head);
202
203 /* timestamp */
204 time(&Zeitstempel);
205 now = localtime(&Zeitstempel);
206 if ( output == 0 )
207 printf("timestamp: %04d-%02d-%02d %02d.%02d.%02d, ", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
208 else
209 printf("%04d-%02d-%02d;%02d:%02d:%02d;", now->tm_year+1900, now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec);
210
211 if ( output == 0 )
212 printf("%s: %5.1f%%, ", cpustatenames[0], perc[0]);
213 else
214 printf("%.1f", perc[0]);
215
216 /* print out calculated information in percentages */
217 for ( i = 1; i < CPUSTATES; i++) {
218 if ( output == 0 )
219 printf("%s: %5.1f%%, ", cpustatenames[i], perc[i]);
220 else
221 printf(";%.1f", perc[i]);
222 }
223 printf("\n");
224 }
225
226 /* to catch Strg+C when looping */
227 void loop_term_handler (int signum) {
228 breakloop = 1;
229 }
230
231 int main(int argc, char** argv) {
232
233 appname = argv[0];
234
235 int i,c,limit;
236 int runonce; /* run just once and exit */
237 int avg; /* is avg measurement allready running */
238 int avg_run; /* did we allready had an avg measurement */
239 static long cp_time1[CPUSTATES];
240 static long cp_time2[CPUSTATES];
241 static long cp_avg_start[CPUSTATES];
242 static long cp_avg_stop[CPUSTATES];
243 static long cp_diff[CPUSTATES];
244
245 struct sigaction sigold, signew;
246
247 long *old = cp_time2;
248 long *new = cp_time1;
249
250 long total;
251 limit = LIMIT;
252 output = 0; /* 0: human readable; 1: machine readable */
253 runonce = 0; /* 0: run continuesly; 1: run once */
254
255 cpunum = -1; /* -1: all CPUs/Cores, 0-n: special CPU/Core */
256
257 /* reading commandline options */
258 while (1) {
259 c = getopt(argc, argv, "saohl:c:");
260
261 if (c == -1){
262 break;
263 }
264
265 switch(c){
266 /*run once and exit */
267 case 's':
268 runonce = 1;
269 break;
270 /* use avg from begin to end -> same as "-l 100" */
271 case 'a':
272 limit = 100;
273 break;
274 case 'o':
275 output = 1; /* machine readable */
276 // header for CSV output
277 printf("date;time;user;nice;system;idle;iowait;irq;softirq\n");
278 break;
279 /* print usage */
280 case 'h':
281 fprintf(stderr, "%s: %s", appname, usage);
282 exit(0);
283 break;
284 /* set limit */
285 case 'l':
286 if ( !(sscanf(optarg, "%d", &limit) == 1) ) {
287 fprintf(stderr, "%s: option for -l should be integer (is %s)\n",
288 appname, optarg);
289 exit(1);
290 }
291 break;
292 /* select CPU/Core */
293 case 'c':
294 if ( !(sscanf(optarg, "%d", &cpunum) == 1) ) {
295 fprintf(stderr, "%s: option for -c should be integer (is %s)\n",
296 appname, optarg);
297 exit(1);
298 }
299 break;
300
301 }
302 }
303
304 if (cpunum != -1) {
305 #ifdef __FreeBSD__
306 fprintf(stderr, "%s: No CPU/Core selection available for FreeBSD\n",
307 appname);
308 exit (1);
309 #else
310 int numcpu = getNumCPU();
311 if ( cpunum < numcpu ) {
312 printf("-- Selected CPU %d\n", cpunum );
313 } else {
314 if (numcpu == 1) {
315 fprintf(stderr, "%s: CPU %d not available (found %d CPU: [0])\n",
316 appname, cpunum, numcpu );
317 } else {
318 fprintf(stderr, "%s: CPU %d not available (found %d CPU's: [0]-[%d])\n ",
319 appname, cpunum, numcpu, numcpu - 1 );
320 }
321 exit(1);
322 }
323
324 #endif
325 }
326
327 breakloop = 0;
328
329 for (i=0; i < CPUSTATES; i++){
330 cpu_max[i] = 0;
331 cpu_min[i] = 100;
332 }
333
334 /* get information */
335 #ifdef __FreeBSD__
336 getsysctl("kern.cp_time", new, sizeof(cp_time1));
337 #else
338 getSysinfo((unsigned long*)new, CPUSTATES);
339 #endif
340
341 /* catch Strg+C when capturing to call pcap_breakloop() */
342 memset(&signew, 0, sizeof(signew));
343 signew.sa_handler = loop_term_handler;
344 if (sigaction(SIGINT, &signew, &sigold) < 0 ){
345 fprintf(stderr, "Could not set signal handler -> exiting");
346 }
347
348 avg = 0;
349 avg_run = 0;
350
351 if ( runonce ) {
352 breakloop=1;
353 }
354
355 while(1) {
356 usleep( 1000000 );
357
358 if ( new == cp_time1 ) {
359 new = cp_time2;
360 old = cp_time1;
361 } else{
362 new = cp_time1;
363 old = cp_time2;
364 }
365
366 /* get information again */
367 #ifdef __FreeBSD__
368 getsysctl("kern.cp_time", new, sizeof(cp_time1));
369 #else
370 getSysinfo((unsigned long*)new, CPUSTATES);
371 #endif
372
373 /* convert cp_time counts to percentages */
374 total = perc(CPUSTATES, new, old, cp_diff);
375
376 /* check for avg measurement start */
377 if ( !avg_run && !avg && (cpu_perc[IDLEI] <= limit) ){
378 avg = 1;
379 for ( i = 0; i < CPUSTATES; i++ )
380 cp_avg_start[i] = new[i];
381 }
382
383 /* check for avg measurement stop */
384 if ( !avg_run && avg && (cpu_perc[IDLEI] > limit) ){
385 avg = 0;
386 for ( i = 0; i < CPUSTATES; i++ )
387 cp_avg_stop[i] = new[i];
388 avg_run = 1;
389 }
390
391 print_perc(cpu_perc, "");
392
393 if (breakloop) {
394 if (avg) {
395 avg = 0;
396 for ( i = 0; i < CPUSTATES; i++ )
397 cp_avg_stop[i] = new[i];
398 }
399 break;
400 }
401 }
402
403 /* Set default behaviour when loop is done */
404 if (sigaction(SIGINT, &sigold, &signew) < 0 ){
405 fprintf(stderr, "%s: Could not restore signal handler -> exiting", appname);
406 }
407
408 if ( ! runonce && output == 0) {
409 // print avg only when not making a one-shot msg and
410 // when not writing CSV output
411 printf("---Summary----\n");
412
413 print_perc(cpu_min, "Min");
414
415 print_perc(cpu_max, "Max");
416
417 perc(CPUSTATES, cp_avg_start, cp_avg_stop, cp_diff);
418
419 print_perc(cpu_perc, "Avg");
420 }
421
422 return 0;
423 }
424
425
426