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