2
KSysGuard, the KDE System Guard
4
Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
5
Copyright (c) 2010 David Naylor <naylor.b.david@gmail.com>
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.
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.
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.
23
#include <sys/types.h>
25
#include <sys/resource.h>
26
#include <sys/sysctl.h>
37
#include "ksysguardd.h"
39
#define FREQ_LEVEL_BUFFER 256
40
#define SYSCTL_ID_LEN 35
42
static void get_mmfreq(int, int*, int*);
44
static long percentages(int cnt, long *out, long *new, long *old, long *diffs);
46
static long (*cp_time)[CPUSTATES] = NULL;
47
static long (*cp_old)[CPUSTATES] = NULL;
48
static long (*cp_diff)[CPUSTATES] = NULL;
50
static int maxcpus = 1;
53
static int (*freq)[3] = NULL;
54
static int *temp = NULL;
56
static long (*cpu_states)[CPUSTATES] = NULL;
59
initCpuInfo(struct SensorModul* sm)
63
char name[SYSCTL_ID_LEN];
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;
73
sysctlbyname("kern.smp.cpus", &cores, &len, NULL, 0);
75
len = sizeof(maxcpus);
76
sysctlbyname("kern.smp.maxcpus", &maxcpus, &len, NULL, 0);
78
/* Core/process count */
79
registerMonitor("system/processors", "integer", printNumCpus, printNumCpusInfo, sm);
80
registerMonitor("system/cores", "integer", printNumCores, printNumCoresInfo, sm);
85
if ((cp_time = malloc(sizeof(long) * CPUSTATES * (cores * 4 + 1))) == NULL) {
86
log_error("out of memory for cp_time");
89
cp_old = &cp_time[cores];
90
cp_diff = &cp_old[cores];
91
cpu_states = &cp_diff[cores];
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);
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);
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);
125
if ((freq = malloc(sizeof(int) * 3 * (cores + 1))) == NULL) {
126
log_error("out of memory for freq");
130
registerMonitor("cpu/system/AverageClock", "float", printCPUClock, printCPUClockInfo, sm);
131
for (id = 0; id < cores; ++id) {
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);
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;
152
freq[cores][1] = minfreq;
153
freq[cores][2] = maxfreq;
158
if ((temp = malloc(sizeof(int) * (cores + 1))) == NULL) {
159
log_error("out of memory for temp");
162
registerMonitor("cpu/system/AverageTemperature", "float", printCPUTemperature, printCPUTemperatureInfo, sm);
163
for (id = 0; id < cores; ++id) {
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);
180
char name[SYSCTL_ID_LEN];
182
removeMonitor("system/processors");
183
removeMonitor("system/cores");
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");
193
/* These were registered as legacy monitors */
194
removeMonitor("cpu/user");
195
removeMonitor("cpu/nice");
196
removeMonitor("cpu/sys");
197
removeMonitor("cpu/idle");
199
for (id = 0; id < cores; ++id) {
200
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/user", id);
202
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/nice", id);
204
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/sys", id);
206
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/TotalLoad", id);
208
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/intr", id);
210
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/idle", id);
213
if (freq != NULL && freq[id][0] != -1) {
214
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/clock", id);
217
if (temp != NULL && temp[id] != -1) {
218
snprintf(name, SYSCTL_ID_LEN, "cpu/cpu%d/temperature", id);
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);
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);
254
int sid, id, tot_freq = 0, tot_temp = 0, freq_count = 0, temp_count = 0;
255
char name[SYSCTL_ID_LEN];
257
if (cp_time == NULL || freq == NULL || temp == NULL)
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];
269
for (id = 0; id < cores; ++id) {
270
if (freq[id][0] != -1) {
272
snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.freq", id);
274
if (!sysctlbyname(name, &freq[id][0], &len, NULL, 0)) {
276
tot_freq += freq[id][0];
279
if (temp[id] != -1) {
281
snprintf(name, SYSCTL_ID_LEN, "dev.cpu.%d.temperature", id);
283
if (!sysctlbyname(name, &temp[id], &len, NULL, 0)) {
285
tot_temp += temp[id];
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;
296
printCPUUser(const char* cmd)
298
fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_USER] / 10.0 / cores);
302
printCPUUserInfo(const char* cmd)
304
fprintf(CurrentClient, "CPU User Load\t0\t100\t%%\n");
308
printCPUNice(const char* cmd)
310
fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_NICE] / 10.0 / cores);
314
printCPUNiceInfo(const char* cmd)
316
fprintf(CurrentClient, "CPU Nice Load\t0\t100\t%%\n");
320
printCPUSys(const char* cmd)
322
fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_SYS] / 10.0 / cores);
326
printCPUSysInfo(const char* cmd)
328
fprintf(CurrentClient, "CPU System Load\t0\t100\t%%\n");
332
printCPUTotalLoad(const char* cmd)
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);
339
printCPUTotalLoadInfo(const char* cmd)
341
fprintf(CurrentClient, "CPU Total Load\t0\t100\t%%\n");
345
printCPUIntr(const char* cmd)
347
fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_INTR] / 10.0 / cores);
351
printCPUIntrInfo(const char* cmd)
353
fprintf(CurrentClient, "CPU Interrupt Load\t0\t100\t%%\n");
357
printCPUIdle(const char* cmd)
359
fprintf(CurrentClient, "%f\n", cpu_states[cores][CP_IDLE] / 10.0 / cores);
363
printCPUIdleInfo(const char* cmd)
365
fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n");
369
printCPUxUser(const char* cmd)
373
sscanf(cmd + 7, "%d", &id);
374
fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_USER] / 10.0);
378
printCPUxUserInfo(const char* cmd)
382
sscanf(cmd + 7, "%d", &id);
383
fprintf(CurrentClient, "CPU%d User Load\t0\t100\t%%\n", id + 1);
387
printCPUxNice(const char* cmd)
391
sscanf(cmd + 7, "%d", &id);
392
fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_NICE] / 10.0);
396
printCPUxNiceInfo(const char* cmd)
400
sscanf(cmd + 7, "%d", &id);
401
fprintf(CurrentClient, "CPU%d Nice Load\t0\t100\t%%\n", id + 1);
405
printCPUxSys(const char* cmd)
409
sscanf(cmd + 7, "%d", &id);
410
fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_SYS] / 10.0);
414
printCPUxSysInfo(const char* cmd)
418
sscanf(cmd + 7, "%d", &id);
419
fprintf(CurrentClient, "CPU%d System Load\t0\t100\t%%\n", id + 1);
423
printCPUxTotalLoad(const char* cmd)
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);
433
printCPUxTotalLoadInfo(const char* cmd)
437
sscanf(cmd + 7, "%d", &id);
438
fprintf(CurrentClient, "CPU%d Total Load\t0\t100\t%%\n", id + 1);
442
printCPUxIntr(const char* cmd)
446
sscanf(cmd + 7, "%d", &id);
447
fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_INTR] / 10.0);
451
printCPUxIntrInfo(const char* cmd)
455
sscanf(cmd + 7, "%d", &id);
456
fprintf(CurrentClient, "CPU%d Interrupt Load\t0\t100\t%%\n", id + 1);
460
printCPUxIdle(const char* cmd)
464
sscanf(cmd + 7, "%d", &id);
465
fprintf(CurrentClient, "%0.1f\n", cpu_states[id][CP_IDLE] / 10.0);
469
printCPUxIdleInfo(const char* cmd)
473
sscanf(cmd + 7, "%d", &id);
474
fprintf(CurrentClient, "CPU%d Idle Load\t0\t100\t%%\n", id + 1);
477
void printCPUxClock(const char* cmd)
481
sscanf(cmd + 7, "%d", &id);
482
fprintf(CurrentClient, "%d\n", freq[id][0]);
485
void printCPUxClockInfo(const char* cmd)
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]);
494
void printCPUClock(const char* cmd)
496
fprintf(CurrentClient, "%f\n", freq[cores][0] / 100.0);
499
void printCPUClockInfo(const char* cmd)
501
fprintf(CurrentClient, "CPU Clock Frequency\t%d\t%d\tMHz\n", freq[cores][1], freq[cores][2]);
504
void printCPUxTemperature(const char* cmd)
508
sscanf(cmd + 7, "%d", &id);
509
fprintf(CurrentClient, "%0.1f\n", (temp[id] - 2732) / 10.0);
512
void printCPUxTemperatureInfo(const char* cmd)
516
sscanf(cmd + 7, "%d", &id);
517
fprintf(CurrentClient, "CPU%d Temperature\t0\t0\tC\n", id + 1);
520
void printCPUTemperature(const char* cmd)
522
fprintf(CurrentClient, "%0.3f\n", (temp[cores] - 273200) / 1000.0);
525
void printCPUTemperatureInfo(const char* cmd)
527
fprintf(CurrentClient, "CPU Temperature\t0\t0\tC\n");
530
void printNumCpus(const char* cmd)
532
fprintf(CurrentClient, "%d\n", cpus);
535
void printNumCpusInfo(const char* cmd)
537
fprintf(CurrentClient, "Number of physical CPUs\t0\t%d\t\n", maxcpus);
540
void printNumCores(const char* cmd)
542
fprintf(CurrentClient, "%d\n", cores);
545
void printNumCoresInfo(const char* cmd)
547
fprintf(CurrentClient, "Total number of processor cores\t0\t%d\t\n", maxcpus);
550
void get_mmfreq(int id, int* minfreq, int* maxfreq)
552
char buf[FREQ_LEVEL_BUFFER];
553
char mid[SYSCTL_ID_LEN];
554
size_t len = FREQ_LEVEL_BUFFER;
559
snprintf(mid, sizeof(mid), "dev.cpu.%d.freq_levels", id);
560
if (!sysctlbyname(mid, buf, &len, NULL, 0))
566
* The string is ([[freq]]/[[num]] )*([[freq]]/[[num]] ), so
567
* for each frequency we get we must also skip over another
572
// Get the first number
573
int number = strtol(start, &end, 10);
584
// Skip over the next number
585
strtol(start, &end, 10);
586
if (start == end || !*end)
593
/* The part ripped from top... */
595
* Top users/processes display for Unix
598
* This program may be freely redistributed,
599
* but this entire comment MUST remain intact.
601
* Copyright (c) 1984, 1989, William LeFebvre, Rice University
602
* Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
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.
613
long percentages(int cnt, long *out, long *new, long *old, long *diffs)
625
/* calculate changes for each state and the overall change */
626
for (i = 0; i < cnt; i++)
628
if ((change = *new - *old) < 0)
630
/* this only happens when the counter wraps */
632
((unsigned long)*new-(unsigned long)*old);
634
total_change += (*dp++ = change);
638
/* avoid divide by zero potential */
639
if (total_change == 0)
644
/* calculate percentages based on overall change, rounding up */
645
half_total = total_change / 2l;
647
/* Do not divide by 0. Causes Floating point exception */
648
for (i = 0; i < cnt; i++)
650
*out++ = (int)((*diffs++ * 1000 + half_total) / total_change);
653
/* return the total in case the caller wants to use it */
654
return(total_change);