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