/*
This file is part of GNUnet.
- (C) 2001, 2002, 2003, 2005, 2006, 2013 Christian Grothoff (and other contributing authors)
+ (C) 2008--2013 Christian Grothoff (and other contributing authors)
GNUnet is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 2, or (at your
+ by the Free Software Foundation; either version 3, or (at your
option) any later version.
GNUnet is distributed in the hope that it will be useful, but
#include "platform.h"
#include "gnunet_util_lib.h"
+#include "gnunet-service-testbed_meminfo.h"
#if SOLARIS
#if HAVE_KSTAT_H
static processor_cpu_load_info_t prev_cpu_load;
#endif
+#ifdef WINDOWS
+#include <winternl.h>
+#endif
#define DEBUG_STATUSCALLS GNUNET_NO
static double agedIOLoad = -1;
+
+/**
+ * hanlde to the file to write the load statistics to
+ */
+struct GNUNET_BIO_WriteHandle *bw;
+
+GNUNET_SCHEDULER_TaskIdentifier sample_load_task_id;
+
+
#ifdef OSX
static int
initMachCpuStats ()
&cpu_msg_count);
if (kret != KERN_SUCCESS)
{
- GNUNET_GE_LOG (NULL,
- GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN |
- GNUNET_GE_BULK, "host_processor_info failed.");
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
return GNUNET_SYSERR;
}
prev_cpu_load = GNUNET_malloc (cpu_count * sizeof (*prev_cpu_load));
#endif
/**
- * Update the currentCPU and currentIO load values.
+ * Update the currentCPU and currentIO load (and on Linux, memory) values.
*
* Before its first invocation the method initStatusCalls() must be called.
* If there is an error the method returns -1.
}
else
{
- GNUNET_GE_LOG (NULL,
- GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN |
- GNUNET_GE_BULK, "host_processor_info failed.");
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
return GNUNET_SYSERR;
}
}
kc = kstat_open ();
if (kc == NULL)
{
- GNUNET_GE_LOG_STRERROR (NULL,
- GNUNET_GE_ERROR | GNUNET_GE_USER |
- GNUNET_GE_ADMIN | GNUNET_GE_BULK,
- "kstat_open");
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
goto ABORT_KSTAT;
}
}
}
if (0 != kstat_close (kc))
- GNUNET_GE_LOG_STRERROR (NULL,
- GNUNET_GE_ERROR | GNUNET_GE_ADMIN |
- GNUNET_GE_USER | GNUNET_GE_BULK, "kstat_close");
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
if ((idlecount == 0) && (totalcount == 0))
goto ABORT_KSTAT; /* no stats found => abort */
deltaidle = idlecount - last_idlecount;
if (once == 0)
{
once = 1;
- GNUNET_GE_LOG (NULL,
- GNUNET_GE_ERROR | GNUNET_GE_USER |
- GNUNET_GE_ADMIN | GNUNET_GE_BULK,
- _("Cannot query the CPU usage (Windows NT).\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot query the CPU usage (Windows NT).\n");
}
return GNUNET_SYSERR;
}
if (once == 0)
{
once = 1;
- GNUNET_GE_LOG (NULL,
- GNUNET_GE_USER | GNUNET_GE_ADMIN |
- GNUNET_GE_ERROR | GNUNET_GE_BULK,
- _("Cannot query the CPU usage (Win 9x)\n"));
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot query the CPU usage (Win 9x)\n");
}
}
age = GNUNET_TIME_absolute_get_duration (lastCall);
if ( (agedCPULoad == -1)
- || (age.rel_value > 500) )
+ || (age.rel_value_us > 500000) )
{
/* use smoothing, but do NOT update lastRet at frequencies higher
than 500ms; this makes the smoothing (mostly) independent from
* @return the CPU load as a percentage of allowed
* (100 is equivalent to full load)
*/
-int
-GST_cpu_get_load ()
+static int
+cpu_get_load ()
{
updateAgedLoad ();
return (int) agedCPULoad;
* @return the CPU load as a percentage of allowed
* (100 is equivalent to full load)
*/
-int
-GST_disk_get_load ()
+static int
+disk_get_load ()
{
updateAgedLoad ();
return (int) agedIOLoad;
}
/**
- * The following method is called in order to initialize the status calls
- * routines. After that it is safe to call each of the status calls separately
- * @return GNUNET_OK on success and GNUNET_SYSERR on error (or calls errexit).
+ * Get the percentage of memory used
+ *
+ * @return the percentage of memory used
+ */
+static unsigned int
+mem_get_usage ()
+{
+ double percentage;
+
+ meminfo ();
+ percentage = ( ((double) kb_main_used) / ((double) kb_main_total) * 100.0 );
+ return (unsigned int) percentage;
+}
+
+
+#ifdef LINUX
+#include <dirent.h>
+/**
+ * Returns the number of processes
+ *
+ * @return the number of processes
+ */
+static unsigned int
+get_nproc ()
+{
+ DIR *dir;
+ struct dirent *ent;
+ unsigned int nproc;
+
+ dir = opendir ("/proc");
+ if (NULL == dir)
+ return 0;
+ nproc = 0;
+ while (NULL != (ent = readdir (dir)))
+ {
+ if((*ent->d_name > '0') && (*ent->d_name <= '9'))
+ nproc++;
+ }
+ closedir (dir);
+ return nproc;
+}
+#endif
+
+
+static void
+sample_load_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TIME_Absolute now;
+ char *str;
+ int nbs;
+ int ld_cpu;
+ int ld_disk;
+ unsigned int mem_usage;
+ unsigned int nproc;
+
+ sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+ ld_cpu = cpu_get_load ();
+ ld_disk = disk_get_load ();
+ if ( (-1 == ld_cpu) || (-1 == ld_disk) )
+ goto reschedule;
+ mem_usage = mem_get_usage ();
+#ifdef LINUX
+ nproc = get_nproc ();
+#else
+ nproc = 0;
+#endif
+ now = GNUNET_TIME_absolute_get ();
+ nbs = GNUNET_asprintf (&str, "%llu %d %d %u %u\n", now.abs_value_us / 1000LL / 1000LL,
+ ld_cpu, ld_disk, mem_usage, nproc);
+ if (0 < nbs)
+ {
+ GNUNET_BIO_write (bw, str, nbs);
+ }
+ else
+ GNUNET_break (0);
+ GNUNET_free (str);
+
+ reschedule:
+ sample_load_task_id =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
+ &sample_load_task, NULL);
+}
+
+
+/**
+ * Initialize logging CPU and IO statisticfs. Checks the configuration for
+ * "STATS_DIR" and logs to a file in that directory. The file is name is
+ * generated from the hostname and the process's PID.
*/
void
-GST_stats_init ()
+GST_stats_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
{
+ char *hostname;
+ char *stats_dir;
+ char *fn;
+ size_t len;
+
+#if MINGW
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Load statistics logging now available for windows\n");
+ return; /* No logging on windows for now :( */
+#endif
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
+ "STATS_DIR", &stats_dir))
+ return;
+ len = GNUNET_OS_get_hostname_max_length ();
+ hostname = GNUNET_malloc (len);
+ if (0 != gethostname (hostname, len))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
+ GNUNET_free (stats_dir);
+ GNUNET_free (hostname);
+ return;
+ }
+ fn = NULL;
+ (void) GNUNET_asprintf (&fn, "%s/%.*s-%jd.dat", stats_dir, len,
+ hostname, (intmax_t) getpid());
+ GNUNET_free (stats_dir);
+ GNUNET_free (hostname);
+ if (NULL == (bw = GNUNET_BIO_write_open (fn)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Cannot open %s for writing load statistics. "
+ "Not logging load statistics\n"), fn);
+ GNUNET_free (fn);
+ return;
+ }
+ GNUNET_free (fn);
+ sample_load_task_id = GNUNET_SCHEDULER_add_now (&sample_load_task, NULL);
#ifdef LINUX
proc_stat = fopen ("/proc/stat", "r");
if (NULL == proc_stat)
"fopen", "/proc/stat");
#elif OSX
initMachCpuStats ();
-#elif MINGW
- InitWinEnv (NULL);
#endif
updateUsage (); /* initialize */
+
}
+
/**
* Shutdown the status calls module.
*/
void
GST_stats_destroy ()
{
+#if MINGW
+ return;
+#endif
+ if (NULL == bw)
+ return;
#ifdef LINUX
if (proc_stat != NULL)
{
}
#elif OSX
GNUNET_free_non_null (prev_cpu_load);
-#elif MINGW
- ShutdownWinEnv ();
#endif
+ if (GNUNET_SCHEDULER_NO_TASK != sample_load_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (sample_load_task_id);
+ sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bw));
+ bw = NULL;
}
-char *GST_stats_dir;
-
/* end of cpustatus.c */