Warning: That file was not part of the compilation database. It may have many parsing errors.

1/*
2 KSysGuard, the KDE System Guard
3
4 Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
5 Copyright (c) 2010 David Naylor <naylor.b.david@gmail.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21*/
22
23#include <sys/types.h>
24
25#include <sys/resource.h>
26#include <sys/sysctl.h>
27
28#include <devstat.h>
29#include <fcntl.h>
30#include <nlist.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35#include "cpuinfo.h"
36#include "Command.h"
37#include "ksysguardd.h"
38
39#define FREQ_LEVEL_BUFFER 256
40#define SYSCTL_ID_LEN 35
41
42static void get_mmfreq(int, int*, int*);
43
44static long percentages(int cnt, long *out, long *new, long *old, long *diffs);
45
46static long (*cp_time)[CPUSTATES] = NULL;
47static long (*cp_old)[CPUSTATES] = NULL;
48static long (*cp_diff)[CPUSTATES] = NULL;
49
50static int maxcpus = 1;
51static int cpus = 1;
52static int cores = 1;
53static int (*freq)[3] = NULL;
54static int *temp = NULL;
55
56static long (*cpu_states)[CPUSTATES] = NULL;
57
58void
59initCpuInfo(struct SensorModul* sm)
60{
61 size_t len;
62 int id;
63 char name[SYSCTL_ID_LEN];
64 int minfreq, maxfreq;
65
66 len = sizeof(cpus);
67 /* XXX: this is a guess */
68 sysctlbyname("kern.smp.active", &cpus, &len, NULL, 0);
69 /* NOTE: cpus may be 0, which implies 1 */
70 cpus = cpus ? cpus : 1;
71
72 len = sizeof(cores);
73 sysctlbyname("kern.smp.cpus", &cores, &len, NULL, 0);
74
75 len = sizeof(maxcpus);
76 sysctlbyname("kern.smp.maxcpus", &maxcpus, &len, NULL, 0);
77
78 /* Core/process count */
79 registerMonitor("system/processors", "integer", printNumCpus, printNumCpusInfo, sm);
80 registerMonitor("system/cores", "integer", printNumCores, printNumCoresInfo, sm);
81
82 /*
83 * CPU Loads
84 */
85 if ((cp_time = malloc(sizeof(long) * CPUSTATES * (cores * 4 + 1))) == NULL) {
86 log_error("out of memory for cp_time");
87 return;
88 }
89 cp_old = &cp_time[cores];
90 cp_diff = &cp_old[cores];
91 cpu_states = &cp_diff[cores];
92
93 /* Total CPU load */
94 registerMonitor("cpu/system/user", "float", printCPUUser, printCPUUserInfo, sm);
95 registerMonitor("cpu/system/nice", "float", printCPUNice, printCPUNiceInfo, sm);
96 registerMonitor("cpu/system/sys", "float", printCPUSys, printCPUSysInfo, sm);
97 registerMonitor("cpu/system/TotalLoad", "float", printCPUTotalLoad, printCPUTotalLoadInfo, sm);
98 registerMonitor("cpu/system/intr", "float", printCPUIntr, printCPUIntrInfo, sm);
99 registerMonitor("cpu/system/idle", "float", printCPUIdle, printCPUIdleInfo, sm);
100
101 /* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
102 registerLegacyMonitor("cpu/user", "float", printCPUUser, printCPUUserInfo, sm);
103 registerLegacyMonitor("cpu/nice", "float", printCPUNice, printCPUNiceInfo, sm);
104 registerLegacyMonitor("cpu/sys", "float", printCPUSys, printCPUSysInfo, sm);
105 registerLegacyMonitor("cpu/idle", "float", printCPUIdle, printCPUIdleInfo, sm);
106
107 for (id = 0; id < cores; ++id) {
108 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/user", id);
109 registerMonitor(name, "float", printCPUxUser, printCPUxUserInfo, sm);
110 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/nice", id);
111 registerMonitor(name, "float", printCPUxNice, printCPUxNiceInfo, sm);
112 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/sys", id);
113 registerMonitor(name, "float", printCPUxSys, printCPUxSysInfo, sm);
114 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/TotalLoad", id);
115 registerMonitor(name, "float", printCPUxTotalLoad, printCPUxTotalLoadInfo, sm);
116 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/intr", id);
117 registerMonitor(name, "float", printCPUxIntr, printCPUxIntrInfo, sm);
118 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/idle", id);
119 registerMonitor(name, "float", printCPUxIdle, printCPUxIdleInfo, sm);
120 }
121
122 /*
123 * CPU frequencies
124 */
125 if ((freq = malloc(sizeof(int) * 3 * (cores + 1))) == NULL) {
126 log_error("out of memory for freq");
127 return;
128 }
129
130 registerMonitor("cpu/system/AverageClock", "float", printCPUClock, printCPUClockInfo, sm);
131 for (id = 0; id < cores; ++id) {
132 len = sizeof(int);
133 snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.freq", id);
134 if (!sysctlbyname(name, &freq[id][0], &len, NULL, 0)) {
135 get_mmfreq(id, &freq[id][1], &freq[id][2]);
136 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/clock", id);
137 registerMonitor(name, "integer", printCPUxClock, printCPUxClockInfo, sm);
138 } else {
139 freq[id][0] = -1;
140 freq[id][1] = 0;
141 freq[id][2] = 0;
142 }
143 }
144
145 minfreq = freq[0][1];
146 maxfreq = freq[0][2];
147 for (id = 1; id < cores; ++id)
148 if (freq[id][0] != -1) {
149 minfreq = minfreq > freq[id][1] ? freq[id][1] : minfreq;
150 maxfreq = maxfreq < freq[id][2] ? freq[id][2] : maxfreq;
151 }
152 freq[cores][1] = minfreq;
153 freq[cores][2] = maxfreq;
154
155 /*
156 * CPU temperature
157 */
158 if ((temp = malloc(sizeof(int) * (cores + 1))) == NULL) {
159 log_error("out of memory for temp");
160 return;
161 }
162 registerMonitor("cpu/system/AverageTemperature", "float", printCPUTemperature, printCPUTemperatureInfo, sm);
163 for (id = 0; id < cores; ++id) {
164 len = sizeof(int);
165 snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.temperature", id);
166 if (!sysctlbyname(name, &temp[id], &len, NULL, 0)) {
167 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/temperature", id);
168 registerMonitor(name, "float", printCPUxTemperature, printCPUxTemperatureInfo, sm);
169 } else
170 temp[id] = -1;
171 }
172
173 updateCpuInfo();
174}
175
176void
177exitCpuInfo(void)
178{
179 int id;
180 char name[SYSCTL_ID_LEN];
181
182 removeMonitor("system/processors");
183 removeMonitor("system/cores");
184
185 if (cp_time != NULL) {
186 removeMonitor("cpu/system/user");
187 removeMonitor("cpu/system/nice");
188 removeMonitor("cpu/system/sys");
189 removeMonitor("cpu/system/TotalLoad");
190 removeMonitor("cpu/system/intr");
191 removeMonitor("cpu/system/idle");
192
193 /* These were registered as legacy monitors */
194 removeMonitor("cpu/user");
195 removeMonitor("cpu/nice");
196 removeMonitor("cpu/sys");
197 removeMonitor("cpu/idle");
198
199 for (id = 0; id < cores; ++id) {
200 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/user", id);
201 removeMonitor(name);
202 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/nice", id);
203 removeMonitor(name);
204 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/sys", id);
205 removeMonitor(name);
206 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/TotalLoad", id);
207 removeMonitor(name);
208 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/intr", id);
209 removeMonitor(name);
210 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/idle", id);
211 removeMonitor(name);
212
213 if (freq != NULL && freq[id][0] != -1) {
214 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/clock", id);
215 removeMonitor(name);
216 }
217 if (temp != NULL && temp[id] != -1) {
218 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/temperature", id);
219 removeMonitor(name);
220 }
221 }
222
223 free(cp_time);
224 cp_time = NULL;
225 }
226
227 if (freq != NULL) {
228 removeMonitor("cpu/system/AverageClock");
229 for (id = 0; id < cores; ++id)
230 if (freq[id][0] != -1) {
231 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/clock", id);
232 removeMonitor(name);
233 }
234 free(freq);
235 freq = NULL;
236 }
237
238 if (temp != NULL) {
239 removeMonitor("cpu/system/AverageTemperature");
240 for (id = 0; id < cores; ++id)
241 if (temp[id] != -1) {
242 snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/temperature", id);
243 removeMonitor(name);
244 }
245 free(temp);
246 temp = NULL;
247 }
248
249}
250
251int
252updateCpuInfo(void)
253{
254 int sid, id, tot_freq = 0, tot_temp = 0, freq_count = 0, temp_count = 0;
255 char name[SYSCTL_ID_LEN];
256
257 if (cp_time == NULL || freq == NULL || temp == NULL)
258 return (0);
259
260 size_t len = sizeof(long) * CPUSTATES * cores;
261 sysctlbyname("kern.cp_times", cp_time, &len, NULL, 0);
262 for (sid = 0; sid < CPUSTATES; ++sid)
263 cpu_states[cores][sid] = 0;
264 for (id = 0; id < cores; ++id) {
265 percentages(CPUSTATES, cpu_states[id], cp_time[id], cp_old[id], cp_diff[id]);
266 for (sid = 0; sid < CPUSTATES; ++sid)
267 cpu_states[cores][sid] += cpu_states[id][sid];
268 }
269 for (id = 0; id < cores; ++id) {
270 if (freq[id][0] != -1) {
271 len = sizeof(int);
272 snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.freq", id);
273 freq[id][0] = 0;
274 if (!sysctlbyname(name, &freq[id][0], &len, NULL, 0)) {
275 freq_count += 1;
276 tot_freq += freq[id][0];
277 }
278 }
279 if (temp[id] != -1) {
280 len = sizeof(int);
281 snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.temperature", id);
282 temp[id] = 0.0;
283 if (!sysctlbyname(name, &temp[id], &len, NULL, 0)) {
284 temp_count += 1;
285 tot_temp += temp[id];
286 }
287 }
288 }
289 freq[cores][0] = freq_count == 0 ? 0 : tot_freq * 100 / freq_count;
290 temp[cores] = temp_count == 0 ? 0.0 : tot_temp * 100 / temp_count;
291
292 return (0);
293}
294
295void
296printCPUUser(const char* cmd)
297{
298 fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_USER] / 10.0 / cores);
299}
300
301void
302printCPUUserInfo(const char* cmd)
303{
304 fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n");
305}
306
307void
308printCPUNice(const char* cmd)
309{
310 fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_NICE] / 10.0 / cores);
311}
312
313void
314printCPUNiceInfo(const char* cmd)
315{
316 fprintf(CurrentClient, "CPU Nice Load\t0\t100\t%%\n");
317}
318
319void
320printCPUSys(const char* cmd)
321{
322 fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_SYS] / 10.0 / cores);
323}
324
325void
326printCPUSysInfo(const char* cmd)
327{
328 fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n");
329}
330
331void
332printCPUTotalLoad(const char* cmd)
333{
334 fprintf(CurrentClient, "%f\n", (cpu_states[cores][CP_SYS] + cpu_states[cores][CP_USER] +
335 cpu_states[cores][CP_NICE] + cpu_states[cores][CP_INTR]) / 10.0 / cores);
336}
337
338void
339printCPUTotalLoadInfo(const char* cmd)
340{
341 fprintf(CurrentClient, "CPU Total Load\t0\t100\t%%\n");
342}
343
344void
345printCPUIntr(const char* cmd)
346{
347 fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_INTR] / 10.0 / cores);
348}
349
350void
351printCPUIntrInfo(const char* cmd)
352{
353 fprintf(CurrentClient, "CPU Interrupt Load\t0\t100\t%%\n");
354}
355
356void
357printCPUIdle(const char* cmd)
358{
359 fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_IDLE] / 10.0 / cores);
360}
361
362void
363printCPUIdleInfo(const char* cmd)
364{
365 fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n");
366}
367
368void
369printCPUxUser(const char* cmd)
370{
371 int id;
372
373 sscanf(cmd + 7, "%d", &id);
374 fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_USER] / 10.0);
375}
376
377void
378printCPUxUserInfo(const char* cmd)
379{
380 int id;
381
382 sscanf(cmd + 7, "%d", &id);
383 fprintf(CurrentClient, "CPU%d User Load\t0\t100\t%%\n", id + 1);
384}
385
386void
387printCPUxNice(const char* cmd)
388{
389 int id;
390
391 sscanf(cmd + 7, "%d", &id);
392 fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_NICE] / 10.0);
393}
394
395void
396printCPUxNiceInfo(const char* cmd)
397{
398 int id;
399
400 sscanf(cmd + 7, "%d", &id);
401 fprintf(CurrentClient, "CPU%d Nice Load\t0\t100\t%%\n", id + 1);
402}
403
404void
405printCPUxSys(const char* cmd)
406{
407 int id;
408
409 sscanf(cmd + 7, "%d", &id);
410 fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_SYS] / 10.0);
411}
412
413void
414printCPUxSysInfo(const char* cmd)
415{
416 int id;
417
418 sscanf(cmd + 7, "%d", &id);
419 fprintf(CurrentClient, "CPU%d System Load\t0\t100\t%%\n", id + 1);
420}
421
422void
423printCPUxTotalLoad(const char* cmd)
424{
425 int id;
426
427 sscanf(cmd + 7, "%d", &id);
428 fprintf(CurrentClient, "%f\n", (cpu_states[id][CP_SYS] + cpu_states[id][CP_USER] +
429 cpu_states[id][CP_NICE] + cpu_states[id][CP_INTR]) / 10.0);
430}
431
432void
433printCPUxTotalLoadInfo(const char* cmd)
434{
435 int id;
436
437 sscanf(cmd + 7, "%d", &id);
438 fprintf(CurrentClient, "CPU%d Total Load\t0\t100\t%%\n", id + 1);
439}
440
441void
442printCPUxIntr(const char* cmd)
443{
444 int id;
445
446 sscanf(cmd + 7, "%d", &id);
447 fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_INTR] / 10.0);
448}
449
450void
451printCPUxIntrInfo(const char* cmd)
452{
453 int id;
454
455 sscanf(cmd + 7, "%d", &id);
456 fprintf(CurrentClient, "CPU%d Interrupt Load\t0\t100\t%%\n", id + 1);
457}
458
459void
460printCPUxIdle(const char* cmd)
461{
462 int id;
463
464 sscanf(cmd + 7, "%d", &id);
465 fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_IDLE] / 10.0);
466}
467
468void
469printCPUxIdleInfo(const char* cmd)
470{
471 int id;
472
473 sscanf(cmd + 7, "%d", &id);
474 fprintf(CurrentClient, "CPU%d Idle Load\t0\t100\t%%\n", id + 1);
475}
476
477void printCPUxClock(const char* cmd)
478{
479 int id;
480
481 sscanf(cmd + 7, "%d", &id);
482 fprintf(CurrentClient, "%d\n", freq[id][0]);
483}
484
485void printCPUxClockInfo(const char* cmd)
486{
487 int id;
488
489 sscanf(cmd + 7, "%d", &id);
490 fprintf(CurrentClient, "CPU%d Clock Frequency\t%d\t%d\tMHz\n", id + 1,
491 freq[id][1], freq[id][2]);
492}
493
494void printCPUClock(const char* cmd)
495{
496 fprintf(CurrentClient, "%f\n", freq[cores][0] / 100.0);
497}
498
499void printCPUClockInfo(const char* cmd)
500{
501 fprintf(CurrentClient, "CPU Clock Frequency\t%d\t%d\tMHz\n", freq[cores][1], freq[cores][2]);
502}
503
504void printCPUxTemperature(const char* cmd)
505{
506 int id;
507
508 sscanf(cmd + 7, "%d", &id);
509 fprintf(CurrentClient, "%0.1f\n", (temp[id] - 2732) / 10.0);
510}
511
512void printCPUxTemperatureInfo(const char* cmd)
513{
514 int id;
515
516 sscanf(cmd + 7, "%d", &id);
517 fprintf(CurrentClient, "CPU%d Temperature\t0\t0\tC\n", id + 1);
518}
519
520void printCPUTemperature(const char* cmd)
521{
522 fprintf(CurrentClient, "%0.3f\n", (temp[cores] - 273200) / 1000.0);
523}
524
525void printCPUTemperatureInfo(const char* cmd)
526{
527 fprintf(CurrentClient, "CPU Temperature\t0\t0\tC\n");
528}
529
530void printNumCpus(const char* cmd)
531{
532 fprintf(CurrentClient, "%d\n", cpus);
533}
534
535void printNumCpusInfo(const char* cmd)
536{
537 fprintf(CurrentClient, "Number of physical CPUs\t0\t%d\t\n", maxcpus);
538}
539
540void printNumCores(const char* cmd)
541{
542 fprintf(CurrentClient, "%d\n", cores);
543}
544
545void printNumCoresInfo(const char* cmd)
546{
547 fprintf(CurrentClient, "Total number of processor cores\t0\t%d\t\n", maxcpus);
548}
549
550void get_mmfreq(int id, int* minfreq, int* maxfreq)
551{
552 char buf[FREQ_LEVEL_BUFFER];
553 char mid[SYSCTL_ID_LEN];
554 size_t len = FREQ_LEVEL_BUFFER;
555
556 *minfreq = 0;
557 *maxfreq = 0;
558
559 snprintf(mid, sizeof(mid), "dev.cpu.%d.freq_levels", id);
560 if (!sysctlbyname(mid, buf, &len, NULL, 0))
561 {
562 char *start = buf;
563 char *end;
564
565 /*
566 * The string is ([[freq]]/[[num]] )*([[freq]]/[[num]] ), so
567 * for each frequency we get we must also skip over another
568 * set of numbers
569 */
570 while (1)
571 {
572 /* Get the first number */
573 int number = strtol(start, &end, 10);
574 if (start == end)
575 break;
576 if (!*maxfreq)
577 *maxfreq = number;
578 else
579 *minfreq = number;
580 if (!*end)
581 break;
582 start = end + 1;
583
584 /* Skip over the next number */
585 strtol(start, &end, 10);
586 if (start == end || !*end)
587 break;
588 start = end + 1;
589 }
590 }
591}
592
593/* The part ripped from top... */
594/*
595 * Top users/processes display for Unix
596 * Version 3
597 *
598 * This program may be freely redistributed,
599 * but this entire comment MUST remain intact.
600 *
601 * Copyright (c) 1984, 1989, William LeFebvre, Rice University
602 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
603 */
604
605/*
606 * percentages(cnt, out, new, old, diffs) - calculate percentage change
607 * between array "old" and "new", putting the percentages i "out".
608 * "cnt" is size of each array and "diffs" is used for scratch space.
609 * The array "old" is updated on each call.
610 * The routine assumes modulo arithmetic. This function is especially
611 * useful on BSD mchines for calculating cpu state percentages.
612 */
613long percentages(int cnt, long *out, long *new, long *old, long *diffs)
614{
615 int i;
616 long change;
617 long total_change;
618 long *dp;
619 long half_total;
620
621 /* initialization */
622 total_change = 0;
623 dp = diffs;
624
625 /* calculate changes for each state and the overall change */
626 for (i = 0; i < cnt; i++)
627 {
628 if ((change = *new - *old) < 0)
629 {
630 /* this only happens when the counter wraps */
631 change = (int)
632 ((unsigned long)*new-(unsigned long)*old);
633 }
634 total_change += (*dp++ = change);
635 *old++ = *new++;
636 }
637
638 /* avoid divide by zero potential */
639 if (total_change == 0)
640 {
641 total_change = 1;
642 }
643
644 /* calculate percentages based on overall change, rounding up */
645 half_total = total_change / 2l;
646
647 /* Do not divide by 0. Causes Floating point exception */
648 for (i = 0; i < cnt; i++)
649 {
650 *out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
651 }
652
653 /* return the total in case the caller wants to use it */
654 return(total_change);
655}
656

Warning: That file was not part of the compilation database. It may have many parsing errors.