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