Logo AND Algorithmique Numérique Distribuée

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