1/* 2 3Copyright (c) 1989 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from the X Consortium. 28 29*/ 30 31/* 32 * get_load - get system load 33 * 34 * Authors: Many and varied... 35 * 36 * Call InitLoadPoint() to initialize. 37 * GetLoadPoint() is a callback for the StripChart widget. 38 */ 39 40#ifdef HAVE_CONFIG_H 41# include "config.h" 42#endif 43 44#include <X11/Xos.h> 45#include <X11/Intrinsic.h> 46#include <X11/Xlocale.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include "xload.h" 50 51#if defined(__CYGWIN__) || defined(_WIN32) 52# define WIN32_LEAN_AND_MEAN 53# include <X11/Xwindows.h> 54typedef struct { 55 DWORD stat; 56 union { 57 LONG vLong; 58 double vDouble; 59 LONGLONG vLongLong; 60 void *string; 61 } u; 62} COUNTER; 63static HANDLE query; 64static HANDLE counter; 65static HINSTANCE hdll; 66static long (__stdcall *pdhopen)(LPCSTR, DWORD, HANDLE); 67static long (__stdcall *pdhaddcounter)(HANDLE, LPCSTR, DWORD, HANDLE*); 68static long (__stdcall *pdhcollectquerydata)(HANDLE); 69static long (__stdcall *pdhgetformattedcountervalue)(HANDLE, DWORD, LPDWORD, COUNTER*); 70# define CYGWIN_PERF 71void InitLoadPoint(void) 72{ 73 long ret; 74 hdll=LoadLibrary("pdh.dll"); 75 if (!hdll) exit(-1); 76 pdhopen=(void*)GetProcAddress(hdll, "PdhOpenQueryA"); 77 if (!pdhopen) exit(-1); 78 pdhaddcounter=(void*)GetProcAddress(hdll, "PdhAddCounterA"); 79 if (!pdhaddcounter) exit(-1); 80 pdhcollectquerydata=(void*)GetProcAddress(hdll, "PdhCollectQueryData"); 81 if (!pdhcollectquerydata) exit(-1); 82 pdhgetformattedcountervalue=(void*)GetProcAddress(hdll, "PdhGetFormattedCounterValue"); 83 if (!pdhgetformattedcountervalue) exit(-1); 84 ret = pdhopen( NULL , 0, &query ); 85 if (ret!=0) exit(-1); 86 ret = pdhaddcounter(query, "\\Processor(_Total)\\% Processor Time", 0, &counter); 87 if (ret!=0) exit(-1); 88} 89void GetLoadPoint( 90 Widget w, /* unused */ 91 XtPointer closure, /* unused */ 92 XtPointer call_data) /* pointer to (double) return value */ 93{ 94 double *loadavg = (double *)call_data; 95 COUNTER fmtvalue; 96 long ret; 97 *loadavg = 0.0; 98 ret = pdhcollectquerydata(query); 99 if (ret!=0) return; 100 ret = pdhgetformattedcountervalue(counter, 0x200, NULL, &fmtvalue); 101 if (ret!=0) return; 102 *loadavg = (fmtvalue.u.vDouble-0.01)/100.0; 103} 104#else /* not CYGWIN */ 105 106static void xload_error(const char *, const char *) _X_NORETURN; 107 108# ifdef HAVE_GETLOADAVG 109# include <stdlib.h> 110# ifdef HAVE_SYS_LOADAVG_H 111# include <sys/loadavg.h> /* Solaris definition of getloadavg */ 112# endif 113 114void InitLoadPoint(void) 115{ 116} 117 118void GetLoadPoint( 119 Widget w, /* unused */ 120 XtPointer closure, /* unused */ 121 XtPointer call_data) /* ptr to (double) return value */ 122{ 123 double *loadavg = (double *)call_data; 124 125 if (getloadavg(loadavg, 1) < 0) 126 xload_error("couldn't obtain load average", ""); 127} 128 129# else /* not HAVE_GETLOADAVG */ 130 131 132# if !defined(linux) && !defined(__GLIBC__) 133# include <nlist.h> 134# endif /* !linux && ... */ 135 136# ifdef CSRG_BASED 137# include <sys/param.h> 138# endif 139 140# if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) 141 142void InitLoadPoint(void) 143{ 144 return; 145} 146 147void GetLoadPoint( 148 Widget w, /* unused */ 149 XtPointer closure, /* unused */ 150 XtPointer call_data) /* pointer to (double) return value */ 151{ 152 static int fd = -1; 153 int n; 154 char buf[10] = {0, }; 155# ifndef X_LOCALE 156 char *dp; 157 static char ldp = 0; 158# endif 159 160 161 if (fd < 0) 162 { 163 if (fd == -2 || 164 (fd = open("/proc/loadavg", O_RDONLY)) < 0) 165 { 166 fd = -2; 167 *(double *)call_data = 0.0; 168 return; 169 } 170# ifndef X_LOCALE 171 ldp = *localeconv()->decimal_point; 172# endif 173 } 174 else 175 lseek(fd, 0, 0); 176 177 if ((n = read(fd, buf, sizeof(buf)-1)) > 0) { 178# ifndef X_LOCALE 179 if (ldp != '.') 180 while ((dp = memchr(buf,'.',sizeof(buf)-1)) != NULL) { 181 *(char *)dp = ldp; 182 } 183 184# endif 185 if (sscanf(buf, "%lf", (double *)call_data) == 1) 186 return; 187 } 188 189 190 *(double *)call_data = 0.0; /* temporary hiccup */ 191 192 return; 193} 194 195# else /* linux */ 196 197# ifdef __GNU__ 198 199# include <mach.h> 200 201static processor_set_t default_set; 202 203void InitLoadPoint(void) 204{ 205 if (processor_set_default (mach_host_self (), &default_set) != KERN_SUCCESS) 206 xload_error("cannot get processor_set_default", ""); 207} 208 209/* ARGSUSED */ 210void GetLoadPoint( 211 Widget w, /* unused */ 212 XtPointer closure, /* unused */ 213 XtPointer call_data) /* pointer to (double) return value */ 214{ 215 host_t host; 216 struct processor_set_basic_info info; 217 unsigned info_count; 218 219 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 220 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host, 221 (processor_set_info_t) &info, &info_count) 222 != KERN_SUCCESS) 223 { 224 InitLoadPoint(); 225 info.load_average = 0; 226 } 227 228 *(double *)call_data = info.load_average * 1000 / LOAD_SCALE; 229 230 return; 231} 232 233# else /* __GNU__ */ 234 235# ifdef __APPLE__ 236 237# include <mach/mach.h> 238 239static mach_port_t host_priv_port; 240 241void InitLoadPoint(void) 242{ 243 host_priv_port = mach_host_self(); 244} 245 246/* ARGSUSED */ 247void GetLoadPoint( 248 Widget w, /* unused */ 249 XtPointer closure, /* unused */ 250 XtPointer call_data) /* pointer to (double) return value */ 251{ 252 double *loadavg = (double *)call_data; 253 254 struct host_load_info load_data; 255 int host_count; 256 kern_return_t kr; 257 258 host_count = sizeof(load_data)/sizeof(integer_t); 259 kr = host_statistics(host_priv_port, HOST_LOAD_INFO, 260 (host_info_t)&load_data, &host_count); 261 if (kr != KERN_SUCCESS) 262 xload_error("cannot get host statistics", ""); 263 *loadavg = (double)load_data.avenrun[0]/LOAD_SCALE; 264 return; 265} 266 267# else /* __APPLE__ */ 268 269 270 271# ifdef __QNXNTO__ 272# include <time.h> 273# include <sys/neutrino.h> 274static _Uint64t nto_idle = 0, nto_idle_last = 0; 275static int nto_idle_id; 276static struct timespec nto_now, nto_last; 277 278void 279InitLoadPoint(void) 280{ 281 nto_idle_id = ClockId(1, 1); /* Idle thread */ 282 ClockTime(nto_idle_id, NULL, &nto_idle_last); 283 clock_gettime( CLOCK_REALTIME, &nto_last); 284} 285 286/* ARGSUSED */ 287void 288GetLoadPoint( /* QNX NTO version */ 289 Widget w, /* unused */ 290 XtPointer closure, /* unused */ 291 XtPointer call_data) /* pointer to (double) return value */ 292{ 293 double *loadavg = (double *)call_data; 294 double timediff; 295 double temp = 0.0; 296 297 ClockTime(nto_idle_id, NULL, &nto_idle); 298 clock_gettime( CLOCK_REALTIME, &nto_now); 299 timediff = 1000000000.0 * (nto_now.tv_sec - nto_last.tv_sec) 300 + (nto_now.tv_nsec - nto_last.tv_nsec); 301 temp = 1.0 - (nto_idle-nto_idle_last)/timediff; 302 *loadavg = temp >= 0 ? temp : 0; 303 nto_idle_last = nto_idle; 304 nto_last = nto_now; 305} 306# else /* not __QNXNTO__ */ 307 308# ifndef KMEM_FILE 309# define KMEM_FILE "/dev/kmem" 310# endif 311 312# ifndef KERNEL_FILE 313/* 314 * provide default for everyone else 315 */ 316/* If <paths.h> exists, check in it */ 317# ifdef HAVE_PATHS_H 318# include <paths.h> 319# ifdef _PATH_UNIX 320# define KERNEL_FILE _PATH_UNIX 321# else 322# ifdef _PATH_KERNEL 323# define KERNEL_FILE _PATH_KERNEL 324# else 325# define KERNEL_FILE "/vmunix" 326# endif 327# endif 328# else /* HAVE_PATHS_H */ 329# define KERNEL_FILE "/vmunix" 330# endif /* HAVE_PATHS_H */ 331# endif /* KERNEL_FILE */ 332 333 334# ifndef KERNEL_LOAD_VARIABLE 335# if defined(BSD) && (BSD >= 199103) 336# define KERNEL_LOAD_VARIABLE "_averunnable" 337# else /* BSD >= 199103 */ 338# define KERNEL_LOAD_VARIABLE "_avenrun" 339# endif /* BSD >= 199103 */ 340# endif /* KERNEL_LOAD_VARIABLE */ 341 342static struct nlist namelist[] = { /* namelist for vmunix grubbing */ 343# define LOADAV 0 344 {KERNEL_LOAD_VARIABLE}, 345 {0} 346}; 347 348static int kmem; 349static long loadavg_seek; 350 351void InitLoadPoint() 352{ 353# if !defined(AIXV5) && !(BSD >= 199103) && !defined(__APPLE__) 354 extern void nlist(); 355# endif 356 357 nlist( KERNEL_FILE, namelist); 358 /* 359 * Some systems appear to set only one of these to Zero if the entry could 360 * not be found, I hope no_one returns Zero as a good value, or bad things 361 * will happen to you. (I have a hard time believing the value will 362 * ever really be zero anyway). CDP 5/17/89. 363 */ 364 if (namelist[LOADAV].n_type == 0 || 365 namelist[LOADAV].n_value == 0) { 366 xload_error("cannot get name list from", KERNEL_FILE); 367 exit(-1); 368 } 369 loadavg_seek = namelist[LOADAV].n_value; 370 kmem = open(KMEM_FILE, O_RDONLY); 371 if (kmem < 0) xload_error("cannot open", KMEM_FILE); 372} 373 374/* ARGSUSED */ 375void GetLoadPoint( w, closure, call_data ) 376 Widget w; /* unused */ 377 XtPointer closure; /* unused */ 378 XtPointer call_data; /* pointer to (double) return value */ 379{ 380 double *loadavg = (double *)call_data; 381 382 (void) lseek(kmem, loadavg_seek, 0); 383 384# if (BSD >= 199103) 385 { 386 long temp; 387 (void) read(kmem, (char *)&temp, sizeof(long)); 388 *loadavg = (double)temp/FSCALE; 389 } 390# else /* else not BSD */ 391 (void) read(kmem, (char *)loadavg, sizeof(double)); 392# endif /* or ... else */ 393 return; 394} 395# endif /* __QNXNTO__ else */ 396# endif /* __APPLE__ else */ 397# endif /* __GNU__ else */ 398# endif /* linux else */ 399# endif /* HAVE_GETLOADAVG else */ 400 401static void xload_error(const char *str1, const char *str2) 402{ 403 (void) fprintf(stderr,"xload: %s %s\n", str1, str2); 404 exit(-1); 405} 406 407#endif /* END of __CYGWIN__ */ 408