Logo AND Algorithmique Numérique Distribuée

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