1 /*
2 KSysGuard, the KDE System Guard
3
4 Copyright (c) 1999, 2000 Chris Schlaeger <cs@kde.org>
5
6 Solaris support by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of version 2 of the GNU General Public
10 License as published by the Free Software Foundation.
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 <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28
29 #ifdef HAVE_KSTAT
30 #include <kstat.h>
31 #endif
32
33 #include "ksysguardd.h"
34 #include "Command.h"
35 #include "LoadAvg.h"
36
37 #define MAX_CPU_COUNT 512
38 double loadavg1 = 0.0;
39 double loadavg5 = 0.0;
40 double loadavg15 = 0.0;
41 double idle_load = 0.0;
42
43 typedef struct {
44 int32_t ks_instance;
45 uint64_t cpu_nsecs_idle;
46 uint64_t cpu_nsecs_kernel;
47 uint64_t cpu_nsecs_user;
48 uint64_t cpu_nsecs_wait;
49 float idle_load;
50 float kernel_load;
51 float user_load;
52 float wait_load;
53 } cpu_loadinfo;
54
55 static cpu_loadinfo cpu_load[MAX_CPU_COUNT];
56
initLoadAvg(struct SensorModul * sm)57 void initLoadAvg( struct SensorModul* sm ) {
58 long nproc, id;
59
60 #ifdef HAVE_KSTAT
61 registerMonitor( "cpu/system/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
62 registerMonitor( "cpu/system/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
63 registerMonitor( "cpu/system/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
64 registerMonitor( "cpu/system/idle", "float", printCPUIdle, printCPUIdleInfo, sm );
65
66 /* Monitor names changed from kde3 => kde4. Remain compatible with legacy requests when possible. */
67 registerLegacyMonitor( "cpu/loadavg1", "float", printLoadAvg1, printLoadAvg1Info, sm );
68 registerLegacyMonitor( "cpu/loadavg5", "float", printLoadAvg5, printLoadAvg5Info, sm );
69 registerLegacyMonitor( "cpu/loadavg15", "float", printLoadAvg15, printLoadAvg15Info, sm );
70 registerLegacyMonitor( "cpu/idle", "float", printCPUIdle, printCPUIdleInfo, sm );
71
72 for (id=0; id<MAX_CPU_COUNT; id++) {
73 cpu_load[id].ks_instance = -1;
74 cpu_load[id].cpu_nsecs_idle = 0;
75 cpu_load[id].cpu_nsecs_kernel = 0;
76 cpu_load[id].cpu_nsecs_user = 0;
77 cpu_load[id].cpu_nsecs_wait = 0;
78 cpu_load[id].idle_load = 0;
79 cpu_load[id].kernel_load = 0;
80 cpu_load[id].user_load = 0;
81 cpu_load[id].wait_load = 0;
82 }
83
84 nproc = sysconf(_SC_NPROCESSORS_ONLN);
85 for (id=0; id<nproc; id++) {
86 char cmdName[ 24 ];
87 sprintf( cmdName, "cpu/cpu%d/user", id );
88 registerMonitor( cmdName, "float", printCPUxUser, printCPUxUserInfo, sm );
89 sprintf( cmdName, "cpu/cpu%d/sys", id );
90 registerMonitor( cmdName, "float", printCPUxKernel, printCPUxKernelInfo, sm );
91 sprintf( cmdName, "cpu/cpu%d/TotalLoad", id );
92 registerMonitor( cmdName, "float", printCPUxTotalLoad, printCPUxTotalLoadInfo, sm );
93 sprintf( cmdName, "cpu/cpu%d/idle", id );
94 registerMonitor( cmdName, "float", printCPUxIdle, printCPUxIdleInfo, sm );
95 sprintf( cmdName, "cpu/cpu%d/wait", id );
96 registerMonitor( cmdName, "float", printCPUxWait, printCPUxWaitInfo, sm );
97 }
98 updateLoadAvg();
99 #endif
100 }
101
exitLoadAvg(void)102 void exitLoadAvg( void ) {
103 #ifdef HAVE_KSTAT
104 removeMonitor("cpu/system/loadavg1");
105 removeMonitor("cpu/system/loadavg5");
106 removeMonitor("cpu/system/loadavg15");
107 removeMonitor("cpu/system/idle");
108
109 /* These were registered as legacy monitors */
110 removeMonitor("cpu/loadavg1");
111 removeMonitor("cpu/loadavg5");
112 removeMonitor("cpu/loadavg15");
113 removeMonitor("cpu/idle");
114 #endif
115 }
116
updateLoadAvg(void)117 int updateLoadAvg( void ) {
118
119 #ifdef HAVE_KSTAT
120 kstat_ctl_t *kctl;
121 kstat_t *ksp;
122 kstat_named_t *kdata;
123 int i;
124 long nproc, id;
125
126 /*
127 * get a kstat handle and update the user's kstat chain
128 */
129 if( (kctl = kstat_open()) == NULL )
130 return( 0 );
131 while( kstat_chain_update( kctl ) != 0 )
132 ;
133
134 for (i=0; i<MAX_CPU_COUNT && cpu_load[i].ks_instance != -1; i++) {
135 cpu_load[i].idle_load = 0;
136 cpu_load[i].kernel_load = 0;
137 cpu_load[i].user_load = 0;
138 cpu_load[i].wait_load = 0;
139 }
140
141 /*
142 * traverse the kstat chain to find the appropriate statistics
143 */
144 /* if( (ksp = kstat_lookup( kctl, "unix", 0, "system_misc" )) == NULL )
145 return( 0 );*/
146 for (ksp = kctl->kc_chain; ksp; ksp = ksp->ks_next) {
147 if (strcmp(ksp->ks_module, "unix") == 0 &&
148 strcmp(ksp->ks_name, "system_misc") == 0) {
149
150 if( kstat_read( kctl, ksp, NULL ) == -1 )
151 continue;
152
153 /*
154 * lookup the data
155 */
156 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_1min" );
157 if( kdata != NULL )
158 loadavg1 = LOAD( kdata->value.ui32 );
159 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_5min" );
160 if( kdata != NULL )
161 loadavg5 = LOAD( kdata->value.ui32 );
162 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "avenrun_15min" );
163 if( kdata != NULL )
164 loadavg15 = LOAD( kdata->value.ui32 );
165
166 } else if (strcmp(ksp->ks_module, "cpu") == 0 &&
167 strcmp(ksp->ks_name, "sys") == 0) {
168 int found;
169
170 found = 0;
171 for (i=0; i<MAX_CPU_COUNT; i++) {
172 if (cpu_load[i].ks_instance == ksp->ks_instance) {
173 found = 1;
174 break;
175 }
176 if (cpu_load[i].ks_instance == -1) {
177 cpu_load[i].ks_instance = ksp->ks_instance;
178 found = 2;
179 break;
180 }
181 }
182 if (found) {
183 uint64_t curr_cpu_nsecs_idle, curr_cpu_nsecs_kernel;
184 uint64_t curr_cpu_nsecs_user, curr_cpu_nsecs_wait;
185 double totalNsecs;
186
187 if( kstat_read( kctl, ksp, NULL ) == -1 )
188 continue;
189
190 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_nsec_idle" );
191 if (kdata != NULL)
192 curr_cpu_nsecs_idle = LOAD( kdata->value.ui64 );
193 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_nsec_kernel" );
194 if (kdata != NULL)
195 curr_cpu_nsecs_kernel = LOAD( kdata->value.ui64 );
196 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_nsec_user" );
197 if (kdata != NULL)
198 curr_cpu_nsecs_user = LOAD( kdata->value.ui64 );
199 kdata = (kstat_named_t *) kstat_data_lookup( ksp, "cpu_nsec_wait" );
200 if (kdata != NULL)
201 curr_cpu_nsecs_wait = LOAD( kdata->value.ui64 );
202
203 if (found == 2) {
204 cpu_load[i].cpu_nsecs_idle = curr_cpu_nsecs_idle;
205 cpu_load[i].cpu_nsecs_kernel = curr_cpu_nsecs_kernel;
206 cpu_load[i].cpu_nsecs_user = curr_cpu_nsecs_user;
207 cpu_load[i].cpu_nsecs_wait = curr_cpu_nsecs_wait;
208 continue;
209 }
210
211 totalNsecs = (curr_cpu_nsecs_idle - cpu_load[i].cpu_nsecs_idle) +
212 (curr_cpu_nsecs_kernel - cpu_load[i].cpu_nsecs_kernel) +
213 (curr_cpu_nsecs_user - cpu_load[i].cpu_nsecs_user) +
214 (curr_cpu_nsecs_wait - cpu_load[i].cpu_nsecs_wait);
215
216 if (totalNsecs > 10) {
217 cpu_load[i].idle_load =
218 (100.0 * (curr_cpu_nsecs_idle - cpu_load[i].cpu_nsecs_idle)) \
219 / totalNsecs;
220 cpu_load[i].kernel_load =
221 (100.0 * (curr_cpu_nsecs_kernel - cpu_load[i].cpu_nsecs_kernel)) \
222 / totalNsecs;
223 cpu_load[i].user_load =
224 (100.0 * (curr_cpu_nsecs_user - cpu_load[i].cpu_nsecs_user)) \
225 / totalNsecs;
226 cpu_load[i].wait_load =
227 (100.0 * (curr_cpu_nsecs_wait - cpu_load[i].cpu_nsecs_wait)) \
228 / totalNsecs;
229
230 cpu_load[i].cpu_nsecs_idle = curr_cpu_nsecs_idle;
231 cpu_load[i].cpu_nsecs_kernel = curr_cpu_nsecs_kernel;
232 cpu_load[i].cpu_nsecs_user = curr_cpu_nsecs_user;
233 cpu_load[i].cpu_nsecs_wait = curr_cpu_nsecs_wait;
234 }
235 }
236 }
237
238 nproc = sysconf(_SC_NPROCESSORS_ONLN);
239 idle_load = 0.0;
240 for (id=0; id<nproc; id++) {
241 idle_load += cpu_load[i].idle_load;
242 }
243 idle_load = idle_load / nproc;
244
245 }
246 kstat_close( kctl );
247 #endif /* ! HAVE_KSTAT */
248
249 return( 0 );
250 }
251
printLoadAvg1Info(const char * cmd)252 void printLoadAvg1Info( const char *cmd ) {
253 fprintf(CurrentClient, "avnrun 1min\t0\t0\n" );
254 }
255
printLoadAvg1(const char * cmd)256 void printLoadAvg1( const char *cmd ) {
257 fprintf(CurrentClient, "%f\n", loadavg1 );
258 }
259
printLoadAvg5Info(const char * cmd)260 void printLoadAvg5Info( const char *cmd ) {
261 fprintf(CurrentClient, "avnrun 5min\t0\t0\n" );
262 }
263
printLoadAvg5(const char * cmd)264 void printLoadAvg5( const char *cmd ) {
265 fprintf(CurrentClient, "%f\n", loadavg5 );
266 }
267
printLoadAvg15Info(const char * cmd)268 void printLoadAvg15Info( const char *cmd ) {
269 fprintf(CurrentClient, "avnrun 15min\t0\t0\n" );
270 }
271
printLoadAvg15(const char * cmd)272 void printLoadAvg15( const char *cmd ) {
273 fprintf(CurrentClient, "%f\n", loadavg15 );
274 }
275
printCPUxUser(const char * cmd)276 void printCPUxUser( const char* cmd ) {
277 int id;
278
279 sscanf( cmd + 7, "%d", &id );
280 fprintf(CurrentClient, "%f\n", cpu_load[ id ].user_load );
281 }
282
printCPUxUserInfo(const char * cmd)283 void printCPUxUserInfo( const char* cmd ) {
284 int id;
285
286 sscanf( cmd + 7, "%d", &id );
287 fprintf(CurrentClient, "CPU %d User Load\t0\t100\t%%\n", id );
288 }
289
printCPUxKernel(const char * cmd)290 void printCPUxKernel( const char* cmd ) {
291 int id;
292
293 sscanf( cmd + 7, "%d", &id );
294 fprintf(CurrentClient, "%f\n", cpu_load[ id ].kernel_load );
295 }
296
printCPUxKernelInfo(const char * cmd)297 void printCPUxKernelInfo( const char* cmd ) {
298 int id;
299
300 sscanf( cmd + 7, "%d", &id );
301 fprintf(CurrentClient, "CPU %d System Load\t0\t100\t%%\n", id );
302 }
303
printCPUxTotalLoad(const char * cmd)304 void printCPUxTotalLoad( const char* cmd ) {
305 int id;
306
307 sscanf( cmd + 7, "%d", &id );
308 fprintf(CurrentClient, "%f\n", cpu_load[ id ].user_load + \
309 cpu_load[ id ].kernel_load + cpu_load[ id ].wait_load );
310 }
311
printCPUxTotalLoadInfo(const char * cmd)312 void printCPUxTotalLoadInfo( const char* cmd ) {
313 int id;
314
315 sscanf( cmd + 7, "%d", &id );
316 fprintf(CurrentClient, "CPU %d Total Load\t0\t100\t%%\n", id );
317 }
318
printCPUIdle(const char * cmd)319 void printCPUIdle( const char* cmd ) {
320 fprintf(CurrentClient, "%f\n", idle_load );
321 }
322
printCPUIdleInfo(const char * cmd)323 void printCPUIdleInfo( const char* cmd ) {
324 fprintf(CurrentClient, "CPU Idle Load\t0\t100\t%%\n" );
325 }
326
printCPUxIdle(const char * cmd)327 void printCPUxIdle( const char* cmd ) {
328 int id;
329
330 sscanf( cmd + 7, "%d", &id );
331 fprintf(CurrentClient, "%f\n", cpu_load[ id ].idle_load );
332 }
333
printCPUxIdleInfo(const char * cmd)334 void printCPUxIdleInfo( const char* cmd ) {
335 int id;
336
337 sscanf( cmd + 7, "%d", &id );
338 fprintf(CurrentClient, "CPU %d Idle Load\t0\t100\t%%\n", id );
339 }
340
printCPUxWait(const char * cmd)341 void printCPUxWait( const char* cmd )
342 {
343 int id;
344
345 sscanf( cmd + 7, "%d", &id );
346 fprintf(CurrentClient, "%f\n", cpu_load[ id ].wait_load );
347 }
348
printCPUxWaitInfo(const char * cmd)349 void printCPUxWaitInfo( const char* cmd )
350 {
351 int id;
352
353 sscanf( cmd + 7, "%d", &id );
354 fprintf(CurrentClient, "CPU %d Wait Load\t0\t100\t%%\n", id );
355 }
356