get_load.c revision 953c684b
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__)
52# define WIN32_LEAN_AND_MEAN
53# include <windows.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