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