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