Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Fix comm_determinism to work in split MCer/MCed
[simgrid.git] / src / smpi / smpi_bench.c
1 /* Copyright (c) 2007, 2009-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "internal_config.h"
8 #include "private.h"
9 #include "xbt/dict.h"
10 #include "xbt/sysdep.h"
11 #include "xbt/ex.h"
12 #include "xbt/hash.h"
13 #include "surf/surf.h"
14 #include "simgrid/sg_config.h"
15 #include "simgrid/modelchecker.h"
16
17 #ifndef WIN32
18 #include <sys/mman.h>
19 #endif
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <math.h> // sqrt
25 #include <unistd.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #ifndef MAP_ANONYMOUS
30 #define MAP_ANONYMOUS MAP_ANON
31 #endif
32
33 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_bench, smpi,
34                                 "Logging specific to SMPI (benchmarking)");
35
36 /* Shared allocations are handled through shared memory segments.
37  * Associated data and metadata are used as follows:
38  *
39  *                                                                    mmap #1
40  *    `allocs' dict                                                     ---- -.
41  *    ----------      shared_data_t               shared_metadata_t   / |  |  |
42  * .->| <name> | ---> -------------------- <--.   -----------------   | |  |  |
43  * |  ----------      | fd of <name>     |    |   | size of mmap  | --| |  |  |
44  * |                  | count (2)        |    |-- | data          |   \ |  |  |
45  * `----------------- | <name>           |    |   -----------------     ----  |
46  *                    --------------------    |   ^                           |
47  *                                            |   |                           |
48  *                                            |   |   `allocs_metadata' dict  |
49  *                                            |   |   ----------------------  |
50  *                                            |   `-- | <addr of mmap #1>  |<-'
51  *                                            |   .-- | <addr of mmap #2>  |<-.
52  *                                            |   |   ----------------------  |
53  *                                            |   |                           |
54  *                                            |   |                           |
55  *                                            |   |                           |
56  *                                            |   |                   mmap #2 |
57  *                                            |   v                     ---- -'
58  *                                            |   shared_metadata_t   / |  |
59  *                                            |   -----------------   | |  |
60  *                                            |   | size of mmap  | --| |  |
61  *                                            `-- | data          |   | |  |
62  *                                                -----------------   | |  |
63  *                                                                    \ |  |
64  *                                                                      ----
65  */
66
67 #define PTR_STRLEN (2 + 2 * sizeof(void*) + 1)
68
69 xbt_dict_t allocs = NULL;          /* Allocated on first use */
70 xbt_dict_t allocs_metadata = NULL; /* Allocated on first use */
71 xbt_dict_t samples = NULL;         /* Allocated on first use */
72 xbt_dict_t calls = NULL;           /* Allocated on first use */
73
74 double smpi_cpu_threshold;
75 double smpi_running_power;
76
77 int smpi_loaded_page = -1;
78 char* smpi_start_data_exe = NULL;
79 int smpi_size_data_exe = 0;
80 int smpi_privatize_global_variables;
81 double smpi_total_benched_time = 0;
82 smpi_privatisation_region_t smpi_privatisation_regions;
83
84 typedef struct {
85   int fd;
86   int count;
87   char* loc;
88 } shared_data_t;
89
90 typedef struct  {
91   size_t size;
92   shared_data_t* data;
93 } shared_metadata_t;
94
95 static size_t shm_size(int fd) {
96   struct stat st;
97
98   if(fstat(fd, &st) < 0) {
99     xbt_die("Could not stat fd %d: %s", fd, strerror(errno));
100   }
101   return (size_t)st.st_size;
102 }
103
104 #ifndef WIN32
105 static void* shm_map(int fd, size_t size, shared_data_t* data) {
106   void* mem;
107   char loc[PTR_STRLEN];
108   shared_metadata_t* meta;
109
110   if(size > shm_size(fd)) {
111     if(ftruncate(fd, (off_t)size) < 0) {
112       xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
113     }
114   }
115
116   mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
117   if(mem == MAP_FAILED) {
118     xbt_die("Could not map fd %d: %s", fd, strerror(errno));
119   }
120   if(!allocs_metadata) {
121     allocs_metadata = xbt_dict_new_homogeneous(xbt_free_f);
122   }
123   snprintf(loc, PTR_STRLEN, "%p", mem);
124   meta = xbt_new(shared_metadata_t, 1);
125   meta->size = size;
126   meta->data = data;
127   xbt_dict_set(allocs_metadata, loc, meta, NULL);
128   XBT_DEBUG("MMAP %zu to %p", size, mem);
129   return mem;
130 }
131 #endif
132
133 void smpi_bench_destroy(void)
134 {
135   xbt_dict_free(&allocs);
136   xbt_dict_free(&allocs_metadata);
137   xbt_dict_free(&samples);
138   xbt_dict_free(&calls);
139 }
140
141 XBT_PUBLIC(void) smpi_execute_flops_(double *flops);
142 void smpi_execute_flops_(double *flops)
143 {
144   smpi_execute_flops(*flops);
145 }
146
147 XBT_PUBLIC(void) smpi_execute_(double *duration);
148 void smpi_execute_(double *duration)
149 {
150   smpi_execute(*duration);
151 }
152
153 void smpi_execute_flops(double flops) {
154   smx_synchro_t action;
155   smx_host_t host;
156   host = SIMIX_host_self();
157   XBT_DEBUG("Handle real computation time: %f flops", flops);
158   action = simcall_host_execute("computation", host, flops, 1, 0, 0);
159 #ifdef HAVE_TRACING
160   simcall_set_category (action, TRACE_internal_smpi_get_category());
161 #endif
162   simcall_host_execution_wait(action);
163   smpi_switch_data_segment(smpi_process_index());
164 }
165
166 void smpi_execute(double duration)
167 {
168   if (duration >= smpi_cpu_threshold) {
169     XBT_DEBUG("Sleep for %g to handle real computation time", duration);
170     double flops = duration * smpi_running_power;
171 #ifdef HAVE_TRACING
172     int rank = smpi_process_index();
173     instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
174     extra->type=TRACING_COMPUTING;
175     extra->comp_size=flops;
176     TRACE_smpi_computing_in(rank, extra);
177 #endif
178     smpi_execute_flops(flops);
179
180 #ifdef HAVE_TRACING
181     TRACE_smpi_computing_out(rank);
182 #endif
183
184   } else {
185     XBT_DEBUG("Real computation took %g while option smpi/cpu_threshold is set to %g => ignore it",
186               duration, smpi_cpu_threshold);
187   }
188 }
189
190 void smpi_switch_data_segment(int dest);
191
192 void smpi_bench_begin(void)
193 {
194   smpi_switch_data_segment(smpi_process_index());
195
196   if (MC_is_active() || MC_record_replay_is_active())
197     return;
198
199   xbt_os_threadtimer_start(smpi_process_timer());
200 }
201
202 void smpi_bench_end(void)
203 {
204
205   if (MC_is_active() || MC_record_replay_is_active())
206     return;
207
208   xbt_os_timer_t timer = smpi_process_timer();
209   xbt_os_threadtimer_stop(timer);
210 //  smpi_switch_data_segment(smpi_process_count());
211   if (smpi_process_get_sampling()) {
212     XBT_CRITICAL("Cannot do recursive benchmarks.");
213     XBT_CRITICAL("Are you trying to make a call to MPI within a SMPI_SAMPLE_ block?");
214     xbt_backtrace_display_current();
215     xbt_die("Aborting.");
216   }
217   // Simulate the benchmarked computation unless disabled via command-line argument
218   if (sg_cfg_get_boolean("smpi/simulate_computation")) {
219     smpi_execute(xbt_os_timer_elapsed(timer));
220   }
221
222   smpi_total_benched_time += xbt_os_timer_elapsed(timer);
223 }
224
225 /* Private sleep function used by smpi_sleep() and smpi_usleep() */
226 static unsigned int private_sleep(double secs)
227 {
228   smpi_bench_end();
229
230   XBT_DEBUG("Sleep for: %lf secs", secs);
231   #ifdef HAVE_TRACING
232   int rank = smpi_comm_rank(MPI_COMM_WORLD);
233   instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
234   extra->type=TRACING_SLEEPING;
235   extra->sleep_duration=secs;
236   TRACE_smpi_sleeping_in(rank, extra);
237 #endif
238   simcall_process_sleep(secs);
239 #ifdef HAVE_TRACING
240   TRACE_smpi_sleeping_out(rank);
241 #endif
242
243   smpi_bench_begin();
244   return 0;
245 }
246
247 unsigned int smpi_sleep(unsigned int secs)
248 {
249   return private_sleep((double)secs);
250 }
251
252 int smpi_usleep(useconds_t usecs)
253 {
254   return (int)private_sleep((double)usecs / 1000000.0);
255 }
256
257
258 int smpi_gettimeofday(struct timeval *tv, void* tz)
259 {
260   double now;
261   smpi_bench_end();
262   now = SIMIX_get_clock();
263   if (tv) {
264     tv->tv_sec = (time_t)now;
265 #ifdef WIN32
266     tv->tv_usec = (useconds_t)((now - tv->tv_sec) * 1e6);
267 #else
268     tv->tv_usec = (suseconds_t)((now - tv->tv_sec) * 1e6);
269 #endif
270   }
271   smpi_bench_begin();
272   return 0;
273 }
274
275 extern double sg_surf_precision;
276 unsigned long long smpi_rastro_resolution (void)
277 {
278   smpi_bench_end();
279   double resolution = (1/sg_surf_precision);
280   smpi_bench_begin();
281   return (unsigned long long)resolution;
282 }
283
284 unsigned long long smpi_rastro_timestamp (void)
285 {
286   smpi_bench_end();
287   double now = SIMIX_get_clock();
288
289   unsigned long long sec = (unsigned long long)now;
290   unsigned long long pre = (now - sec) * smpi_rastro_resolution();
291   smpi_bench_begin();
292   return (unsigned long long)sec * smpi_rastro_resolution() + pre;
293 }
294
295 /* ****************************** Functions related to the SMPI_SAMPLE_ macros ************************************/
296 typedef struct {
297   double threshold; /* maximal stderr requested (if positive) */
298   double relstderr; /* observed stderr so far */
299   double mean;      /* mean of benched times, to be used if the block is disabled */
300   double sum;       /* sum of benched times (to compute the mean and stderr) */
301   double sum_pow2;  /* sum of the square of the benched times (to compute the stderr) */
302   int iters;        /* amount of requested iterations */
303   int count;        /* amount of iterations done so far */
304   int benching;     /* 1: we are benchmarking; 0: we have enough data, no bench anymore */
305 } local_data_t;
306
307 static char *sample_location(int global, const char *file, int line) {
308   if (global) {
309     return bprintf("%s:%d", file, line);
310   } else {
311     return bprintf("%s:%d:%d", file, line, smpi_process_index());
312   }
313 }
314 static int sample_enough_benchs(local_data_t *data) {
315   int res = data->count >= data->iters;
316   if (data->threshold>0.0) {
317     if (data->count <2)
318       res = 0; // not enough data
319     if (data->relstderr > data->threshold)
320       res = 0; // stderr too high yet
321   }
322   XBT_DEBUG("%s (count:%d iter:%d stderr:%f thres:%f mean:%fs)",
323       (res?"enough benchs":"need more data"),
324       data->count, data->iters, data->relstderr, data->threshold, data->mean);
325   return res;
326 }
327
328 void smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
329 {
330   char *loc = sample_location(global, file, line);
331   local_data_t *data;
332
333   smpi_bench_end();     /* Take time from previous, unrelated computation into account */
334   smpi_process_set_sampling(1);
335
336   if (!samples)
337     samples = xbt_dict_new_homogeneous(free);
338
339   data = xbt_dict_get_or_null(samples, loc);
340   if (!data) {
341     xbt_assert(threshold>0 || iters>0,
342         "You should provide either a positive amount of iterations to bench, or a positive maximal stderr (or both)");
343     data = (local_data_t *) xbt_new(local_data_t, 1);
344     data->count = 0;
345     data->sum = 0.0;
346     data->sum_pow2 = 0.0;
347     data->iters = iters;
348     data->threshold = threshold;
349     data->benching = 1; // If we have no data, we need at least one
350     data->mean = 0;
351     xbt_dict_set(samples, loc, data, NULL);
352     XBT_DEBUG("XXXXX First time ever on benched nest %s.",loc);
353   } else {
354     if (data->iters != iters || data->threshold != threshold) {
355       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??",
356           loc, data->iters, data->threshold, iters,threshold);
357       THROW_IMPOSSIBLE;
358     }
359
360     // if we already have some data, check whether sample_2 should get one more bench or whether it should emulate the computation instead
361     data->benching = !sample_enough_benchs(data);
362     XBT_DEBUG("XXXX Re-entering the benched nest %s. %s",loc, (data->benching?"more benching needed":"we have enough data, skip computes"));
363   }
364   xbt_free(loc);
365 }
366
367 int smpi_sample_2(int global, const char *file, int line)
368 {
369   char *loc = sample_location(global, file, line);
370   local_data_t *data;
371   int res;
372
373   xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
374   data = xbt_dict_get(samples, loc);
375   XBT_DEBUG("sample2 %s",loc);
376   xbt_free(loc);
377
378   if (data->benching==1) {
379     // we need to run a new bench
380     XBT_DEBUG("benchmarking: count:%d iter:%d stderr:%f thres:%f; mean:%f",
381         data->count, data->iters, data->relstderr, data->threshold, data->mean);
382     res = 1;
383   } else {
384     // 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).
385     // Just sleep instead
386     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",
387         data->count, data->iters, data->relstderr, data->threshold, data->mean);
388     smpi_execute(data->mean);
389     smpi_process_set_sampling(0);
390     res = 0; // prepare to capture future, unrelated computations
391   }
392   smpi_bench_begin();
393   return res;
394 }
395
396
397 void smpi_sample_3(int global, const char *file, int line)
398 {
399   char *loc = sample_location(global, file, line);
400   local_data_t *data;
401
402   xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
403   data = xbt_dict_get(samples, loc);
404   XBT_DEBUG("sample3 %s",loc);
405   xbt_free(loc);
406
407   if (data->benching==0) {
408     THROW_IMPOSSIBLE;
409   }
410
411   // ok, benchmarking this loop is over
412   xbt_os_threadtimer_stop(smpi_process_timer());
413
414   // update the stats
415   double sample, n;
416   data->count++;
417   sample = xbt_os_timer_elapsed(smpi_process_timer());
418   data->sum += sample;
419   data->sum_pow2 += sample * sample;
420   n = (double)data->count;
421   data->mean = data->sum / n;
422   data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
423   if (!sample_enough_benchs(data)) {
424     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
425   }
426   XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
427       data->mean, data->relstderr, sample);
428
429   // That's enough for now, prevent sample_2 to run the same code over and over
430   data->benching = 0;
431 }
432
433 #ifndef WIN32
434 static void smpi_shared_alloc_free(void *p)
435 {
436   shared_data_t *data = p;
437   xbt_free(data->loc);
438   xbt_free(data);
439 }
440
441 static char *smpi_shared_alloc_hash(char *loc)
442 {
443   char hash[42];
444   char s[7];
445   unsigned val;
446   int i, j;
447
448   xbt_sha(loc, hash);
449   hash[41] = '\0';
450   s[6] = '\0';
451   loc = xbt_realloc(loc, 30);
452   loc[0] = '/';
453   for (i = 0; i < 40; i += 6) { /* base64 encode */
454     memcpy(s, hash + i, 6);
455     val = strtoul(s, NULL, 16);
456     for (j = 0; j < 4; j++) {
457       unsigned char x = (val >> (18 - 3 * j)) & 0x3f;
458       loc[1 + 4 * i / 6 + j] =
459         "ABCDEFGHIJKLMNOPQRSTUVZXYZabcdefghijklmnopqrstuvzxyz0123456789-_"[x];
460     }
461   }
462   loc[29] = '\0';
463   return loc;
464 }
465
466 void *smpi_shared_malloc(size_t size, const char *file, int line)
467 {
468   void* mem;
469   if (sg_cfg_get_boolean("smpi/use_shared_malloc")){
470     char *loc = bprintf("%zu_%s_%d", (size_t)getpid(), file, line);
471     int fd;
472     shared_data_t *data;
473     loc = smpi_shared_alloc_hash(loc); /* hash loc, in order to have something
474                                         * not too long */
475     if (!allocs) {
476       allocs = xbt_dict_new_homogeneous(smpi_shared_alloc_free);
477     }
478     data = xbt_dict_get_or_null(allocs, loc);
479     if (!data) {
480       fd = shm_open(loc, O_RDWR | O_CREAT | O_EXCL,
481                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
482       if (fd < 0) {
483         switch(errno) {
484           case EEXIST:
485             xbt_die("Please cleanup /dev/shm/%s", loc);
486           default:
487             xbt_die("An unhandled error occured while opening %s. shm_open: %s", loc, strerror(errno));
488         }
489       }
490       data = xbt_new(shared_data_t, 1);
491       data->fd = fd;
492       data->count = 1;
493       data->loc = loc;
494       mem = shm_map(fd, size, data);
495       if (shm_unlink(loc) < 0) {
496         XBT_WARN("Could not early unlink %s. shm_unlink: %s", loc, strerror(errno));
497       }
498       xbt_dict_set(allocs, loc, data, NULL);
499       XBT_DEBUG("Mapping %s at %p through %d", loc, mem, fd);
500     } else {
501       xbt_free(loc);
502       mem = shm_map(data->fd, size, data);
503       data->count++;
504     }
505     XBT_DEBUG("Shared malloc %zu in %p (metadata at %p)", size, mem, data);
506   } else {
507     mem = xbt_malloc(size);
508     XBT_DEBUG("Classic malloc %zu in %p", size, mem);
509   }
510
511   return mem;
512 }
513 void smpi_shared_free(void *ptr)
514 {
515   char loc[PTR_STRLEN];
516   shared_metadata_t* meta;
517   shared_data_t* data;
518   if (sg_cfg_get_boolean("smpi/use_shared_malloc")){
519
520     if (!allocs) {
521       XBT_WARN("Cannot free: nothing was allocated");
522       return;
523     }
524     if(!allocs_metadata) {
525       XBT_WARN("Cannot free: no metadata was allocated");
526     }
527     snprintf(loc, PTR_STRLEN, "%p", ptr);
528     meta = (shared_metadata_t*)xbt_dict_get_or_null(allocs_metadata, loc);
529     if (!meta) {
530       XBT_WARN("Cannot free: %p was not shared-allocated by SMPI", ptr);
531       return;
532     }
533     data = meta->data;
534     if(!data) {
535       XBT_WARN("Cannot free: something is broken in the metadata link");
536       return;
537     }
538     if(munmap(ptr, meta->size) < 0) {
539       XBT_WARN("Unmapping of fd %d failed: %s", data->fd, strerror(errno));
540     }
541     data->count--;
542     XBT_DEBUG("Shared free - no removal - of %p, count = %d", ptr, data->count);
543     if (data->count <= 0) {
544       close(data->fd);
545       xbt_dict_remove(allocs, data->loc);
546       XBT_DEBUG("Shared free - with removal - of %p", ptr);
547     }
548   }else{
549     XBT_DEBUG("Classic free of %p", ptr);
550     xbt_free(ptr);
551   }
552 }
553 #endif
554
555 int smpi_shared_known_call(const char* func, const char* input)
556 {
557   char* loc = bprintf("%s:%s", func, input);
558   xbt_ex_t ex;
559   int known = 0;
560
561   if (!calls) {
562     calls = xbt_dict_new_homogeneous(NULL);
563   }
564   TRY {
565     xbt_dict_get(calls, loc); /* Succeed or throw */
566     known = 1;
567   }
568   TRY_CLEANUP {
569     xbt_free(loc);
570   }
571   CATCH(ex) {
572     if (ex.category != not_found_error)
573       RETHROW;
574     xbt_ex_free(ex);
575   }
576   return known;
577 }
578
579 void* smpi_shared_get_call(const char* func, const char* input) {
580    char* loc = bprintf("%s:%s", func, input);
581    void* data;
582
583    if(!calls) {
584       calls = xbt_dict_new_homogeneous(NULL);
585    }
586    data = xbt_dict_get(calls, loc);
587    free(loc);
588    return data;
589 }
590
591 void* smpi_shared_set_call(const char* func, const char* input, void* data) {
592    char* loc = bprintf("%s:%s", func, input);
593
594    if(!calls) {
595       calls = xbt_dict_new_homogeneous(NULL);
596    }
597    xbt_dict_set(calls, loc, data, NULL);
598    free(loc);
599    return data;
600 }
601
602
603
604
605 #define TOPAGE(addr) (void *)(((unsigned long)(addr) / xbt_pagesize) * xbt_pagesize)
606
607
608 /** Map a given SMPI privatization segment (make a SMPI process active)
609  */
610 void smpi_switch_data_segment(int dest){
611
612   if (smpi_loaded_page==dest)//no need to switch either
613    return;
614
615   // So the job:
616   smpi_really_switch_data_segment(dest);
617 }
618
619 /** Map a given SMPI privatization segment (make a SMPI process active)
620  *  even if SMPI thinks it is already active
621  *
622  *  When doing a state restoration, the state of the restored variables
623  *  might not be consistent with the state of the virtual memory.
624  *  In this case, we to change the data segment.
625  */
626 void smpi_really_switch_data_segment(int dest) {
627
628   if(smpi_size_data_exe == 0)//no need to switch
629     return;
630
631 #ifdef HAVE_MMAP
632   int i;
633   if(smpi_loaded_page==-1){//initial switch, do the copy from the real page here
634     for (i=0; i< SIMIX_process_count(); i++){
635       memcpy(smpi_privatisation_regions[i].address,
636         TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
637     }
638   }
639
640   // FIXME, cross-process support (mmap across process when necessary)
641   int current = smpi_privatisation_regions[dest].file_descriptor;
642   XBT_DEBUG("Switching data frame to the one of process %d", dest);
643   void* tmp = mmap (TOPAGE(smpi_start_data_exe), smpi_size_data_exe,
644     PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0);
645   if (tmp != TOPAGE(smpi_start_data_exe))
646     xbt_die("Couldn't map the new region");
647   smpi_loaded_page = dest;
648 #endif
649 }
650
651 int smpi_is_privatisation_file(char* file)
652 {
653   return strncmp("/dev/shm/my-buffer-", file, 19) == 0;
654 }
655
656 void smpi_get_executable_global_size(){
657   int size_bss_binary=0;
658   int size_data_binary=0;
659   FILE *fp;
660   char *line = NULL;            /* Temporal storage for each line that is readed */
661   ssize_t read;                 /* Number of bytes readed */
662   size_t n = 0;                 /* Amount of bytes to read by xbt_getline */
663
664   char *lfields[7];
665   int i, found = 0;
666
667   char *command = bprintf("objdump --section-headers %s", xbt_binary_name);
668
669   fp = popen(command, "r");
670
671   if(fp == NULL){
672     perror("popen failed");
673     xbt_abort();
674   }
675
676   while ((read = xbt_getline(&line, &n, fp)) != -1 && found != 2) {
677
678     if(n == 0)
679       continue;
680
681     /* Wipeout the new line character */
682     line[read - 1] = '\0';
683
684     lfields[0] = strtok(line, " ");
685
686     if(lfields[0] == NULL)
687       continue;
688
689     if(strcmp(lfields[0], "Sections:") == 0
690         || strcmp(lfields[0], "Idx") == 0
691         || strncmp(lfields[0], xbt_binary_name, strlen(xbt_binary_name)) == 0)
692       continue;
693
694     for (i = 1; i < 7 && lfields[i - 1] != NULL; i++) {
695       lfields[i] = strtok(NULL, " ");
696     }
697
698     /*
699      * we are looking for these fields
700     23 .data         02625a20  00000000006013e0  00000000006013e0  000013e0  2**5
701                      CONTENTS, ALLOC, LOAD, DATA
702     24 .bss          02625a40  0000000002c26e00  0000000002c26e00  02626e00  2**5
703                      ALLOC
704     */
705
706     if(i>=6){
707       if(strcmp(lfields[1], ".data") == 0){
708         size_data_binary = strtoul(lfields[2], NULL, 16);
709         smpi_start_data_exe = (char*) strtoul(lfields[4], NULL, 16);
710         found++;
711       }else if(strcmp(lfields[1], ".bss") == 0){
712         //the beginning of bss is not exactly the end of data if not aligned, grow bss reported size accordingly
713         //TODO : check if this is OK, as some segments may be inserted between them..
714         size_bss_binary = ((char*) strtoul(lfields[4], NULL, 16) - (smpi_start_data_exe + size_data_binary))
715                           + strtoul(lfields[2], NULL, 16);
716         found++;
717        }
718
719     }
720
721   }
722
723   smpi_size_data_exe = (unsigned long) smpi_start_data_exe
724     - (unsigned long) TOPAGE(smpi_start_data_exe)
725     + size_data_binary+size_bss_binary;
726   xbt_free(command);
727   xbt_free(line);
728   pclose(fp);
729
730 }
731
732 void smpi_initialize_global_memory_segments(){
733
734 #ifndef HAVE_MMAP
735   smpi_privatize_global_variables=0;
736   return;
737 #else
738
739   unsigned int i = 0;
740   smpi_get_executable_global_size();
741
742   XBT_DEBUG ("bss+data segment found : size %d starting at %p",
743     smpi_size_data_exe, smpi_start_data_exe );
744
745   if (smpi_size_data_exe == 0){//no need to switch
746     smpi_privatize_global_variables=0;
747     return;
748   }
749
750   smpi_privatisation_regions = (smpi_privatisation_region_t) malloc(
751     smpi_process_count() * sizeof(struct s_smpi_privatisation_region));
752
753   for (i=0; i< SIMIX_process_count(); i++){
754       //create SIMIX_process_count() mappings of this size with the same data inside
755       void *address = NULL;
756       char path[] = "/dev/shm/my-buffer-XXXXXX";
757       int status;
758
759       int file_descriptor= mkstemp (path);
760       if (file_descriptor < 0) {
761           if (errno==EMFILE) {
762                   xbt_die("Impossible to create temporary file for memory mapping: %s\n\
763 The open() system call failed with the EMFILE error code (too many files). \n\n\
764 This means that you reached the system limits concerning the amount of files per process. \
765 This is not a surprise if you are trying to virtualize many processes on top of SMPI. \
766 Don't panic -- you should simply increase your system limits and try again. \n\n\
767 First, check what your limits are:\n\
768   cat /proc/sys/fs/file-max # Gives you the system-wide limit\n\
769   ulimit -Hn                # Gives you the per process hard limit\n\
770   ulimit -Sn                # Gives you the per process soft limit\n\
771   cat /proc/self/limits     # Displays any per-process limitation (including the one given above)\n\n\
772 If one of these values is less than the amount of MPI processes that you try to run, then you got the explanation of this error. \
773 Ask the Internet about tutorials on how to increase the files limit such as: https://rtcamp.com/tutorials/linux/increase-open-files-limit/",
774              strerror(errno));
775           }
776         xbt_die("Impossible to create temporary file for memory mapping: %s",
777                         strerror(errno));
778       }
779
780       status = unlink (path);
781       if (status)
782         xbt_die("Impossible to unlink temporary file for memory mapping");
783
784       status = ftruncate(file_descriptor, smpi_size_data_exe);
785       if(status)
786         xbt_die("Impossible to set the size of the temporary file for memory mapping");
787
788       /* Ask for a free region */
789       address = mmap (NULL, smpi_size_data_exe, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0);
790       if (address == MAP_FAILED)
791         xbt_die("Couldn't find a free region for memory mapping");
792
793       //initialize the values
794       memcpy(address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
795
796       //store the address of the mapping for further switches
797       smpi_privatisation_regions[i].file_descriptor = file_descriptor;
798       smpi_privatisation_regions[i].address = address;
799   }
800
801 #endif
802
803 }
804
805 void smpi_destroy_global_memory_segments(){
806   if (smpi_size_data_exe == 0)//no need to switch
807     return;
808 #ifdef HAVE_MMAP
809   int i;
810   for (i=0; i< smpi_process_count(); i++){
811     if(munmap(smpi_privatisation_regions[i].address, smpi_size_data_exe) < 0) {
812       XBT_WARN("Unmapping of fd %d failed: %s",
813         smpi_privatisation_regions[i].file_descriptor, strerror(errno));
814     }
815     close(smpi_privatisation_regions[i].file_descriptor);
816   }
817   xbt_free(smpi_privatisation_regions);
818 #endif
819
820 }