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