add packages_10.03.2 in preparation for the 10.03.2 interim release
[10.03/packages.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