1fd0c672fSmrg/*
2fd0c672fSmrg
3fd0c672fSmrgCopyright (c) 1989  X Consortium
4fd0c672fSmrg
5fd0c672fSmrgPermission is hereby granted, free of charge, to any person obtaining
6fd0c672fSmrga copy of this software and associated documentation files (the
7fd0c672fSmrg"Software"), to deal in the Software without restriction, including
8fd0c672fSmrgwithout limitation the rights to use, copy, modify, merge, publish,
9fd0c672fSmrgdistribute, sublicense, and/or sell copies of the Software, and to
10fd0c672fSmrgpermit persons to whom the Software is furnished to do so, subject to
11fd0c672fSmrgthe following conditions:
12fd0c672fSmrg
13fd0c672fSmrgThe above copyright notice and this permission notice shall be included
14fd0c672fSmrgin all copies or substantial portions of the Software.
15fd0c672fSmrg
16fd0c672fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17fd0c672fSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18fd0c672fSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19fd0c672fSmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20fd0c672fSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21fd0c672fSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22fd0c672fSmrgOTHER DEALINGS IN THE SOFTWARE.
23fd0c672fSmrg
24fd0c672fSmrgExcept as contained in this notice, the name of the X Consortium shall
25fd0c672fSmrgnot be used in advertising or otherwise to promote the sale, use or
26fd0c672fSmrgother dealings in this Software without prior written authorization
27fd0c672fSmrgfrom the X Consortium.
28fd0c672fSmrg
29fd0c672fSmrg*/
30fd0c672fSmrg
31fd0c672fSmrg/*
32fd0c672fSmrg * get_load - get system load
33fd0c672fSmrg *
34fd0c672fSmrg * Authors:  Many and varied...
35fd0c672fSmrg *
36fd0c672fSmrg * Call InitLoadPoint() to initialize.
37fd0c672fSmrg * GetLoadPoint() is a callback for the StripChart widget.
38fd0c672fSmrg */
39fd0c672fSmrg
40fd0c672fSmrg#ifdef HAVE_CONFIG_H
41fd0c672fSmrg# include "config.h"
42fd0c672fSmrg#endif
43fd0c672fSmrg
44fd0c672fSmrg#include <X11/Xos.h>
45fd0c672fSmrg#include <X11/Intrinsic.h>
46fd0c672fSmrg#include <X11/Xlocale.h>
47fd0c672fSmrg#include <stdio.h>
48fd0c672fSmrg#include <stdlib.h>
49fd0c672fSmrg#include "xload.h"
50fd0c672fSmrg
518846b520Smrg#if defined(__CYGWIN__) || defined(_WIN32)
52953c684bSmrg# define WIN32_LEAN_AND_MEAN
538846b520Smrg# include <X11/Xwindows.h>
54fd0c672fSmrgtypedef struct {
55fd0c672fSmrg  DWORD stat;
56fd0c672fSmrg  union {
57fd0c672fSmrg    LONG vLong;
58fd0c672fSmrg    double vDouble;
59fd0c672fSmrg    LONGLONG vLongLong;
60fd0c672fSmrg    void *string;
61fd0c672fSmrg  } u;
62fd0c672fSmrg} COUNTER;
63fd0c672fSmrgstatic HANDLE query;
64fd0c672fSmrgstatic HANDLE counter;
65fd0c672fSmrgstatic HINSTANCE hdll;
66fd0c672fSmrgstatic long (__stdcall *pdhopen)(LPCSTR, DWORD, HANDLE);
67fd0c672fSmrgstatic long (__stdcall *pdhaddcounter)(HANDLE, LPCSTR, DWORD, HANDLE*);
68fd0c672fSmrgstatic long (__stdcall *pdhcollectquerydata)(HANDLE);
69fd0c672fSmrgstatic long (__stdcall *pdhgetformattedcountervalue)(HANDLE, DWORD, LPDWORD, COUNTER*);
70953c684bSmrg# define CYGWIN_PERF
71a8bb11d0Smrgvoid InitLoadPoint(void)
72fd0c672fSmrg{
73fd0c672fSmrg  long ret;
74fd0c672fSmrg  hdll=LoadLibrary("pdh.dll");
75fd0c672fSmrg  if (!hdll) exit(-1);
76fd0c672fSmrg  pdhopen=(void*)GetProcAddress(hdll, "PdhOpenQueryA");
77fd0c672fSmrg  if (!pdhopen) exit(-1);
78fd0c672fSmrg  pdhaddcounter=(void*)GetProcAddress(hdll, "PdhAddCounterA");
79fd0c672fSmrg  if (!pdhaddcounter) exit(-1);
80fd0c672fSmrg  pdhcollectquerydata=(void*)GetProcAddress(hdll, "PdhCollectQueryData");
81fd0c672fSmrg  if (!pdhcollectquerydata) exit(-1);
82fd0c672fSmrg  pdhgetformattedcountervalue=(void*)GetProcAddress(hdll, "PdhGetFormattedCounterValue");
83fd0c672fSmrg  if (!pdhgetformattedcountervalue) exit(-1);
84fd0c672fSmrg  ret = pdhopen( NULL , 0, &query );
85fd0c672fSmrg  if (ret!=0) exit(-1);
86fd0c672fSmrg  ret = pdhaddcounter(query, "\\Processor(_Total)\\% Processor Time", 0, &counter);
87953c684bSmrg  if (ret!=0) exit(-1);
88fd0c672fSmrg}
89a8bb11d0Smrgvoid GetLoadPoint(
90a8bb11d0Smrg     Widget  w,              /* unused */
91a8bb11d0Smrg     XtPointer    closure,        /* unused */
92a8bb11d0Smrg     XtPointer    call_data)      /* pointer to (double) return value */
93fd0c672fSmrg{
94fd0c672fSmrg  double *loadavg = (double *)call_data;
95fd0c672fSmrg  COUNTER fmtvalue;
96fd0c672fSmrg  long ret;
97fd0c672fSmrg  *loadavg = 0.0;
98fd0c672fSmrg  ret = pdhcollectquerydata(query);
99fd0c672fSmrg  if (ret!=0) return;
100fd0c672fSmrg  ret = pdhgetformattedcountervalue(counter, 0x200, NULL, &fmtvalue);
101fd0c672fSmrg  if (ret!=0) return;
102fd0c672fSmrg  *loadavg = (fmtvalue.u.vDouble-0.01)/100.0;
103fd0c672fSmrg}
104953c684bSmrg#else /* not CYGWIN */
105fd0c672fSmrg
106953c684bSmrgstatic void xload_error(const char *, const char *) _X_NORETURN;
107fd0c672fSmrg
108953c684bSmrg# ifdef HAVE_GETLOADAVG
109953c684bSmrg#  include <stdlib.h>
110953c684bSmrg#  ifdef HAVE_SYS_LOADAVG_H
111953c684bSmrg#   include <sys/loadavg.h>	/* Solaris definition of getloadavg */
112953c684bSmrg#  endif
113fd0c672fSmrg
114953c684bSmrgvoid InitLoadPoint(void)
115953c684bSmrg{
116953c684bSmrg}
117fd0c672fSmrg
118953c684bSmrgvoid GetLoadPoint(
119953c684bSmrg    Widget w,            /* unused */
120953c684bSmrg    XtPointer closure,   /* unused */
121953c684bSmrg    XtPointer call_data) /* ptr to (double) return value */
122953c684bSmrg{
123953c684bSmrg    double *loadavg = (double *)call_data;
124fd0c672fSmrg
125953c684bSmrg    if (getloadavg(loadavg, 1) < 0)
126953c684bSmrg        xload_error("couldn't obtain load average", "");
127953c684bSmrg}
128fd0c672fSmrg
129953c684bSmrg# else /* not HAVE_GETLOADAVG */
130fd0c672fSmrg
131fd0c672fSmrg
13283f4f7f0Smrg#  if !defined(linux) && !defined(__GLIBC__)
13383f4f7f0Smrg#   include <nlist.h>
13483f4f7f0Smrg#  endif /* !linux && ... */
135fd0c672fSmrg
136953c684bSmrg#  ifdef CSRG_BASED
137953c684bSmrg#   include <sys/param.h>
138953c684bSmrg#  endif
139fd0c672fSmrg
14083f4f7f0Smrg#  if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
141fd0c672fSmrg
14248e69166Smrgvoid InitLoadPoint(void)
143fd0c672fSmrg{
144fd0c672fSmrg      return;
145fd0c672fSmrg}
146fd0c672fSmrg
14748e69166Smrgvoid GetLoadPoint(
14848e69166Smrg    Widget	w,		/* unused */
14948e69166Smrg    XtPointer	closure,	/* unused */
15048e69166Smrg    XtPointer	call_data)      /* pointer to (double) return value */
151fd0c672fSmrg{
152fd0c672fSmrg      static int fd = -1;
153fd0c672fSmrg      int n;
154fd0c672fSmrg      char buf[10] = {0, };
15583f4f7f0Smrg#   ifndef X_LOCALE
156fd0c672fSmrg      char *dp;
157fd0c672fSmrg      static char ldp = 0;
15883f4f7f0Smrg#   endif
159fd0c672fSmrg
160fd0c672fSmrg
161fd0c672fSmrg      if (fd < 0)
162fd0c672fSmrg      {
163fd0c672fSmrg              if (fd == -2 ||
164fd0c672fSmrg                  (fd = open("/proc/loadavg", O_RDONLY)) < 0)
165fd0c672fSmrg              {
166fd0c672fSmrg                      fd = -2;
167fd0c672fSmrg                      *(double *)call_data = 0.0;
168fd0c672fSmrg                      return;
169fd0c672fSmrg              }
17083f4f7f0Smrg#   ifndef X_LOCALE
171fd0c672fSmrg	      ldp = *localeconv()->decimal_point;
17283f4f7f0Smrg#   endif
173fd0c672fSmrg      }
174fd0c672fSmrg      else
175fd0c672fSmrg              lseek(fd, 0, 0);
176fd0c672fSmrg
177fd0c672fSmrg      if ((n = read(fd, buf, sizeof(buf)-1)) > 0) {
17883f4f7f0Smrg#   ifndef X_LOCALE
179fd0c672fSmrg	  if (ldp != '.')
180fd0c672fSmrg	      while ((dp = memchr(buf,'.',sizeof(buf)-1)) != NULL) {
181fd0c672fSmrg		  *(char *)dp = ldp;
182fd0c672fSmrg	      }
183953c684bSmrg
18483f4f7f0Smrg#   endif
185fd0c672fSmrg	  if (sscanf(buf, "%lf", (double *)call_data) == 1)
186fd0c672fSmrg	      return;
187fd0c672fSmrg      }
188953c684bSmrg
189fd0c672fSmrg
190fd0c672fSmrg      *(double *)call_data = 0.0;     /* temporary hiccup */
191fd0c672fSmrg
192fd0c672fSmrg      return;
193fd0c672fSmrg}
194fd0c672fSmrg
19583f4f7f0Smrg#  else /* linux */
196fd0c672fSmrg
19783f4f7f0Smrg#   ifdef __GNU__
198fd0c672fSmrg
19983f4f7f0Smrg#    include <mach.h>
200fd0c672fSmrg
201fd0c672fSmrgstatic processor_set_t default_set;
202fd0c672fSmrg
20348e69166Smrgvoid InitLoadPoint(void)
204fd0c672fSmrg{
205fd0c672fSmrg  if (processor_set_default (mach_host_self (), &default_set) != KERN_SUCCESS)
206fd0c672fSmrg    xload_error("cannot get processor_set_default", "");
207fd0c672fSmrg}
208fd0c672fSmrg
209fd0c672fSmrg/* ARGSUSED */
21048e69166Smrgvoid GetLoadPoint(
21148e69166Smrg    Widget	w,		/* unused */
21248e69166Smrg    XtPointer	closure,	/* unused */
21348e69166Smrg    XtPointer	call_data)	/* pointer to (double) return value */
214fd0c672fSmrg{
215fd0c672fSmrg  host_t host;
216fd0c672fSmrg  struct processor_set_basic_info info;
217fd0c672fSmrg  unsigned info_count;
218fd0c672fSmrg
219fd0c672fSmrg  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
220fd0c672fSmrg  if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
221fd0c672fSmrg			  (processor_set_info_t) &info, &info_count)
222fd0c672fSmrg      != KERN_SUCCESS)
223fd0c672fSmrg    {
224fd0c672fSmrg      InitLoadPoint();
225fd0c672fSmrg      info.load_average = 0;
226fd0c672fSmrg    }
227fd0c672fSmrg
228fd0c672fSmrg  *(double *)call_data = info.load_average * 1000 / LOAD_SCALE;
229fd0c672fSmrg
230fd0c672fSmrg  return;
231fd0c672fSmrg}
232fd0c672fSmrg
23383f4f7f0Smrg#   else /* __GNU__ */
234fd0c672fSmrg
23583f4f7f0Smrg#    ifdef __APPLE__
236fd0c672fSmrg
23783f4f7f0Smrg#     include <mach/mach.h>
238fd0c672fSmrg
239fd0c672fSmrgstatic mach_port_t host_priv_port;
240fd0c672fSmrg
24148e69166Smrgvoid InitLoadPoint(void)
242fd0c672fSmrg{
243fd0c672fSmrg    host_priv_port = mach_host_self();
244fd0c672fSmrg}
245fd0c672fSmrg
246fd0c672fSmrg/* ARGSUSED */
24748e69166Smrgvoid GetLoadPoint(
24848e69166Smrg    Widget	w,		/* unused */
24948e69166Smrg    XtPointer	closure,	/* unused */
25048e69166Smrg    XtPointer	call_data)	/* pointer to (double) return value */
251fd0c672fSmrg{
252fd0c672fSmrg    double *loadavg = (double *)call_data;
253fd0c672fSmrg
254fd0c672fSmrg    struct host_load_info load_data;
255fd0c672fSmrg    int host_count;
256fd0c672fSmrg    kern_return_t kr;
257fd0c672fSmrg
258fd0c672fSmrg    host_count = sizeof(load_data)/sizeof(integer_t);
259fd0c672fSmrg    kr = host_statistics(host_priv_port, HOST_LOAD_INFO,
260fd0c672fSmrg                        (host_info_t)&load_data, &host_count);
261fd0c672fSmrg    if (kr != KERN_SUCCESS)
262fd0c672fSmrg        xload_error("cannot get host statistics", "");
263fd0c672fSmrg    *loadavg = (double)load_data.avenrun[0]/LOAD_SCALE;
264fd0c672fSmrg    return;
265fd0c672fSmrg}
266fd0c672fSmrg
26783f4f7f0Smrg#    else /* __APPLE__ */
268fd0c672fSmrg
269fd0c672fSmrg
270fd0c672fSmrg
27183f4f7f0Smrg#     ifdef __QNXNTO__
27283f4f7f0Smrg#      include <time.h>
27383f4f7f0Smrg#      include <sys/neutrino.h>
274fd0c672fSmrgstatic _Uint64t          nto_idle = 0, nto_idle_last = 0;
275fd0c672fSmrgstatic  int       nto_idle_id;
276fd0c672fSmrgstatic  struct timespec nto_now, nto_last;
277fd0c672fSmrg
278fd0c672fSmrgvoid
27948e69166SmrgInitLoadPoint(void)
280fd0c672fSmrg{
281fd0c672fSmrg  nto_idle_id = ClockId(1, 1); /* Idle thread */
282fd0c672fSmrg  ClockTime(nto_idle_id, NULL, &nto_idle_last);
283fd0c672fSmrg  clock_gettime( CLOCK_REALTIME, &nto_last);
284fd0c672fSmrg}
285fd0c672fSmrg
286fd0c672fSmrg/* ARGSUSED */
287fd0c672fSmrgvoid
28848e69166SmrgGetLoadPoint(			/* QNX NTO version */
28948e69166Smrg    Widget	w,		/* unused */
29048e69166Smrg    XtPointer	closure,	/* unused */
29148e69166Smrg    XtPointer	call_data)	/* pointer to (double) return value */
292fd0c672fSmrg{
293fd0c672fSmrg    double *loadavg = (double *)call_data;
294fd0c672fSmrg    double timediff;
295fd0c672fSmrg    double temp = 0.0;
296fd0c672fSmrg
297fd0c672fSmrg    ClockTime(nto_idle_id, NULL, &nto_idle);
298fd0c672fSmrg    clock_gettime( CLOCK_REALTIME, &nto_now);
299fd0c672fSmrg    timediff = 1000000000.0 * (nto_now.tv_sec - nto_last.tv_sec)
300fd0c672fSmrg               + (nto_now.tv_nsec - nto_last.tv_nsec);
301fd0c672fSmrg    temp = 1.0 - (nto_idle-nto_idle_last)/timediff;
302fd0c672fSmrg    *loadavg = temp >= 0 ? temp : 0;
303fd0c672fSmrg    nto_idle_last = nto_idle;
304fd0c672fSmrg    nto_last = nto_now;
305fd0c672fSmrg}
30683f4f7f0Smrg#     else /* not __QNXNTO__ */
307fd0c672fSmrg
30883f4f7f0Smrg#      ifndef KMEM_FILE
30983f4f7f0Smrg#       define KMEM_FILE "/dev/kmem"
31083f4f7f0Smrg#      endif
311fd0c672fSmrg
31283f4f7f0Smrg#      ifndef KERNEL_FILE
313fd0c672fSmrg/*
314fd0c672fSmrg * provide default for everyone else
315fd0c672fSmrg */
31683f4f7f0Smrg/* If <paths.h> exists, check in it */
31783f4f7f0Smrg#       ifdef HAVE_PATHS_H
31883f4f7f0Smrg#        include <paths.h>
31983f4f7f0Smrg#        ifdef _PATH_UNIX
32083f4f7f0Smrg#         define KERNEL_FILE _PATH_UNIX
32183f4f7f0Smrg#        else
32283f4f7f0Smrg#         ifdef _PATH_KERNEL
32383f4f7f0Smrg#          define KERNEL_FILE _PATH_KERNEL
32483f4f7f0Smrg#         else
32583f4f7f0Smrg#          define KERNEL_FILE "/vmunix"
32683f4f7f0Smrg#         endif
32783f4f7f0Smrg#        endif
32883f4f7f0Smrg#       else /* HAVE_PATHS_H */
32983f4f7f0Smrg#        define KERNEL_FILE "/vmunix"
33083f4f7f0Smrg#       endif /* HAVE_PATHS_H */
33183f4f7f0Smrg#      endif /* KERNEL_FILE */
33283f4f7f0Smrg
33383f4f7f0Smrg
33483f4f7f0Smrg#      ifndef KERNEL_LOAD_VARIABLE
33583f4f7f0Smrg#       if defined(BSD) && (BSD >= 199103)
33683f4f7f0Smrg#        define KERNEL_LOAD_VARIABLE "_averunnable"
33783f4f7f0Smrg#       else /* BSD >= 199103 */
33883f4f7f0Smrg#        define KERNEL_LOAD_VARIABLE "_avenrun"
33983f4f7f0Smrg#       endif /* BSD >= 199103 */
34083f4f7f0Smrg#      endif /* KERNEL_LOAD_VARIABLE */
341fd0c672fSmrg
342fd0c672fSmrgstatic struct nlist namelist[] = {	    /* namelist for vmunix grubbing */
34383f4f7f0Smrg#      define LOADAV 0
344fd0c672fSmrg    {KERNEL_LOAD_VARIABLE},
345fd0c672fSmrg    {0}
346fd0c672fSmrg};
347fd0c672fSmrg
348fd0c672fSmrgstatic int kmem;
349fd0c672fSmrgstatic long loadavg_seek;
350fd0c672fSmrg
351fd0c672fSmrgvoid InitLoadPoint()
352fd0c672fSmrg{
35383f4f7f0Smrg#      if !defined(AIXV5) && !(BSD >= 199103) && !defined(__APPLE__)
354fd0c672fSmrg    extern void nlist();
35583f4f7f0Smrg#      endif
356fd0c672fSmrg
357fd0c672fSmrg    nlist( KERNEL_FILE, namelist);
358fd0c672fSmrg    /*
359fd0c672fSmrg     * Some systems appear to set only one of these to Zero if the entry could
360fd0c672fSmrg     * not be found, I hope no_one returns Zero as a good value, or bad things
361fd0c672fSmrg     * will happen to you.  (I have a hard time believing the value will
362fd0c672fSmrg     * ever really be zero anyway).   CDP 5/17/89.
363fd0c672fSmrg     */
364fd0c672fSmrg    if (namelist[LOADAV].n_type == 0 ||
365fd0c672fSmrg	namelist[LOADAV].n_value == 0) {
366fd0c672fSmrg	xload_error("cannot get name list from", KERNEL_FILE);
367fd0c672fSmrg	exit(-1);
368fd0c672fSmrg    }
369fd0c672fSmrg    loadavg_seek = namelist[LOADAV].n_value;
370fd0c672fSmrg    kmem = open(KMEM_FILE, O_RDONLY);
371fd0c672fSmrg    if (kmem < 0) xload_error("cannot open", KMEM_FILE);
372fd0c672fSmrg}
373fd0c672fSmrg
374fd0c672fSmrg/* ARGSUSED */
375fd0c672fSmrgvoid GetLoadPoint( w, closure, call_data )
376fd0c672fSmrg     Widget	w;		/* unused */
377fd0c672fSmrg     XtPointer	closure;	/* unused */
378fd0c672fSmrg     XtPointer	call_data;	/* pointer to (double) return value */
379fd0c672fSmrg{
380fd0c672fSmrg  	double *loadavg = (double *)call_data;
381fd0c672fSmrg
382fd0c672fSmrg	(void) lseek(kmem, loadavg_seek, 0);
383fd0c672fSmrg
38483f4f7f0Smrg#      if (BSD >= 199103)
385fd0c672fSmrg	{
386fd0c672fSmrg		long temp;
387fd0c672fSmrg		(void) read(kmem, (char *)&temp, sizeof(long));
388fd0c672fSmrg		*loadavg = (double)temp/FSCALE;
389fd0c672fSmrg	}
39083f4f7f0Smrg#      else /* else not BSD */
391fd0c672fSmrg	(void) read(kmem, (char *)loadavg, sizeof(double));
39283f4f7f0Smrg#      endif /* or ... else */
393fd0c672fSmrg	return;
394fd0c672fSmrg}
39583f4f7f0Smrg#     endif /* __QNXNTO__ else */
39683f4f7f0Smrg#    endif /* __APPLE__ else */
39783f4f7f0Smrg#   endif /* __GNU__ else */
39883f4f7f0Smrg#  endif /* linux else */
399953c684bSmrg# endif /* HAVE_GETLOADAVG else */
400fd0c672fSmrg
401a8bb11d0Smrgstatic void xload_error(const char *str1, const char *str2)
402fd0c672fSmrg{
403fd0c672fSmrg    (void) fprintf(stderr,"xload: %s %s\n", str1, str2);
404fd0c672fSmrg    exit(-1);
405fd0c672fSmrg}
406fd0c672fSmrg
407fd0c672fSmrg#endif /* END of __CYGWIN__ */
408