- expand $ variables in filenames
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed_cpustatus.c
1 /*
2      This file is part of GNUnet.
3      (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file testbed/gnunet-service-testbed_cpustatus.c
23  * @brief calls to determine current CPU load
24  * @author Tzvetan Horozov
25  * @author Christian Grothoff
26  * @author Igor Wronsky
27  * @author Alex Harper (OS X portion)
28  * @author Sree Harsha Totakura
29  */
30
31 #include "platform.h"
32 #include "gnunet_util_lib.h"
33
34 #if SOLARIS
35 #if HAVE_KSTAT_H
36 #include <kstat.h>
37 #endif
38 #if HAVE_SYS_SYSINFO_H
39 #include <sys/sysinfo.h>
40 #endif
41 #if HAVE_KVM_H
42 #include <kvm.h>
43 #endif
44 #endif
45 #if SOMEBSD
46 #if HAVE_KVM_H
47 #include <kvm.h>
48 #endif
49 #endif
50
51 #ifdef OSX
52 #include <mach/mach.h>
53
54 static processor_cpu_load_info_t prev_cpu_load;
55 #endif
56
57 #define DEBUG_STATUSCALLS GNUNET_NO
58
59 #ifdef LINUX
60 static FILE *proc_stat;
61 #endif
62
63 /**
64  * Current CPU load, as percentage of CPU cycles not idle or
65  * blocked on IO.
66  */
67 static int currentCPULoad;
68
69 static double agedCPULoad = -1;
70
71 /**
72  * Current IO load, as percentage of CPU cycles blocked on IO.
73  */
74 static int currentIOLoad;
75
76 static double agedIOLoad = -1;
77
78
79 /**
80  * hanlde to the file to write the load statistics to
81  */
82 struct GNUNET_BIO_WriteHandle *bw;
83
84 GNUNET_SCHEDULER_TaskIdentifier sample_load_task_id;
85
86
87 #ifdef OSX
88 static int
89 initMachCpuStats ()
90 {
91   unsigned int cpu_count;
92   processor_cpu_load_info_t cpu_load;
93   mach_msg_type_number_t cpu_msg_count;
94   kern_return_t kret;
95   int i, j;
96
97   kret = host_processor_info (mach_host_self (),
98                               PROCESSOR_CPU_LOAD_INFO,
99                               &cpu_count,
100                               (processor_info_array_t *) & cpu_load,
101                               &cpu_msg_count);
102   if (kret != KERN_SUCCESS)
103     {
104       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
105       return GNUNET_SYSERR;
106     }
107   prev_cpu_load = GNUNET_malloc (cpu_count * sizeof (*prev_cpu_load));
108   for (i = 0; i < cpu_count; i++)
109     {
110       for (j = 0; j < CPU_STATE_MAX; j++)
111         {
112           prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
113         }
114     }
115   vm_deallocate (mach_task_self (),
116                  (vm_address_t) cpu_load,
117                  (vm_size_t) (cpu_msg_count * sizeof (*cpu_load)));
118   return GNUNET_OK;
119 }
120 #endif
121
122 /**
123  * Update the currentCPU and currentIO load values.
124  *
125  * Before its first invocation the method initStatusCalls() must be called.
126  * If there is an error the method returns -1.
127  */
128 static int
129 updateUsage ()
130 {
131   currentIOLoad = -1;
132   currentCPULoad = -1;
133 #ifdef LINUX
134   /* under linux, first try %idle/usage using /proc/stat;
135      if that does not work, disable /proc/stat for the future
136      by closing the file and use the next-best method. */
137   if (proc_stat != NULL)
138     {
139       static unsigned long long last_cpu_results[5] = { 0, 0, 0, 0, 0 };
140       static int have_last_cpu = GNUNET_NO;
141       int ret;
142       char line[256];
143       unsigned long long user_read, system_read, nice_read, idle_read,
144         iowait_read;
145       unsigned long long user, system, nice, idle, iowait;
146       unsigned long long usage_time = 0, total_time = 1;
147
148       /* Get the first line with the data */
149       rewind (proc_stat);
150       fflush (proc_stat);
151       if (NULL == fgets (line, 256, proc_stat))
152         {
153           GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
154                                     "fgets", "/proc/stat");
155           proc_stat = NULL;     /* don't try again */
156         }
157       else
158         {
159           iowait_read = 0;
160           ret = sscanf (line, "%*s %llu %llu %llu %llu %llu",
161                         &user_read,
162                         &system_read, &nice_read, &idle_read, &iowait_read);
163           if (ret < 4)
164             {
165               GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
166                                         "fgets-sscanf", "/proc/stat");
167               fclose (proc_stat);
168               proc_stat = NULL; /* don't try again */
169               have_last_cpu = GNUNET_NO;
170             }
171           else
172             {
173               /* Store the current usage */
174               user = user_read - last_cpu_results[0];
175               system = system_read - last_cpu_results[1];
176               nice = nice_read - last_cpu_results[2];
177               idle = idle_read - last_cpu_results[3];
178               iowait = iowait_read - last_cpu_results[4];
179               /* Calculate the % usage */
180               usage_time = user + system + nice;
181               total_time = usage_time + idle + iowait;
182               if ((total_time > 0) && (have_last_cpu == GNUNET_YES))
183                 {
184                   currentCPULoad = (int) (100L * usage_time / total_time);
185                   if (ret > 4)
186                     currentIOLoad = (int) (100L * iowait / total_time);
187                   else
188                     currentIOLoad = -1; /* 2.4 kernel */
189                 }
190               /* Store the values for the next calculation */
191               last_cpu_results[0] = user_read;
192               last_cpu_results[1] = system_read;
193               last_cpu_results[2] = nice_read;
194               last_cpu_results[3] = idle_read;
195               last_cpu_results[4] = iowait_read;
196               have_last_cpu = GNUNET_YES;
197               return GNUNET_OK;
198             }
199         }
200     }
201 #endif
202
203 #ifdef OSX
204   {
205     unsigned int cpu_count;
206     processor_cpu_load_info_t cpu_load;
207     mach_msg_type_number_t cpu_msg_count;
208     unsigned long long t_sys, t_user, t_nice, t_idle, t_total;
209     unsigned long long t_idle_all, t_total_all;
210     kern_return_t kret;
211     int i, j;
212
213     t_idle_all = t_total_all = 0;
214     kret = host_processor_info (mach_host_self (), PROCESSOR_CPU_LOAD_INFO,
215                                 &cpu_count,
216                                 (processor_info_array_t *) & cpu_load,
217                                 &cpu_msg_count);
218     if (kret == KERN_SUCCESS)
219       {
220         for (i = 0; i < cpu_count; i++)
221           {
222             if (cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] >=
223                 prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM])
224               {
225                 t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] -
226                   prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM];
227               }
228             else
229               {
230                 t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] +
231                   (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] +
232                    1);
233               }
234
235             if (cpu_load[i].cpu_ticks[CPU_STATE_USER] >=
236                 prev_cpu_load[i].cpu_ticks[CPU_STATE_USER])
237               {
238                 t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER] -
239                   prev_cpu_load[i].cpu_ticks[CPU_STATE_USER];
240               }
241             else
242               {
243                 t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER] +
244                   (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_USER] +
245                    1);
246               }
247
248             if (cpu_load[i].cpu_ticks[CPU_STATE_NICE] >=
249                 prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE])
250               {
251                 t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE] -
252                   prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE];
253               }
254             else
255               {
256                 t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE] +
257                   (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE] +
258                    1);
259               }
260
261             if (cpu_load[i].cpu_ticks[CPU_STATE_IDLE] >=
262                 prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE])
263               {
264                 t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE] -
265                   prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE];
266               }
267             else
268               {
269                 t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE] +
270                   (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE] +
271                    1);
272               }
273             t_total = t_sys + t_user + t_nice + t_idle;
274             t_idle_all += t_idle;
275             t_total_all += t_total;
276           }
277         for (i = 0; i < cpu_count; i++)
278           {
279             for (j = 0; j < CPU_STATE_MAX; j++)
280               {
281                 prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
282               }
283           }
284         if (t_total_all > 0)
285           currentCPULoad = 100 - (100 * t_idle_all) / t_total_all;
286         else
287           currentCPULoad = -1;
288         vm_deallocate (mach_task_self (),
289                        (vm_address_t) cpu_load,
290                        (vm_size_t) (cpu_msg_count * sizeof (*cpu_load)));
291         currentIOLoad = -1;     /* FIXME-OSX! */
292         return GNUNET_OK;
293       }
294     else
295       {
296         GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
297         return GNUNET_SYSERR;
298       }
299   }
300 #endif
301   /* try kstat (Solaris only) */
302 #if SOLARIS && HAVE_KSTAT_H && HAVE_SYS_SYSINFO_H
303   {
304     static long long last_idlecount;
305     static long long last_totalcount;
306     static int kstat_once;      /* if open fails, don't keep
307                                    trying */
308     kstat_ctl_t *kc;
309     kstat_t *khelper;
310     long long idlecount;
311     long long totalcount;
312     long long deltaidle;
313     long long deltatotal;
314
315     if (kstat_once == 1)
316       goto ABORT_KSTAT;
317     kc = kstat_open ();
318     if (kc == NULL)
319       {
320         GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");        
321         goto ABORT_KSTAT;
322       }
323
324     idlecount = 0;
325     totalcount = 0;
326     for (khelper = kc->kc_chain; khelper != NULL; khelper = khelper->ks_next)
327       {
328         cpu_stat_t stats;
329
330         if (0 != strncmp (khelper->ks_name, "cpu_stat", strlen ("cpu_stat")))
331           continue;
332         if (khelper->ks_data_size > sizeof (cpu_stat_t))
333           continue;             /* better save then sorry! */
334         if (-1 != kstat_read (kc, khelper, &stats))
335           {
336             idlecount += stats.cpu_sysinfo.cpu[CPU_IDLE];
337             totalcount
338               += stats.cpu_sysinfo.cpu[CPU_IDLE] +
339               stats.cpu_sysinfo.cpu[CPU_USER] +
340               stats.cpu_sysinfo.cpu[CPU_KERNEL] +
341               stats.cpu_sysinfo.cpu[CPU_WAIT];
342           }
343       }
344     if (0 != kstat_close (kc))
345       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
346     if ((idlecount == 0) && (totalcount == 0))
347       goto ABORT_KSTAT;         /* no stats found => abort */
348     deltaidle = idlecount - last_idlecount;
349     deltatotal = totalcount - last_totalcount;
350     if ((deltatotal > 0) && (last_totalcount > 0))
351       {
352         currentCPULoad = (unsigned int) (100.0 * deltaidle / deltatotal);
353         if (currentCPULoad > 100)
354           currentCPULoad = 100; /* odd */
355         if (currentCPULoad < 0)
356           currentCPULoad = 0;   /* odd */
357         currentCPULoad = 100 - currentCPULoad;  /* computed idle-load before! */
358       }
359     else
360       currentCPULoad = -1;
361     currentIOLoad = -1;         /* FIXME-SOLARIS! */
362     last_idlecount = idlecount;
363     last_totalcount = totalcount;
364     return GNUNET_OK;
365   ABORT_KSTAT:
366     kstat_once = 1;             /* failed, don't try again */
367     return GNUNET_SYSERR;
368   }
369 #endif
370
371   /* insert methods better than getloadavg for
372      other platforms HERE! */
373
374   /* ok, maybe we have getloadavg on this platform */
375 #if HAVE_GETLOADAVG
376   {
377     static int warnOnce = 0;
378     double loadavg;
379     if (1 != getloadavg (&loadavg, 1))
380       {
381         /* only warn once, if there is a problem with
382            getloadavg, we're going to hit it frequently... */
383         if (warnOnce == 0)
384           {
385             warnOnce = 1;
386             GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getloadavg");
387           }
388         return GNUNET_SYSERR;
389       }
390     else
391       {
392         /* success with getloadavg */
393         currentCPULoad = (int) (100 * loadavg);
394         currentIOLoad = -1;     /* FIXME */
395         return GNUNET_OK;
396       }
397   }
398 #endif
399
400 #if MINGW
401   /* Win NT? */
402   if (GNNtQuerySystemInformation)
403     {
404       static double dLastKernel;
405       static double dLastIdle;
406       static double dLastUser;
407       double dKernel;
408       double dIdle;
409       double dUser;
410       double dDiffKernel;
411       double dDiffIdle;
412       double dDiffUser;
413       SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION theInfo;
414
415       if (GNNtQuerySystemInformation (SystemProcessorPerformanceInformation,
416                                       &theInfo,
417                                       sizeof (theInfo), NULL) == NO_ERROR)
418         {
419           /* PORT-ME MINGW: Multi-processor? */
420           dKernel = Li2Double (theInfo.KernelTime);
421           dIdle = Li2Double (theInfo.IdleTime);
422           dUser = Li2Double (theInfo.UserTime);
423           dDiffKernel = dKernel - dLastKernel;
424           dDiffIdle = dIdle - dLastIdle;
425           dDiffUser = dUser - dLastUser;
426
427           if (((dDiffKernel + dDiffUser) > 0) &&
428               (dLastIdle + dLastKernel + dLastUser > 0))
429             currentCPULoad =
430               100.0 - (dDiffIdle / (dDiffKernel + dDiffUser)) * 100.0;
431           else
432             currentCPULoad = -1;        /* don't know (yet) */
433
434           dLastKernel = dKernel;
435           dLastIdle = dIdle;
436           dLastUser = dUser;
437
438           currentIOLoad = -1;   /* FIXME-MINGW */
439           return GNUNET_OK;
440         }
441       else
442         {
443           /* only warn once, if there is a problem with
444              NtQuery..., we're going to hit it frequently... */
445           static int once;
446           if (once == 0)
447             {
448               once = 1;
449               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
450                           "Cannot query the CPU usage (Windows NT).\n");
451             }
452           return GNUNET_SYSERR;
453         }
454     }
455   else
456     {                           /* Win 9x */
457       HKEY hKey;
458       DWORD dwDataSize, dwType, dwDummy;
459
460       /* Start query */
461       if (RegOpenKeyEx (HKEY_DYN_DATA,
462                         "PerfStats\\StartSrv",
463                         0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
464         {
465           /* only warn once */
466           static int once = 0;
467           if (once == 0)
468             {
469               once = 1;
470               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
471                           "Cannot query the CPU usage (Win 9x)\n");
472             }
473         }
474
475       RegOpenKeyEx (HKEY_DYN_DATA,
476                     "PerfStats\\StartStat", 0, KEY_ALL_ACCESS, &hKey);
477       dwDataSize = sizeof (dwDummy);
478       RegQueryValueEx (hKey,
479                        "KERNEL\\CPUUsage",
480                        NULL, &dwType, (LPBYTE) & dwDummy, &dwDataSize);
481       RegCloseKey (hKey);
482
483       /* Get CPU usage */
484       RegOpenKeyEx (HKEY_DYN_DATA,
485                     "PerfStats\\StatData", 0, KEY_ALL_ACCESS, &hKey);
486       dwDataSize = sizeof (currentCPULoad);
487       RegQueryValueEx (hKey,
488                        "KERNEL\\CPUUsage",
489                        NULL, &dwType, (LPBYTE) & currentCPULoad, &dwDataSize);
490       RegCloseKey (hKey);
491       currentIOLoad = -1;       /* FIXME-MINGW! */
492
493       /* Stop query */
494       RegOpenKeyEx (HKEY_DYN_DATA,
495                     "PerfStats\\StopStat", 0, KEY_ALL_ACCESS, &hKey);
496       RegOpenKeyEx (HKEY_DYN_DATA,
497                     "PerfStats\\StopSrv", 0, KEY_ALL_ACCESS, &hKey);
498       dwDataSize = sizeof (dwDummy);
499       RegQueryValueEx (hKey,
500                        "KERNEL\\CPUUsage",
501                        NULL, &dwType, (LPBYTE) & dwDummy, &dwDataSize);
502       RegCloseKey (hKey);
503
504       return GNUNET_OK;
505     }
506 #endif
507
508   /* loadaverage not defined and no platform
509      specific alternative defined
510      => default: error
511    */
512   return GNUNET_SYSERR;
513 }
514
515
516 /**
517  * Update load values (if enough time has expired),
518  * including computation of averages.  Code assumes
519  * that lock has already been obtained.
520  */
521 static void
522 updateAgedLoad ()
523 {
524   static struct GNUNET_TIME_Absolute lastCall;
525   struct GNUNET_TIME_Relative age;
526
527   age = GNUNET_TIME_absolute_get_duration (lastCall);
528   if ( (agedCPULoad == -1)
529        || (age.rel_value > 500) )
530     {
531       /* use smoothing, but do NOT update lastRet at frequencies higher
532          than 500ms; this makes the smoothing (mostly) independent from
533          the frequency at which getCPULoad is called (and we don't spend
534          more time measuring CPU than actually computing something). */
535       lastCall = GNUNET_TIME_absolute_get ();
536       updateUsage ();
537       if (currentCPULoad == -1)
538         {
539           agedCPULoad = -1;
540         }
541       else
542         {
543           if (agedCPULoad == -1)
544             {
545               agedCPULoad = currentCPULoad;
546             }
547           else
548             {
549               /* for CPU, we don't do the 'fast increase' since CPU is much
550                  more jitterish to begin with */
551               agedCPULoad = (agedCPULoad * 31 + currentCPULoad) / 32;
552             }
553         }
554       if (currentIOLoad == -1)
555         {
556           agedIOLoad = -1;
557         }
558       else
559         {
560           if (agedIOLoad == -1)
561             {
562               agedIOLoad = currentIOLoad;
563             }
564           else
565             {
566               /* for IO, we don't do the 'fast increase' since IO is much
567                  more jitterish to begin with */
568               agedIOLoad = (agedIOLoad * 31 + currentIOLoad) / 32;
569             }
570         }
571     }
572 }
573
574 /**
575  * Get the load of the CPU relative to what is allowed.
576  * @return the CPU load as a percentage of allowed
577  *        (100 is equivalent to full load)
578  */
579 static int
580 cpu_get_load ()
581 {
582   updateAgedLoad ();
583   return (int) agedCPULoad;
584 }
585
586
587 /**
588  * Get the load of the CPU relative to what is allowed.
589  * @return the CPU load as a percentage of allowed
590  *        (100 is equivalent to full load)
591  */
592 static int
593 disk_get_load ()
594 {
595   updateAgedLoad ();
596   return (int) agedIOLoad;
597 }
598
599
600 static void
601 sample_load_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
602 {
603   struct GNUNET_TIME_Absolute now;
604   char *str;
605   int nbs;
606   int ld_cpu;
607   int ld_disk;
608
609   sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
610   if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
611     return;
612   ld_cpu = cpu_get_load ();
613   ld_disk = disk_get_load ();
614   if ( (-1 == ld_cpu) || (-1 == ld_disk) )
615     goto reschedule;
616   now = GNUNET_TIME_absolute_get ();
617   nbs = GNUNET_asprintf (&str, "%llu %d %d\n", now.abs_value / 1000,
618                          ld_cpu, ld_disk);
619   if (0 < nbs) 
620   {
621     GNUNET_BIO_write (bw, str, nbs);
622     GNUNET_free (str);
623   }
624   else
625     GNUNET_break (0);
626
627  reschedule:
628   sample_load_task_id =
629       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
630                                     &sample_load_task, NULL);
631 }
632
633
634 /**
635  * Initialize logging CPU and IO statisticfs.  Checks the configuration for
636  * "STATS_DIR" and logs to a file in that directory.  The file is name is
637  * generated from the hostname and the process's PID.
638  */
639 void
640 GST_stats_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
641 {
642   char *hostname;
643   char *stats_dir;
644   char *fn;
645   size_t len;
646   
647 #if MINGW
648   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
649               "Load statistics logging now available for windows\n");
650   return;                       /* No logging on windows for now :( */
651 #endif
652
653   if (GNUNET_OK !=
654       GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
655                                                "STATS_DIR", &stats_dir))
656     return;
657   len = GNUNET_OS_get_hostname_max_length ();
658   hostname = GNUNET_malloc (len);
659   if (0 != gethostname  (hostname, len))
660   {
661     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
662     GNUNET_free (stats_dir);
663     GNUNET_free (hostname);
664     return;
665   }
666   fn = NULL;  
667   (void) GNUNET_asprintf (&fn, "%s/%.*s-%jd.dat", stats_dir, len,
668                           hostname, (intmax_t) getpid());
669   GNUNET_free (stats_dir);
670   GNUNET_free (hostname);
671   if (NULL == (bw = GNUNET_BIO_write_open (fn)))
672   {
673     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
674                 _("Cannot open %s for writing load statistics.  "
675                   "Not logging load statistics\n"), fn);
676     GNUNET_free (fn);
677     return;
678   }
679   GNUNET_free (fn);
680   sample_load_task_id = GNUNET_SCHEDULER_add_now (&sample_load_task, NULL);
681 #ifdef LINUX
682   proc_stat = fopen ("/proc/stat", "r");
683   if (NULL == proc_stat)
684     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
685                               "fopen", "/proc/stat");
686 #elif OSX
687   initMachCpuStats ();
688 #endif
689   updateUsage ();               /* initialize */
690   
691 }
692
693
694 /**
695  * Shutdown the status calls module.
696  */
697 void
698 GST_stats_destroy ()
699 {
700 #if MINGW
701   return;
702 #endif
703   if (NULL == bw)
704     return;
705 #ifdef LINUX
706   if (proc_stat != NULL)
707     {
708       fclose (proc_stat);
709       proc_stat = NULL;
710     }
711 #elif OSX
712   GNUNET_free_non_null (prev_cpu_load);
713 #endif
714   if (GNUNET_SCHEDULER_NO_TASK != sample_load_task_id)
715   {
716     GNUNET_SCHEDULER_cancel (sample_load_task_id);
717     sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
718   }
719   GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bw));
720   bw = NULL;
721 }
722
723 /* end of cpustatus.c */