get_load.c revision 8846b520
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# if defined(att) || defined(QNX4) 132# define LOADSTUB 133# endif 134 135# ifndef LOADSTUB 136# if !defined(linux) && !defined(__GLIBC__) 137# include <nlist.h> 138# endif /* !linux && ... */ 139# endif /* LOADSTUB */ 140 141# ifdef CSRG_BASED 142# include <sys/param.h> 143# endif 144 145# ifdef sgi 146# define FSCALE 1024.0 147# endif 148 149# ifdef __osf__ 150/* 151 * Use the table(2) interface; it doesn't require setuid root. 152 * 153 * Select 0, 1, or 2 for 5, 30, or 60 second load averages. 154 */ 155# ifndef WHICH_AVG 156# define WHICH_AVG 1 157# endif 158# include <sys/table.h> 159# endif 160 161# ifdef SVR4 162# ifndef FSCALE 163# define FSCALE (1 << 8) 164# endif 165# endif 166 167# if defined(SYSV) && defined(i386) 168/* 169 * inspired by 'avgload' by John F. Haugh II 170 */ 171# include <sys/param.h> 172# include <sys/buf.h> 173# include <sys/immu.h> 174# include <sys/region.h> 175# include <sys/var.h> 176# include <sys/proc.h> 177# define KERNEL_FILE "/unix" 178# define KMEM_FILE "/dev/kmem" 179# define VAR_NAME "v" 180# define PROC_NAME "proc" 181# define BUF_NAME "buf" 182# define DECAY 0.8 183struct nlist namelist[] = { 184 {VAR_NAME}, 185 {PROC_NAME}, 186 {BUF_NAME}, 187 {0}, 188}; 189 190static int kmem; 191static struct var v; 192static struct proc *p; 193static XtPointer first_buf, last_buf; 194 195void InitLoadPoint() /* SYSV386 version */ 196{ 197 int i; 198 199 nlist( KERNEL_FILE, namelist); 200 201 for (i=0; namelist[i].n_name; i++) 202 if (namelist[i].n_value == 0) 203 xload_error("cannot get name list from", KERNEL_FILE); 204 205 if ((kmem = open(KMEM_FILE, O_RDONLY)) < 0) 206 xload_error("cannot open", KMEM_FILE); 207 208 if (lseek(kmem, namelist[0].n_value, 0) == -1) 209 xload_error("cannot seek", VAR_NAME); 210 211 if (read(kmem, &v, sizeof(v)) != sizeof(v)) 212 xload_error("cannot read", VAR_NAME); 213 214 if ((p=(struct proc *)malloc(v.v_proc*sizeof(*p))) == NULL) 215 xload_error("cannot allocat space for", PROC_NAME); 216 217 first_buf = (XtPointer) namelist[2].n_value; 218 last_buf = (char *)first_buf + v.v_buf * sizeof(struct buf); 219} 220 221/* ARGSUSED */ 222void GetLoadPoint( w, closure, call_data ) /* SYSV386 version */ 223Widget w; /* unused */ 224XtPointer closure; /* unused */ 225XtPointer call_data; /* pointer to (double) return value */ 226{ 227 double *loadavg = (double *)call_data; 228 static double avenrun = 0.0; 229 int i, nproc, size; 230 231 (void) lseek(kmem, namelist[0].n_value, 0); 232 (void) read(kmem, &v, sizeof(v)); 233 234 size = (struct proc *)v.ve_proc - (struct proc *)namelist[1].n_value; 235 236 (void) lseek(kmem, namelist[1].n_value, 0); 237 (void) read(kmem, p, size * sizeof(struct proc)); 238 239 for (nproc = 0, i=0; i<size; i++) 240 if ((p[i].p_stat == SRUN) || 241 (p[i].p_stat == SIDL) || 242 (p[i].p_stat == SXBRK) || 243 (p[i].p_stat == SSLEEP && (p[i].p_pri < PZERO) && 244 (p[i].p_wchan >= (char *)first_buf) && (p[i].p_wchan < (char *)last_buf))) 245 nproc++; 246 247 /* update the load average using a decay filter */ 248 avenrun = DECAY * avenrun + nproc * (1.0 - DECAY); 249 *loadavg = avenrun; 250 251 return; 252} 253# else /* not (SYSV && i386) */ 254 255# if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__)) 256 257void InitLoadPoint(void) 258{ 259 return; 260} 261 262void GetLoadPoint( 263 Widget w, /* unused */ 264 XtPointer closure, /* unused */ 265 XtPointer call_data) /* pointer to (double) return value */ 266{ 267 static int fd = -1; 268 int n; 269 char buf[10] = {0, }; 270# ifndef X_LOCALE 271 char *dp; 272 static char ldp = 0; 273# endif 274 275 276 if (fd < 0) 277 { 278 if (fd == -2 || 279 (fd = open("/proc/loadavg", O_RDONLY)) < 0) 280 { 281 fd = -2; 282 *(double *)call_data = 0.0; 283 return; 284 } 285# ifndef X_LOCALE 286 ldp = *localeconv()->decimal_point; 287# endif 288 } 289 else 290 lseek(fd, 0, 0); 291 292 if ((n = read(fd, buf, sizeof(buf)-1)) > 0) { 293# ifndef X_LOCALE 294 if (ldp != '.') 295 while ((dp = memchr(buf,'.',sizeof(buf)-1)) != NULL) { 296 *(char *)dp = ldp; 297 } 298 299# endif 300 if (sscanf(buf, "%lf", (double *)call_data) == 1) 301 return; 302 } 303 304 305 *(double *)call_data = 0.0; /* temporary hiccup */ 306 307 return; 308} 309 310# else /* linux */ 311 312# ifdef __GNU__ 313 314# include <mach.h> 315 316static processor_set_t default_set; 317 318void InitLoadPoint(void) 319{ 320 if (processor_set_default (mach_host_self (), &default_set) != KERN_SUCCESS) 321 xload_error("cannot get processor_set_default", ""); 322} 323 324/* ARGSUSED */ 325void GetLoadPoint( 326 Widget w, /* unused */ 327 XtPointer closure, /* unused */ 328 XtPointer call_data) /* pointer to (double) return value */ 329{ 330 host_t host; 331 struct processor_set_basic_info info; 332 unsigned info_count; 333 334 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 335 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host, 336 (processor_set_info_t) &info, &info_count) 337 != KERN_SUCCESS) 338 { 339 InitLoadPoint(); 340 info.load_average = 0; 341 } 342 343 *(double *)call_data = info.load_average * 1000 / LOAD_SCALE; 344 345 return; 346} 347 348# else /* __GNU__ */ 349 350# ifdef __APPLE__ 351 352# include <mach/mach.h> 353 354static mach_port_t host_priv_port; 355 356void InitLoadPoint(void) 357{ 358 host_priv_port = mach_host_self(); 359} 360 361/* ARGSUSED */ 362void GetLoadPoint( 363 Widget w, /* unused */ 364 XtPointer closure, /* unused */ 365 XtPointer call_data) /* pointer to (double) return value */ 366{ 367 double *loadavg = (double *)call_data; 368 369 struct host_load_info load_data; 370 int host_count; 371 kern_return_t kr; 372 373 host_count = sizeof(load_data)/sizeof(integer_t); 374 kr = host_statistics(host_priv_port, HOST_LOAD_INFO, 375 (host_info_t)&load_data, &host_count); 376 if (kr != KERN_SUCCESS) 377 xload_error("cannot get host statistics", ""); 378 *loadavg = (double)load_data.avenrun[0]/LOAD_SCALE; 379 return; 380} 381 382# else /* __APPLE__ */ 383 384# ifdef LOADSTUB 385 386void InitLoadPoint() 387{ 388} 389 390/* ARGSUSED */ 391void GetLoadPoint( w, closure, call_data ) 392 Widget w; /* unused */ 393 XtPointer closure; /* unused */ 394 XtPointer call_data; /* pointer to (double) return value */ 395{ 396 *(double *)call_data = 1.0; 397} 398 399# else /* not LOADSTUB */ 400 401# ifdef __osf__ 402 403void InitLoadPoint() 404{ 405} 406 407/*ARGSUSED*/ 408void GetLoadPoint( w, closure, call_data ) 409 Widget w; /* unused */ 410 XtPointer closure; /* unused */ 411 XtPointer call_data; /* pointer to (double) return value */ 412{ 413 double *loadavg = (double *)call_data; 414 struct tbl_loadavg load_data; 415 416 if (table(TBL_LOADAVG, 0, (char *)&load_data, 1, sizeof(load_data)) < 0) 417 xload_error("error reading load average", ""); 418 *loadavg = (load_data.tl_lscale == 0) ? 419 load_data.tl_avenrun.d[WHICH_AVG] : 420 load_data.tl_avenrun.l[WHICH_AVG] / (double)load_data.tl_lscale; 421} 422 423# else /* not __osf__ */ 424 425# ifdef __QNXNTO__ 426# include <time.h> 427# include <sys/neutrino.h> 428static _Uint64t nto_idle = 0, nto_idle_last = 0; 429static int nto_idle_id; 430static struct timespec nto_now, nto_last; 431 432void 433InitLoadPoint(void) 434{ 435 nto_idle_id = ClockId(1, 1); /* Idle thread */ 436 ClockTime(nto_idle_id, NULL, &nto_idle_last); 437 clock_gettime( CLOCK_REALTIME, &nto_last); 438} 439 440/* ARGSUSED */ 441void 442GetLoadPoint( /* QNX NTO version */ 443 Widget w, /* unused */ 444 XtPointer closure, /* unused */ 445 XtPointer call_data) /* pointer to (double) return value */ 446{ 447 double *loadavg = (double *)call_data; 448 double timediff; 449 double temp = 0.0; 450 451 ClockTime(nto_idle_id, NULL, &nto_idle); 452 clock_gettime( CLOCK_REALTIME, &nto_now); 453 timediff = 1000000000.0 * (nto_now.tv_sec - nto_last.tv_sec) 454 + (nto_now.tv_nsec - nto_last.tv_nsec); 455 temp = 1.0 - (nto_idle-nto_idle_last)/timediff; 456 *loadavg = temp >= 0 ? temp : 0; 457 nto_idle_last = nto_idle; 458 nto_last = nto_now; 459} 460# else /* not __QNXNTO__ */ 461 462# ifdef __bsdi__ 463# include <kvm.h> 464 465static struct nlist nl[] = { 466 { "_averunnable" }, 467# define X_AVERUNNABLE 0 468 { "_fscale" }, 469# define X_FSCALE 1 470 { "" }, 471}; 472static kvm_t *kd; 473static int fscale; 474 475void InitLoadPoint(void) 476{ 477 fixpt_t averunnable[3]; /* unused really */ 478 479 if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL) 480 xload_error("can't open kvm files", ""); 481 482 if (kvm_nlist(kd, nl) != 0) 483 xload_error("can't read name list", ""); 484 485 if (kvm_read(kd, (off_t)nl[X_AVERUNNABLE].n_value, (char *)averunnable, 486 sizeof(averunnable)) != sizeof(averunnable)) 487 xload_error("couldn't obtain _averunnable variable", ""); 488 489 if (kvm_read(kd, (off_t)nl[X_FSCALE].n_value, (char *)&fscale, 490 sizeof(fscale)) != sizeof(fscale)) 491 xload_error("couldn't obtain _fscale variable", ""); 492 493 return; 494} 495 496void GetLoadPoint( 497 Widget w, /* unused */ 498 XtPointer closure, /* unused */ 499 XtPointer call_data) /* ptr to (double) return value */ 500{ 501 double *loadavg = (double *)call_data; 502 fixpt_t t; 503 504 if (kvm_read(kd, (off_t)nl[X_AVERUNNABLE].n_value, (char *)&t, 505 sizeof(t)) != sizeof(t)) 506 xload_error("couldn't obtain load average", ""); 507 508 *loadavg = (double)t/fscale; 509 510 return; 511} 512 513# else /* not __bsdi__ */ 514# ifndef KMEM_FILE 515# define KMEM_FILE "/dev/kmem" 516# endif 517 518# ifndef KERNEL_FILE 519 520# ifdef hpux 521# define KERNEL_FILE "/hp-ux" 522# endif /* hpux */ 523 524# ifdef sgi 525# if (OSMAJORVERSION > 4) 526# define KERNEL_FILE "/unix" 527# endif 528# endif 529 530/* 531 * provide default for everyone else 532 */ 533# ifndef KERNEL_FILE 534# ifdef SVR4 535# define KERNEL_FILE "/stand/unix" 536# else 537# ifdef SYSV 538# define KERNEL_FILE "/unix" 539# else 540/* If a BSD system, check in <paths.h> */ 541# ifdef BSD 542# include <paths.h> 543# ifdef _PATH_UNIX 544# define KERNEL_FILE _PATH_UNIX 545# else 546# ifdef _PATH_KERNEL 547# define KERNEL_FILE _PATH_KERNEL 548# else 549# define KERNEL_FILE "/vmunix" 550# endif 551# endif 552# else /* BSD */ 553# define KERNEL_FILE "/vmunix" 554# endif /* BSD */ 555# endif /* SYSV */ 556# endif /* SVR4 */ 557# endif /* KERNEL_FILE */ 558# endif /* KERNEL_FILE */ 559 560 561# ifndef KERNEL_LOAD_VARIABLE 562# if defined(BSD) && (BSD >= 199103) 563# define KERNEL_LOAD_VARIABLE "_averunnable" 564# endif /* BSD >= 199103 */ 565 566# ifdef hpux 567# ifdef __hp9000s800 568# define KERNEL_LOAD_VARIABLE "avenrun" 569# endif /* hp9000s800 */ 570# endif /* hpux */ 571 572# ifdef sgi 573# define KERNEL_LOAD_VARIABLE "avenrun" 574# endif /* sgi */ 575 576# endif /* KERNEL_LOAD_VARIABLE */ 577 578/* 579 * provide default for everyone else 580 */ 581 582# ifndef KERNEL_LOAD_VARIABLE 583# ifdef USG 584# define KERNEL_LOAD_VARIABLE "sysinfo" 585# define SYSINFO 586# else 587# ifdef SVR4 588# define KERNEL_LOAD_VARIABLE "avenrun" 589# else 590# define KERNEL_LOAD_VARIABLE "_avenrun" 591# endif 592# endif 593# endif /* KERNEL_LOAD_VARIABLE */ 594 595static struct nlist namelist[] = { /* namelist for vmunix grubbing */ 596# define LOADAV 0 597 {KERNEL_LOAD_VARIABLE}, 598 {0} 599}; 600 601static int kmem; 602static long loadavg_seek; 603 604void InitLoadPoint() 605{ 606# if !defined(SVR4) && !defined(sgi) && !defined(AIXV5) && !(BSD >= 199103) && !defined(__APPLE__) 607 extern void nlist(); 608# endif 609 610 nlist( KERNEL_FILE, namelist); 611 /* 612 * Some systems appear to set only one of these to Zero if the entry could 613 * not be found, I hope no_one returns Zero as a good value, or bad things 614 * will happen to you. (I have a hard time believing the value will 615 * ever really be zero anyway). CDP 5/17/89. 616 */ 617 if (namelist[LOADAV].n_type == 0 || 618 namelist[LOADAV].n_value == 0) { 619 xload_error("cannot get name list from", KERNEL_FILE); 620 exit(-1); 621 } 622 loadavg_seek = namelist[LOADAV].n_value; 623 kmem = open(KMEM_FILE, O_RDONLY); 624 if (kmem < 0) xload_error("cannot open", KMEM_FILE); 625} 626 627/* ARGSUSED */ 628void GetLoadPoint( w, closure, call_data ) 629 Widget w; /* unused */ 630 XtPointer closure; /* unused */ 631 XtPointer call_data; /* pointer to (double) return value */ 632{ 633 double *loadavg = (double *)call_data; 634 635 (void) lseek(kmem, loadavg_seek, 0); 636 637# if defined(SVR4) || defined(sgi) || (BSD >= 199103) 638 { 639 long temp; 640 (void) read(kmem, (char *)&temp, sizeof(long)); 641 *loadavg = (double)temp/FSCALE; 642 } 643# else /* else not SVR4 or sgi or BSD */ 644 (void) read(kmem, (char *)loadavg, sizeof(double)); 645# endif /* SVR4 or ... else */ 646 return; 647} 648# endif /* __bsdi__ else */ 649# endif /* __QNXNTO__ else */ 650# endif /* __osf__ else */ 651# endif /* LOADSTUB else */ 652# endif /* __APPLE__ else */ 653# endif /* __GNU__ else */ 654# endif /* linux else */ 655# endif /* SYSV && i386 else */ 656# endif /* HAVE_GETLOADAVG else */ 657 658static void xload_error(const char *str1, const char *str2) 659{ 660 (void) fprintf(stderr,"xload: %s %s\n", str1, str2); 661# ifdef __bsdi__ 662 if (kd) 663 kvm_close(kd); 664# endif 665 exit(-1); 666} 667 668#endif /* END of __CYGWIN__ */ 669