Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Compil smpi on win32.
[simgrid.git] / src / smpi / smpi_bench.c
index 195aa72..58c8c5a 100644 (file)
 #include "xbt/ex.h"
 #include "surf/surf.h"
 
+#ifndef WIN32
 #include <sys/mman.h>
+#endif
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h> // sqrt
 #include <unistd.h>
 #include <string.h>
 #include <stdio.h>
@@ -81,6 +84,7 @@ static size_t shm_size(int fd) {
   return (size_t)st.st_size;
 }
 
+#ifndef WIN32
 static void* shm_map(int fd, size_t size, shared_data_t* data) {
   void* mem;
   char loc[PTR_STRLEN];
@@ -91,6 +95,7 @@ static void* shm_map(int fd, size_t size, shared_data_t* data) {
       xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
     }
   }
+
   mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   if(mem == MAP_FAILED) {
     xbt_die("Could not map fd %d: %s", fd, strerror(errno));
@@ -106,52 +111,39 @@ static void* shm_map(int fd, size_t size, shared_data_t* data) {
   XBT_DEBUG("MMAP %zu to %p", size, mem);
   return mem;
 }
-
-typedef struct {
-  int count;
-  double sum;
-  double sum_pow2;
-  double mean;
-  double relstderr;
-  int iters;
-  double threshold;
-  int started;
-} local_data_t;
+#endif
 
 void smpi_bench_destroy(void)
 {
-  if (allocs) {
-    xbt_dict_free(&allocs);
-  }
-  if (samples) {
-    xbt_dict_free(&samples);
-  }
-  if(calls) {
-    xbt_dict_free(&calls);
-  }
+  xbt_dict_free(&allocs);
+  xbt_dict_free(&samples);
+  xbt_dict_free(&calls);
 }
 
-static void smpi_execute_flops(double flops)
-{
+void smpi_execute_flops(double flops) {
   smx_action_t action;
   smx_host_t host;
   host = SIMIX_host_self();
 
   XBT_DEBUG("Handle real computation time: %f flops", flops);
-  action = SIMIX_req_host_execute("computation", host, flops, 1);
+  action = simcall_host_execute("computation", host, flops, 1);
 #ifdef HAVE_TRACING
-  SIMIX_req_set_category (action, TRACE_internal_smpi_get_category());
+  simcall_set_category (action, TRACE_internal_smpi_get_category());
 #endif
-  SIMIX_req_host_execution_wait(action);
+  simcall_host_execution_wait(action);
 }
 
 static void smpi_execute(double duration)
 {
+  /* FIXME: a global variable would be less expensive to consult than a call to xbt_cfg_get_double() right on the critical path */
   if (duration >= xbt_cfg_get_double(_surf_cfg_set, "smpi/cpu_threshold")) {
     XBT_DEBUG("Sleep for %f to handle real computation time", duration);
     smpi_execute_flops(duration *
                        xbt_cfg_get_double(_surf_cfg_set,
                                           "smpi/running_power"));
+  } else {
+    XBT_DEBUG("Real computation took %f while option smpi/cpu_threshold is set to %f => ignore it",
+        duration, xbt_cfg_get_double(_surf_cfg_set, "smpi/cpu_threshold"));
   }
 }
 
@@ -171,53 +163,117 @@ void smpi_bench_end(void)
 
 unsigned int smpi_sleep(unsigned int secs)
 {
+  smpi_bench_end();
   smpi_execute((double) secs);
+  smpi_bench_begin();
   return secs;
 }
 
 int smpi_gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-  double now = SIMIX_get_clock();
-
+  double now;
+  smpi_bench_end();
+  now = SIMIX_get_clock();
   if (tv) {
-    tv->tv_sec = (time_t) now;
-    tv->tv_usec = (suseconds_t) (now * 1e6);
+    tv->tv_sec = (time_t)now;
+#ifdef WIN32
+    tv->tv_usec = (useconds_t)((now - tv->tv_sec) * 1e6);
+#else
+    tv->tv_usec = (suseconds_t)((now - tv->tv_sec) * 1e6);
+#endif
   }
+  smpi_bench_begin();
   return 0;
 }
 
-static char *sample_location(int global, const char *file, int line)
+extern double sg_maxmin_precision;
+unsigned long long smpi_rastro_resolution (void)
+{
+  smpi_bench_end();
+  double resolution = (1/sg_maxmin_precision);
+  smpi_bench_begin();
+  return (unsigned long long)resolution;
+}
+
+unsigned long long smpi_rastro_timestamp (void)
 {
+  smpi_bench_end();
+  double now = SIMIX_get_clock();
+
+  unsigned long long sec = (unsigned long long)now;
+  unsigned long long pre = (now - sec) * smpi_rastro_resolution();
+  smpi_bench_begin();
+  return (unsigned long long)sec * smpi_rastro_resolution() + pre;
+}
+
+/* ****************************** Functions related to the SMPI_SAMPLE_ macros ************************************/
+typedef struct {
+  int iters;        /* amount of requested iterations */
+  int count;        /* amount of iterations done so far */
+  double threshold; /* maximal stderr requested (if positive) */
+  double relstderr; /* observed stderr so far */
+  double mean;      /* mean of benched times, to be used if the block is disabled */
+  double sum;       /* sum of benched times (to compute the mean and stderr) */
+  double sum_pow2;  /* sum of the square of the benched times (to compute the stderr) */
+  int benching;     /* 1: we are benchmarking; 0: we have enough data, no bench anymore */
+} local_data_t;
+
+static char *sample_location(int global, const char *file, int line) {
   if (global) {
     return bprintf("%s:%d", file, line);
   } else {
     return bprintf("%s:%d:%d", file, line, smpi_process_index());
   }
 }
+static int sample_enough_benchs(local_data_t *data) {
+  int res = data->count >= data->iters;
+  if (data->threshold>0.0) {
+    if (data->count <2)
+      res = 0; // not enough data
+    if (data->relstderr > data->threshold)
+      res = 0; // stderr too high yet
+  }
+  XBT_DEBUG("%s (count:%d iter:%d stderr:%f thres:%f mean:%fs)",
+      (res?"enough benchs":"need more data"),
+      data->count, data->iters, data->relstderr, data->threshold, data->mean);
+  return res;
+}
 
-int smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
+void smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
 {
   char *loc = sample_location(global, file, line);
   local_data_t *data;
 
-  smpi_bench_end();     /* Take time from previous MPI call into account */
-  if (!samples) {
-    samples = xbt_dict_new();
-  }
+  smpi_bench_end();     /* Take time from previous, unrelated computation into account */
+  if (!samples)
+    samples = xbt_dict_new_homogeneous(free);
+
   data = xbt_dict_get_or_null(samples, loc);
   if (!data) {
+    xbt_assert(threshold>0 || iters>0,
+        "You should provide either a positive amount of iterations to bench, or a positive maximal stderr (or both)");
     data = (local_data_t *) xbt_new(local_data_t, 1);
     data->count = 0;
     data->sum = 0.0;
     data->sum_pow2 = 0.0;
     data->iters = iters;
     data->threshold = threshold;
-    data->started = 0;
-    xbt_dict_set(samples, loc, data, &free);
-    return 0;
+    data->benching = 1; // If we have no data, we need at least one
+    data->mean = 0;
+    xbt_dict_set(samples, loc, data, NULL);
+    XBT_DEBUG("XXXXX First time ever on benched nest %s.",loc);
+  } else {
+    if (data->iters != iters || data->threshold != threshold) {
+      XBT_ERROR("Asked to bench block %s with different settings %d, %f is not %d, %f. How did you manage to give two numbers at the same line??",
+          loc, data->iters, data->threshold, iters,threshold);
+      THROW_IMPOSSIBLE;
+    }
+
+    // if we already have some data, check whether sample_2 should get one more bench or whether it should emulate the computation instead
+    data->benching = !sample_enough_benchs(data);
+    XBT_DEBUG("XXXX Re-entering the benched nest %s. %s",loc, (data->benching?"more benching needed":"we have enough data, skip computes"));
   }
   free(loc);
-  return 1;
 }
 
 int smpi_sample_2(int global, const char *file, int line)
@@ -225,56 +281,66 @@ int smpi_sample_2(int global, const char *file, int line)
   char *loc = sample_location(global, file, line);
   local_data_t *data;
 
-  xbt_assert(samples, "You did something very inconsistent, didn't you?");
-  data = xbt_dict_get_or_null(samples, loc);
-  if (!data) {
-    xbt_assert(data, "Please, do thing in order");
-  }
-  if (!data->started) {
-    if ((data->iters > 0 && data->count >= data->iters)
-        || (data->count > 1 && data->threshold > 0.0 && data->relstderr <= data->threshold)) {
-      XBT_DEBUG("Perform some wait of %f", data->mean);
-      smpi_execute(data->mean);
-    } else {
-      data->started = 1;
-      data->count++;
-    }
+  xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
+  data = xbt_dict_get(samples, loc);
+  XBT_DEBUG("sample2 %s",loc);
+  free(loc);
+
+  if (data->benching==1) {
+    // we need to run a new bench
+    XBT_DEBUG("benchmarking: count:%d iter:%d stderr:%f thres:%f; mean:%f",
+        data->count, data->iters, data->relstderr, data->threshold, data->mean);
+    smpi_bench_begin();
+    return 1;
   } else {
-    data->started = 0;
+    // Enough data, no more bench (either we got enough data from previous visits to this benched nest, or we just ran one bench and need to bail out now that our job is done).
+    // Just sleep instead
+    XBT_DEBUG("No benchmark (either no need, or just ran one): count >= iter (%d >= %d) or stderr<thres (%f<=%f). apply the %fs delay instead",
+        data->count, data->iters, data->relstderr, data->threshold, data->mean);
+    smpi_execute(data->mean);
+
+    smpi_bench_begin(); // prepare to capture future, unrelated computations
+    return 0;
   }
-  free(loc);
-  smpi_bench_begin();
-  smpi_process_simulated_start();
-  return data->started;
 }
 
+
 void smpi_sample_3(int global, const char *file, int line)
 {
   char *loc = sample_location(global, file, line);
   local_data_t *data;
-  double sample, n;
 
-  xbt_assert(samples, "You did something very inconsistent, didn't you?");
-  data = xbt_dict_get_or_null(samples, loc);
-  smpi_bench_end();
-  if(data && data->started && data->count < data->iters) {
-    sample = smpi_process_simulated_elapsed();
-    data->sum += sample;
-    data->sum_pow2 += sample * sample;
-    n = (double)data->count;
-    data->mean = data->sum / n;
-    data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
-    XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
-           data->mean, data->relstderr, sample);
+  xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
+  data = xbt_dict_get(samples, loc);
+  XBT_DEBUG("sample3 %s",loc);
+
+  if (data->benching==0) {
+    THROW_IMPOSSIBLE;
   }
-  free(loc);
-}
 
-void smpi_sample_flops(double flops)
-{
-  smpi_execute_flops(flops);
+  // ok, benchmarking this loop is over
+  xbt_os_timer_stop(smpi_process_timer());
+
+  // update the stats
+  double sample, n;
+  data->count++;
+  sample = xbt_os_timer_elapsed(smpi_process_timer());
+  data->sum += sample;
+  data->sum_pow2 += sample * sample;
+  n = (double)data->count;
+  data->mean = data->sum / n;
+  data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
+  if (!sample_enough_benchs(data)) {
+    data->mean = sample; // Still in benching process; We want sample_2 to simulate the exact time of this loop occurrence before leaving, not the mean over the history
+  }
+  XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
+      data->mean, data->relstderr, sample);
+
+  // That's enough for now, prevent sample_2 to run the same code over and over
+  data->benching = 0;
 }
 
+#ifndef WIN32
 void *smpi_shared_malloc(size_t size, const char *file, int line)
 {
   char *loc = bprintf("%zu_%s_%d", (size_t)getpid(), file, line);
@@ -291,7 +357,7 @@ void *smpi_shared_malloc(size_t size, const char *file, int line)
     }
   }
   if (!allocs) {
-    allocs = xbt_dict_new();
+    allocs = xbt_dict_new_homogeneous(free);
   }
   data = xbt_dict_get_or_null(allocs, loc);
   if(!data) {
@@ -312,7 +378,7 @@ void *smpi_shared_malloc(size_t size, const char *file, int line)
     if(shm_unlink(loc) < 0) {
       XBT_WARN("Could not early unlink %s: %s", loc, strerror(errno));
     }
-    xbt_dict_set(allocs, loc, data, &free);
+    xbt_dict_set(allocs, loc, data, NULL);
     XBT_DEBUG("Mapping %s at %p through %d", loc, mem, fd);
   } else {
     mem = shm_map(data->fd, size, data);
@@ -321,7 +387,6 @@ void *smpi_shared_malloc(size_t size, const char *file, int line)
   XBT_DEBUG("Malloc %zu in %p (metadata at %p)", size, mem, data);
   return mem;
 }
-
 void smpi_shared_free(void *ptr)
 {
   char loc[PTR_STRLEN];
@@ -356,6 +421,7 @@ void smpi_shared_free(void *ptr)
     free(data->loc);
   }
 }
+#endif
 
 int smpi_shared_known_call(const char* func, const char* input) {
    char* loc = bprintf("%s:%s", func, input);
@@ -363,7 +429,7 @@ int smpi_shared_known_call(const char* func, const char* input) {
    int known;
 
    if(!calls) {
-      calls = xbt_dict_new();
+      calls = xbt_dict_new_homogeneous(NULL);
    }
    TRY {
       xbt_dict_get(calls, loc); /* Succeed or throw */
@@ -386,7 +452,7 @@ void* smpi_shared_get_call(const char* func, const char* input) {
    void* data;
 
    if(!calls) {
-      calls = xbt_dict_new();
+      calls = xbt_dict_new_homogeneous(NULL);
    }
    data = xbt_dict_get(calls, loc);
    free(loc);
@@ -397,7 +463,7 @@ void* smpi_shared_set_call(const char* func, const char* input, void* data) {
    char* loc = bprintf("%s:%s", func, input);
 
    if(!calls) {
-      calls = xbt_dict_new();
+      calls = xbt_dict_new_homogeneous(NULL);
    }
    xbt_dict_set(calls, loc, data, NULL);
    free(loc);