Logo AND Algorithmique Numérique Distribuée

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