Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
This should be a per process variable.
[simgrid.git] / src / smpi / smpi_bench.c
index 3608df6..3992750 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007, 2009, 2010. The SimGrid Team.
+/* Copyright (c) 2007, 2009-2013. The SimGrid Team.
  * All rights reserved.                                                     */
 
 /* This program is free software; you can redistribute it and/or modify it
 #include "private.h"
 #include "xbt/dict.h"
 #include "xbt/sysdep.h"
+#include "xbt/ex.h"
+#include "xbt/hash.h"
+#include "surf/surf.h"
+#include "simgrid/sg_config.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>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_bench, smpi,
                                 "Logging specific to SMPI (benchmarking)");
 
-xbt_dict_t allocs = NULL; /* Allocated on first use */
-xbt_dict_t samples = NULL; /* Allocated on first use */
+/* Shared allocations are handled through shared memory segments.
+ * Associated data and metadata are used as follows:
+ *
+ *                                                                    mmap #1
+ *    `allocs' dict                                                     ---- -.
+ *    ----------      shared_data_t               shared_metadata_t   / |  |  |
+ * .->| <name> | ---> -------------------- <--.   -----------------   | |  |  |
+ * |  ----------      | fd of <name>     |    |   | size of mmap  | --| |  |  |
+ * |                  | count (2)        |    |-- | data          |   \ |  |  |
+ * `----------------- | <name>           |    |   -----------------     ----  |
+ *                    --------------------    |   ^                           |
+ *                                            |   |                           |
+ *                                            |   |   `allocs_metadata' dict  |
+ *                                            |   |   ----------------------  |
+ *                                            |   `-- | <addr of mmap #1>  |<-'
+ *                                            |   .-- | <addr of mmap #2>  |<-.
+ *                                            |   |   ----------------------  |
+ *                                            |   |                           |
+ *                                            |   |                           |
+ *                                            |   |                           |
+ *                                            |   |                   mmap #2 |
+ *                                            |   v                     ---- -'
+ *                                            |   shared_metadata_t   / |  |
+ *                                            |   -----------------   | |  |
+ *                                            |   | size of mmap  | --| |  |
+ *                                            `-- | data          |   | |  |
+ *                                                -----------------   | |  |
+ *                                                                    \ |  |
+ *                                                                      ----
+ */
+
+#define PTR_STRLEN (2 + 2 * sizeof(void*) + 1)
+
+xbt_dict_t allocs = NULL;          /* Allocated on first use */
+xbt_dict_t allocs_metadata = NULL; /* Allocated on first use */
+xbt_dict_t samples = NULL;         /* Allocated on first use */
+xbt_dict_t calls = NULL;           /* Allocated on first use */
+__thread int smpi_current_rank = 0;      /* Updated after each MPI call */
+
+double smpi_cpu_threshold;
+double smpi_running_power;
 
 typedef struct {
-   int count;
-   char data[];
+  int fd;
+  int count;
+  char* loc;
 } shared_data_t;
 
-typedef struct {
-   double time;
-   int count;
-   int max;
-   int started;
-} local_data_t;
+typedef struct  {
+  size_t size;
+  shared_data_t* data;
+} shared_metadata_t;
 
-void smpi_bench_destroy(void) {
-   if (allocs) {
-      xbt_dict_free(&allocs);
-   }
-   if (samples) {
-      xbt_dict_free(&samples);
-   }
+static size_t shm_size(int fd) {
+  struct stat st;
+
+  if(fstat(fd, &st) < 0) {
+    xbt_die("Could not stat fd %d: %s", fd, strerror(errno));
+  }
+  return (size_t)st.st_size;
 }
 
-static void smpi_execute(double duration) {
-  smx_host_t host;
-  smx_action_t action;
-  smx_mutex_t mutex;
-  smx_cond_t cond;
-  e_surf_action_state_t state;
-
-  if(duration >= xbt_cfg_get_double(_surf_cfg_set, "smpi/cpu_threshold")) {
-    host = SIMIX_host_self();
-    mutex = SIMIX_mutex_init();
-    cond = SIMIX_cond_init();
-    DEBUG1("Sleep for %f to handle real computation time", duration);
-    duration *= xbt_cfg_get_double(_surf_cfg_set, "smpi/running_power");
-    action = SIMIX_action_execute(host, "computation", duration);
-    SIMIX_mutex_lock(mutex);
-    SIMIX_register_action_to_condition(action, cond);
-    for(state = SIMIX_action_get_state(action);
-        state == SURF_ACTION_READY ||
-        state == SURF_ACTION_RUNNING; state = SIMIX_action_get_state(action)) {
-      SIMIX_cond_wait(cond, mutex);
+#ifndef WIN32
+static void* shm_map(int fd, size_t size, shared_data_t* data) {
+  void* mem;
+  char loc[PTR_STRLEN];
+  shared_metadata_t* meta;
+
+  if(size > shm_size(fd)) {
+    if(ftruncate(fd, (off_t)size) < 0) {
+      xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
     }
-    SIMIX_unregister_action_to_condition(action, cond);
-    SIMIX_mutex_unlock(mutex);
-    SIMIX_action_destroy(action);
-    SIMIX_cond_destroy(cond);
-    SIMIX_mutex_destroy(mutex);
   }
+
+  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));
+  }
+  if(!allocs_metadata) {
+    allocs_metadata = xbt_dict_new_homogeneous(xbt_free);
+  }
+  snprintf(loc, PTR_STRLEN, "%p", mem);
+  meta = xbt_new(shared_metadata_t, 1);
+  meta->size = size;
+  meta->data = data;
+  xbt_dict_set(allocs_metadata, loc, meta, NULL);
+  XBT_DEBUG("MMAP %zu to %p", size, mem);
+  return mem;
 }
+#endif
 
-void smpi_bench_begin(int rank, const char* mpi_call) {
-  if(mpi_call && rank >= 0 && xbt_cfg_get_int(_surf_cfg_set, "smpi/log_events")) {
-    INFO3("SMPE: ts=%f rank=%d type=end et=%s", SIMIX_get_clock(), rank, mpi_call);
+void smpi_bench_destroy(void)
+{
+  xbt_dict_free(&allocs);
+  xbt_dict_free(&allocs_metadata);
+  xbt_dict_free(&samples);
+  xbt_dict_free(&calls);
+}
+
+void smpi_execute_flops(double flops) {
+  smx_action_t action;
+  smx_host_t host;
+  host = SIMIX_host_self();
+  XBT_DEBUG("Handle real computation time: %g flops", flops);
+  action = simcall_host_execute("computation", host, flops, 1);
+#ifdef HAVE_TRACING
+  simcall_set_category (action, TRACE_internal_smpi_get_category());
+#endif
+  simcall_host_execution_wait(action);
+}
+
+static void smpi_execute(double duration)
+{
+  if (duration >= smpi_cpu_threshold) {
+    XBT_DEBUG("Sleep for %g to handle real computation time", duration);
+    double flops = duration * smpi_running_power;
+#ifdef HAVE_TRACING
+    int rank = smpi_process_index();
+    instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
+    extra->type=TRACING_COMPUTING;
+    extra->comp_size=flops;
+    TRACE_smpi_computing_in(rank, extra);
+#endif
+    smpi_execute_flops(flops);
+
+#ifdef HAVE_TRACING
+    TRACE_smpi_computing_out(rank);
+#endif
+
+  } else {
+    XBT_DEBUG("Real computation took %g while option smpi/cpu_threshold is set to %g => ignore it",
+              duration, smpi_cpu_threshold);
   }
-  xbt_os_timer_start(smpi_process_timer());
 }
 
-void smpi_bench_end(int rank, const char* mpi_call) {
+void smpi_bench_begin(void)
+{
+  xbt_os_threadtimer_start(smpi_process_timer());
+  smpi_current_rank = smpi_process_index();
+}
+
+void smpi_bench_end(void)
+{
   xbt_os_timer_t timer = smpi_process_timer();
 
-  xbt_os_timer_stop(timer);
+  xbt_os_threadtimer_stop(timer);
   smpi_execute(xbt_os_timer_elapsed(timer));
-  if(mpi_call && rank >= 0 && xbt_cfg_get_int(_surf_cfg_set, "smpi/log_events")) {
-    INFO3("SMPE: ts=%f rank=%d type=begin et=%s", SIMIX_get_clock(), rank, mpi_call);
+}
+
+unsigned int smpi_sleep(unsigned int secs)
+{
+  smx_action_t action;
+
+  smpi_bench_end();
+
+  double flops = (double) secs*simcall_host_get_speed(SIMIX_host_self());
+  XBT_DEBUG("Sleep for: %f flops", flops);
+  action = simcall_host_execute("computation", SIMIX_host_self(), flops, 1);
+  #ifdef HAVE_TRACING
+    simcall_set_category (action, TRACE_internal_smpi_get_category());
+  #endif
+  simcall_host_execution_wait(action);
+
+  smpi_bench_begin();
+  return secs;
+}
+
+int smpi_gettimeofday(struct timeval *tv)
+{
+  double now;
+  smpi_bench_end();
+  now = SIMIX_get_clock();
+  if (tv) {
+    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;
 }
 
-unsigned int smpi_sleep(unsigned int secs) {
-   smpi_execute((double)secs);
+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;
 }
 
-int smpi_gettimeofday(struct timeval* tv, struct timezone* tz) {
-   double now = SIMIX_get_clock();
+unsigned long long smpi_rastro_timestamp (void)
+{
+  smpi_bench_end();
+  double now = SIMIX_get_clock();
 
-   if(tv) {
-      tv->tv_sec = (time_t)now;
-      tv->tv_usec = (suseconds_t)(now * 1e6);
-   }
-   return 0;
+  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;
 }
 
-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());
-   }
+/* ****************************** Functions related to the SMPI_SAMPLE_ macros ************************************/
+typedef struct {
+  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 iters;        /* amount of requested iterations */
+  int count;        /* amount of iterations done so far */
+  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;
 }
 
-void smpi_sample_1(int global, const char* file, int line, int max) {
-   char* loc = sample_location(global, file, line);
-   local_data_t* data;
+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(-1, NULL); /* Take time from previous MPI call into account */
-   if (!samples) {
-      samples = xbt_dict_new();
-   }
-   data = xbt_dict_get_or_null(samples, loc);
-   if (!data) {
-      data = (local_data_t*)xbt_new(local_data_t, 1);
-      data->time = 0.0;
-      data->count = 0;
-      data->max = max;
-      data->started = 0;
-      xbt_dict_set(samples, loc, data, &free);
-   }
-   free(loc);
+  smpi_bench_end();     /* Take time from previous, unrelated computation into account */
+  smpi_process_set_sampling(1);
+
+  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->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"));
+  }
+  xbt_free(loc);
 }
 
-int smpi_sample_2(int global, const char* file, int line) {
-   char* loc = sample_location(global, file, line);
-   local_data_t* data;
-   double* simu;
+int smpi_sample_2(int global, const char *file, int line)
+{
+  char *loc = sample_location(global, file, line);
+  local_data_t *data;
+  int res;
 
-   xbt_assert0(samples, "You did something very inconsistent, didn't you?");
-   data = xbt_dict_get_or_null(samples, loc);
-   if (!data) {
-      xbt_assert0(data, "Please, do thing in order");
-   }
-   if (!data->started) {
-      if (data->count < data->max) {
-         data->started = 1;
-         data->count++;
-      } else {
-         DEBUG1("Perform some wait of %f", data->time / (double)data->count);
-         smpi_execute(data->time / (double)data->count);
-      }
-   } else {
-      data->started = 0;
-   }
-   free(loc);
-   smpi_bench_begin(-1, NULL);
-   smpi_process_simulated_start();
-   return data->started;
+  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);
+  xbt_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);
+    res = 1;
+  } else {
+    // 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_process_set_sampling(0);
+    res = 0; // prepare to capture future, unrelated computations
+  }
+  smpi_bench_begin();
+  return res;
 }
 
-void smpi_sample_3(int global, const char* file, int line) {
-   char* loc = sample_location(global, file, line);
-   local_data_t* data;
-   double spent;
 
-   xbt_assert0(samples, "You did something very inconsistent, didn't you?");
-   data = xbt_dict_get_or_null(samples, loc);
-   if (!data || !data->started || data->count >= data->max) {
-      xbt_assert0(data, "Please, do thing in order");
-   }
-   smpi_bench_end(-1, NULL);
-   data->time += smpi_process_simulated_elapsed();
-   DEBUG2("Average mean after %d steps is %f", data->count, data->time / (double)data->count);
+void smpi_sample_3(int global, const char *file, int line)
+{
+  char *loc = sample_location(global, file, line);
+  local_data_t *data;
+
+  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);
+  xbt_free(loc);
+
+  if (data->benching==0) {
+    THROW_IMPOSSIBLE;
+  }
+
+  // ok, benchmarking this loop is over
+  xbt_os_threadtimer_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;
 }
 
-void* smpi_shared_malloc(size_t size, const char* file, int line) {
-   char* loc = bprintf("%s:%d:%zu", file, line, size);
-   shared_data_t* data;
+#ifndef WIN32
+static void smpi_shared_alloc_free(void *p)
+{
+  shared_data_t *data = p;
+  xbt_free(data->loc);
+  xbt_free(data);
+}
 
-   if (!allocs) {
-      allocs = xbt_dict_new();
-   }
-   data = xbt_dict_get_or_null(allocs, loc);
-   if (!data) {
-      data = (shared_data_t*)xbt_malloc0(sizeof(int) + size);
+static char *smpi_shared_alloc_hash(char *loc)
+{
+  char hash[42];
+  char s[7];
+  unsigned val;
+  int i, j;
+
+  xbt_sha(loc, hash);
+  hash[41] = '\0';
+  s[6] = '\0';
+  loc = xbt_realloc(loc, 30);
+  loc[0] = '/';
+  for (i = 0; i < 40; i += 6) { /* base64 encode */
+    memcpy(s, hash + i, 6);
+    val = strtoul(s, NULL, 16);
+    for (j = 0; j < 4; j++) {
+      unsigned char x = (val >> (18 - 3 * j)) & 0x3f;
+      loc[1 + 4 * i / 6 + j] =
+        "ABCDEFGHIJKLMNOPQRSTUVZXYZabcdefghijklmnopqrstuvzxyz0123456789-_"[x];
+    }
+  }
+  loc[29] = '\0';
+  return loc;
+}
+
+void *smpi_shared_malloc(size_t size, const char *file, int line)
+{
+  void* mem;
+  if (sg_cfg_get_boolean("smpi/use_shared_malloc")){
+    char *loc = bprintf("%zu_%s_%d", (size_t)getpid(), file, line);
+    int fd;
+    shared_data_t *data;
+    loc = smpi_shared_alloc_hash(loc); /* hash loc, in order to have something
+                                        * not too long */
+    if (!allocs) {
+      allocs = xbt_dict_new_homogeneous(smpi_shared_alloc_free);
+    }
+    data = xbt_dict_get_or_null(allocs, loc);
+    if (!data) {
+      fd = shm_open(loc, O_RDWR | O_CREAT | O_EXCL,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+      if (fd < 0) {
+        switch(errno) {
+          case EEXIST:
+            xbt_die("Please cleanup /dev/shm/%s", loc);
+          default:
+            xbt_die("An unhandled error occured while opening %s. shm_open: %s", loc, strerror(errno));
+        }
+      }
+      data = xbt_new(shared_data_t, 1);
+      data->fd = fd;
       data->count = 1;
-      xbt_dict_set(allocs, loc, data, &free);
-   } else {
+      data->loc = loc;
+      mem = shm_map(fd, size, data);
+      if (shm_unlink(loc) < 0) {
+        XBT_WARN("Could not early unlink %s. shm_unlink: %s", loc, strerror(errno));
+      }
+      xbt_dict_set(allocs, loc, data, NULL);
+      XBT_DEBUG("Mapping %s at %p through %d", loc, mem, fd);
+    } else {
+      xbt_free(loc);
+      mem = shm_map(data->fd, size, data);
       data->count++;
+    }
+    XBT_DEBUG("Shared malloc %zu in %p (metadata at %p)", size, mem, data);
+  } else {
+    mem = xbt_malloc(size);
+    XBT_DEBUG("Classic malloc %zu in %p", size, mem);
+  }
+
+  return mem;
+}
+void smpi_shared_free(void *ptr)
+{
+  char loc[PTR_STRLEN];
+  shared_metadata_t* meta;
+  shared_data_t* data;
+  if (sg_cfg_get_boolean("smpi/use_shared_malloc")){
+  
+    if (!allocs) {
+      XBT_WARN("Cannot free: nothing was allocated");
+      return;
+    }
+    if(!allocs_metadata) {
+      XBT_WARN("Cannot free: no metadata was allocated");
+    }
+    snprintf(loc, PTR_STRLEN, "%p", ptr);
+    meta = (shared_metadata_t*)xbt_dict_get_or_null(allocs_metadata, loc);
+    if (!meta) {
+      XBT_WARN("Cannot free: %p was not shared-allocated by SMPI", ptr);
+      return;
+    }
+    data = meta->data;
+    if(!data) {
+      XBT_WARN("Cannot free: something is broken in the metadata link");
+      return;
+    }
+    if(munmap(ptr, meta->size) < 0) {
+      XBT_WARN("Unmapping of fd %d failed: %s", data->fd, strerror(errno));
+    }
+    data->count--;
+    XBT_DEBUG("Shared free - no removal - of %p, count = %d", ptr, data->count);
+    if (data->count <= 0) {
+      close(data->fd);
+      xbt_dict_remove(allocs, data->loc);
+      XBT_DEBUG("Shared free - with removal - of %p", ptr);
+    }
+  }else{
+    XBT_DEBUG("Classic free of %p", ptr);
+    xbt_free(ptr);
+  }
+}
+#endif
+
+int smpi_shared_known_call(const char* func, const char* input) {
+   char* loc = bprintf("%s:%s", func, input);
+   xbt_ex_t ex;
+   int known;
+
+   if(!calls) {
+      calls = xbt_dict_new_homogeneous(NULL);
+   }
+   TRY {
+      xbt_dict_get(calls, loc); /* Succeed or throw */
+      known = 1;
+   }
+   CATCH(ex) {
+      if(ex.category == not_found_error) {
+         known = 0;
+         xbt_ex_free(ex);
+      } else {
+         RETHROW;
+      }
    }
    free(loc);
-   return data->data;
+   return known;
 }
 
-void smpi_shared_free(void* ptr) {
-   shared_data_t* data = (shared_data_t*)((int*)ptr - 1);
-   char* loc;
+void* smpi_shared_get_call(const char* func, const char* input) {
+   char* loc = bprintf("%s:%s", func, input);
+   void* data;
 
-   if (!allocs) {
-      WARN0("Cannot free: nothing was allocated");
-      return;
+   if(!calls) {
+      calls = xbt_dict_new_homogeneous(NULL);
    }
-   loc = xbt_dict_get_key(allocs, data);
-   if (!loc) {
-      WARN1("Cannot free: %p was not shared-allocated by SMPI", ptr);
-      return;
-   }
-   data->count--;
-   if (data->count <= 0) {
-      xbt_dict_remove(allocs, loc);
+   data = xbt_dict_get(calls, loc);
+   free(loc);
+   return data;
+}
+
+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_homogeneous(NULL);
    }
+   xbt_dict_set(calls, loc, data, NULL);
+   free(loc);
+   return data;
 }