1 /* Copyright (c) 2007, 2009-2015. The SimGrid Team.
2 * All rights reserved. */
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. */
9 #include <unordered_map>
12 #include "src/internal_config.h"
14 #include "private.hpp"
17 #include "xbt/sysdep.h"
19 #include "surf/surf.h"
20 #include "simgrid/sg_config.h"
21 #include "simgrid/modelchecker.h"
22 #include "src/mc/mc_replay.h"
24 #include <sys/types.h>
31 #include <math.h> // sqrt
41 #define MAP_ANONYMOUS MAP_ANON
44 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_bench, smpi, "Logging specific to SMPI (benchmarking)");
46 /* Shared allocations are handled through shared memory segments.
47 * Associated data and metadata are used as follows:
50 * `allocs' dict ---- -.
51 * ---------- shared_data_t shared_metadata_t / | | |
52 * .->| <name> | ---> -------------------- <--. ----------------- | | | |
53 * | ---------- | fd of <name> | | | size of mmap | --| | | |
54 * | | count (2) | |-- | data | \ | | |
55 * `----------------- | <name> | | ----------------- ---- |
56 * -------------------- | ^ |
58 * | | `allocs_metadata' dict |
59 * | | ---------------------- |
60 * | `-- | <addr of mmap #1> |<-'
61 * | .-- | <addr of mmap #2> |<-.
62 * | | ---------------------- |
68 * | shared_metadata_t / | |
69 * | ----------------- | | |
70 * | | size of mmap | --| | |
72 * ----------------- | | |
77 #define PTR_STRLEN (2 + 2 * sizeof(void*) + 1)
79 xbt_dict_t samples = nullptr; /* Allocated on first use */
80 xbt_dict_t calls = nullptr; /* Allocated on first use */
82 double smpi_cpu_threshold;
83 double smpi_host_speed;
85 int smpi_loaded_page = -1;
86 char* smpi_start_data_exe = nullptr;
87 int smpi_size_data_exe = 0;
88 bool smpi_privatize_global_variables;
89 double smpi_total_benched_time = 0;
90 smpi_privatisation_region_t smpi_privatisation_regions;
94 /** Some location in the source code
96 * This information is used by SMPI_SHARED_MALLOC to allocate some shared memory for all simulated processes.
98 class smpi_source_location {
100 smpi_source_location(const char* filename, int line)
101 : filename(xbt_strdup(filename)), filename_length(strlen(filename)), line(line) {}
103 /** Pointer to a static string containing the file name */
104 char* filename = nullptr;
105 int filename_length = 0;
108 bool operator==(smpi_source_location const& that) const
110 return filename_length == that.filename_length
112 && std::memcmp(filename, that.filename, filename_length) == 0;
114 bool operator!=(smpi_source_location const& that) const
116 return !(*this == that);
125 class hash<smpi_source_location> {
127 typedef smpi_source_location argument_type;
128 typedef std::size_t result_type;
129 result_type operator()(smpi_source_location const& loc) const
131 return xbt_str_hash_ext(loc.filename, loc.filename_length)
132 ^ xbt_str_hash_ext((const char*) &loc.line, sizeof(loc.line));
145 std::unordered_map<smpi_source_location, shared_data_t> allocs;
146 typedef std::unordered_map<smpi_source_location, shared_data_t>::value_type shared_data_key_type;
150 shared_data_key_type* data;
153 std::unordered_map<void*, shared_metadata_t> allocs_metadata;
157 static size_t shm_size(int fd) {
160 if(fstat(fd, &st) < 0) {
161 xbt_die("Could not stat fd %d: %s", fd, strerror(errno));
163 return static_cast<size_t>(st.st_size);
167 static void* shm_map(int fd, size_t size, shared_data_key_type* data) {
169 char loc[PTR_STRLEN];
170 shared_metadata_t meta;
172 if(size > shm_size(fd) && (ftruncate(fd, static_cast<off_t>(size)) < 0)) {
173 xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
176 mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
177 if(mem == MAP_FAILED) {
178 xbt_die("Could not map fd %d with size %zu: %s.\n If you are running a lot of processes, you may be exceeding the amount of mappings allowed per process. \n On linux systems, this value can be set by using sudo sysctl -w vm.max_map_count=newvalue .\n Default value is 65536", fd, size, strerror(errno));
180 snprintf(loc, PTR_STRLEN, "%p", mem);
183 allocs_metadata[mem] = meta;
184 XBT_DEBUG("MMAP %zu to %p", size, mem);
189 void smpi_bench_destroy()
192 allocs_metadata.clear();
193 xbt_dict_free(&samples);
194 xbt_dict_free(&calls);
197 extern "C" XBT_PUBLIC(void) smpi_execute_flops_(double *flops);
198 void smpi_execute_flops_(double *flops)
200 smpi_execute_flops(*flops);
203 extern "C" XBT_PUBLIC(void) smpi_execute_(double *duration);
204 void smpi_execute_(double *duration)
206 smpi_execute(*duration);
209 void smpi_execute_flops(double flops) {
210 XBT_DEBUG("Handle real computation time: %f flops", flops);
211 smx_activity_t action = simcall_execution_start("computation", flops, 1, 0);
212 simcall_set_category (action, TRACE_internal_smpi_get_category());
213 simcall_execution_wait(action);
214 smpi_switch_data_segment(smpi_process_index());
217 void smpi_execute(double duration)
219 if (duration >= smpi_cpu_threshold) {
220 XBT_DEBUG("Sleep for %g to handle real computation time", duration);
221 double flops = duration * smpi_host_speed;
222 int rank = smpi_process_index();
223 instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
224 extra->type=TRACING_COMPUTING;
225 extra->comp_size=flops;
226 TRACE_smpi_computing_in(rank, extra);
228 smpi_execute_flops(flops);
230 TRACE_smpi_computing_out(rank);
233 XBT_DEBUG("Real computation took %g while option smpi/cpu_threshold is set to %g => ignore it",
234 duration, smpi_cpu_threshold);
238 void smpi_bench_begin()
240 if (smpi_privatize_global_variables) {
241 smpi_switch_data_segment(smpi_process_index());
244 if (MC_is_active() || MC_record_replay_is_active())
248 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') {
249 int event_set = smpi_process_papi_event_set();
250 // PAPI_start sets everything to 0! See man(3) PAPI_start
251 if (PAPI_LOW_LEVEL_INITED == PAPI_is_initialized()) {
252 if (PAPI_start(event_set) != PAPI_OK) {
253 // TODO This needs some proper handling.
254 XBT_CRITICAL("Could not start PAPI counters.\n");
260 xbt_os_threadtimer_start(smpi_process_timer());
263 void smpi_bench_end()
265 if (MC_is_active() || MC_record_replay_is_active())
269 xbt_os_timer_t timer = smpi_process_timer();
270 xbt_os_threadtimer_stop(timer);
274 * An MPI function has been called and now is the right time to update
275 * our PAPI counters for this process.
277 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') {
278 papi_counter_t& counter_data = smpi_process_papi_counters();
279 int event_set = smpi_process_papi_event_set();
280 std::vector<long long> event_values = std::vector<long long>(counter_data.size());
282 if (PAPI_stop(event_set, &event_values[0]) != PAPI_OK) { // Error
283 XBT_CRITICAL("Could not stop PAPI counters.\n");
286 for (unsigned int i = 0; i < counter_data.size(); i++) {
287 counter_data[i].second += event_values[i];
288 // XBT_DEBUG("[%i] PAPI: Counter %s: Value is now %lli (got increment by %lli\n", smpi_process_index(),
289 // counter_data[i].first.c_str(), counter_data[i].second, event_values[i]);
295 if (smpi_process_get_sampling()) {
296 XBT_CRITICAL("Cannot do recursive benchmarks.");
297 XBT_CRITICAL("Are you trying to make a call to MPI within a SMPI_SAMPLE_ block?");
298 xbt_backtrace_display_current();
299 xbt_die("Aborting.");
302 if (xbt_cfg_get_string("smpi/comp-adjustment-file")[0] != '\0') { // Maybe we need to artificially speed up or slow
303 // down our computation based on our statistical analysis.
305 smpi_trace_call_location_t* loc = smpi_process_get_call_location();
306 std::string key = loc->get_composed_key();
307 std::unordered_map<std::string, double>::const_iterator it = location2speedup.find(key);
308 if (it != location2speedup.end()) {
309 speedup = it->second;
313 // Simulate the benchmarked computation unless disabled via command-line argument
314 if (xbt_cfg_get_boolean("smpi/simulate-computation")) {
315 smpi_execute(xbt_os_timer_elapsed(timer)/speedup);
319 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0' && TRACE_smpi_is_enabled()) {
320 char container_name[INSTR_DEFAULT_STR_SIZE];
321 smpi_container(smpi_process_index(), container_name, INSTR_DEFAULT_STR_SIZE);
322 container_t container = PJ_container_get(container_name);
323 papi_counter_t& counter_data = smpi_process_papi_counters();
325 for (auto& pair : counter_data) {
326 new_pajeSetVariable(surf_get_clock(), container,
327 PJ_type_get(/* countername */ pair.first.c_str(), container->type), pair.second);
332 smpi_total_benched_time += xbt_os_timer_elapsed(timer);
335 /* Private sleep function used by smpi_sleep() and smpi_usleep() */
336 static unsigned int private_sleep(double secs)
340 XBT_DEBUG("Sleep for: %lf secs", secs);
341 int rank = smpi_comm_rank(MPI_COMM_WORLD);
342 instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
343 extra->type=TRACING_SLEEPING;
344 extra->sleep_duration=secs;
345 TRACE_smpi_sleeping_in(rank, extra);
347 simcall_process_sleep(secs);
349 TRACE_smpi_sleeping_out(rank);
355 unsigned int smpi_sleep(unsigned int secs)
357 return private_sleep(static_cast<double>(secs));
360 int smpi_usleep(useconds_t usecs)
362 return static_cast<int>(private_sleep(static_cast<double>(usecs) / 1000000.0));
365 #if _POSIX_TIMERS > 0
366 int smpi_nanosleep(const struct timespec *tp, struct timespec * t)
368 return static_cast<int>(private_sleep(static_cast<double>(tp->tv_sec + tp->tv_nsec / 1000000000.0)));
372 int smpi_gettimeofday(struct timeval *tv, void* tz)
376 now = SIMIX_get_clock();
378 tv->tv_sec = static_cast<time_t>(now);
380 tv->tv_usec = static_cast<useconds_t>((now - tv->tv_sec) * 1e6);
382 tv->tv_usec = static_cast<suseconds_t>((now - tv->tv_sec) * 1e6);
389 #if _POSIX_TIMERS > 0
390 int smpi_clock_gettime(clockid_t clk_id, struct timespec *tp)
392 //there is only one time in SMPI, so clk_id is ignored.
395 now = SIMIX_get_clock();
397 tp->tv_sec = static_cast<time_t>(now);
398 tp->tv_nsec = static_cast<long int>((now - tp->tv_sec) * 1e9);
405 extern double sg_surf_precision;
406 unsigned long long smpi_rastro_resolution ()
409 double resolution = (1/sg_surf_precision);
411 return static_cast<unsigned long long>(resolution);
414 unsigned long long smpi_rastro_timestamp ()
417 double now = SIMIX_get_clock();
419 unsigned long long sec = (unsigned long long)now;
420 unsigned long long pre = (now - sec) * smpi_rastro_resolution();
422 return static_cast<unsigned long long>(sec) * smpi_rastro_resolution() + pre;
425 /* ****************************** Functions related to the SMPI_SAMPLE_ macros ************************************/
427 double threshold; /* maximal stderr requested (if positive) */
428 double relstderr; /* observed stderr so far */
429 double mean; /* mean of benched times, to be used if the block is disabled */
430 double sum; /* sum of benched times (to compute the mean and stderr) */
431 double sum_pow2; /* sum of the square of the benched times (to compute the stderr) */
432 int iters; /* amount of requested iterations */
433 int count; /* amount of iterations done so far */
434 int benching; /* 1: we are benchmarking; 0: we have enough data, no bench anymore */
437 static char *sample_location(int global, const char *file, int line) {
439 return bprintf("%s:%d", file, line);
441 return bprintf("%s:%d:%d", file, line, smpi_process_index());
445 static int sample_enough_benchs(local_data_t *data) {
446 int res = data->count >= data->iters;
447 if (data->threshold>0.0) {
449 res = 0; // not enough data
450 if (data->relstderr > data->threshold)
451 res = 0; // stderr too high yet
453 XBT_DEBUG("%s (count:%d iter:%d stderr:%f thres:%f mean:%fs)",
454 (res?"enough benchs":"need more data"), data->count, data->iters, data->relstderr, data->threshold, data->mean);
458 void smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
460 char *loc = sample_location(global, file, line);
463 smpi_bench_end(); /* Take time from previous, unrelated computation into account */
464 smpi_process_set_sampling(1);
466 if (samples==nullptr)
467 samples = xbt_dict_new_homogeneous(free);
469 data = static_cast<local_data_t *>(xbt_dict_get_or_null(samples, loc));
471 xbt_assert(threshold>0 || iters>0,
472 "You should provide either a positive amount of iterations to bench, or a positive maximal stderr (or both)");
473 data = static_cast<local_data_t *>( xbt_new(local_data_t, 1));
476 data->sum_pow2 = 0.0;
478 data->threshold = threshold;
479 data->benching = 1; // If we have no data, we need at least one
481 xbt_dict_set(samples, loc, data, nullptr);
482 XBT_DEBUG("XXXXX First time ever on benched nest %s.",loc);
484 if (data->iters != iters || data->threshold != threshold) {
485 XBT_ERROR("Asked to bench block %s with different settings %d, %f is not %d, %f. "
486 "How did you manage to give two numbers at the same line??",
487 loc, data->iters, data->threshold, iters,threshold);
491 // if we already have some data, check whether sample_2 should get one more bench or whether it should emulate
492 // the computation instead
493 data->benching = (sample_enough_benchs(data) == 0);
494 XBT_DEBUG("XXXX Re-entering the benched nest %s. %s",loc,
495 (data->benching?"more benching needed":"we have enough data, skip computes"));
500 int smpi_sample_2(int global, const char *file, int line)
502 char *loc = sample_location(global, file, line);
506 xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
507 data = static_cast<local_data_t *>(xbt_dict_get(samples, loc));
508 XBT_DEBUG("sample2 %s",loc);
511 if (data->benching==1) {
512 // we need to run a new bench
513 XBT_DEBUG("benchmarking: count:%d iter:%d stderr:%f thres:%f; mean:%f",
514 data->count, data->iters, data->relstderr, data->threshold, data->mean);
517 // Enough data, no more bench (either we got enough data from previous visits to this benched nest, or we just
518 //ran one bench and need to bail out now that our job is done). Just sleep instead
519 XBT_DEBUG("No benchmark (either no need, or just ran one): count >= iter (%d >= %d) or stderr<thres (%f<=%f)."
520 " apply the %fs delay instead", data->count, data->iters, data->relstderr, data->threshold, data->mean);
521 smpi_execute(data->mean);
522 smpi_process_set_sampling(0);
523 res = 0; // prepare to capture future, unrelated computations
529 void smpi_sample_3(int global, const char *file, int line)
531 char *loc = sample_location(global, file, line);
534 xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
535 data = static_cast<local_data_t *>(xbt_dict_get(samples, loc));
536 XBT_DEBUG("sample3 %s",loc);
539 if (data->benching==0) {
543 // ok, benchmarking this loop is over
544 xbt_os_threadtimer_stop(smpi_process_timer());
549 sample = xbt_os_timer_elapsed(smpi_process_timer());
551 data->sum_pow2 += sample * sample;
552 n = static_cast<double>(data->count);
553 data->mean = data->sum / n;
554 data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
555 if (sample_enough_benchs(data)==0) {
556 data->mean = sample; // Still in benching process; We want sample_2 to simulate the exact time of this loop
557 // occurrence before leaving, not the mean over the history
559 XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
560 data->mean, data->relstderr, sample);
562 // That's enough for now, prevent sample_2 to run the same code over and over
568 void *smpi_shared_malloc(size_t size, const char *file, int line)
571 if (size > 0 && xbt_cfg_get_boolean("smpi/use-shared-malloc")){
573 smpi_source_location loc(file, line);
574 auto res = allocs.insert(std::make_pair(loc, shared_data_t()));
575 auto data = res.first;
577 // The insertion did not take place.
578 // Generate a shared memory name from the address of the shared_data:
579 char shmname[32]; // cannot be longer than PSHMNAMLEN = 31 on Mac OS X (shm_open raises ENAMETOOLONG otherwise)
580 snprintf(shmname, 31, "/shmalloc%p", &*data);
581 fd = shm_open(shmname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
584 xbt_die("Please cleanup /dev/shm/%s", shmname);
586 xbt_die("An unhandled error occurred while opening %s. shm_open: %s", shmname, strerror(errno));
588 data->second.fd = fd;
589 data->second.count = 1;
590 mem = shm_map(fd, size, &*data);
591 if (shm_unlink(shmname) < 0) {
592 XBT_WARN("Could not early unlink %s. shm_unlink: %s", shmname, strerror(errno));
594 XBT_DEBUG("Mapping %s at %p through %d", shmname, mem, fd);
596 mem = shm_map(data->second.fd, size, &*data);
597 data->second.count++;
599 XBT_DEBUG("Shared malloc %zu in %p (metadata at %p)", size, mem, &*data);
601 mem = xbt_malloc(size);
602 XBT_DEBUG("Classic malloc %zu in %p", size, mem);
608 void smpi_shared_free(void *ptr)
610 char loc[PTR_STRLEN];
612 if (xbt_cfg_get_boolean("smpi/use-shared-malloc")){
613 snprintf(loc, PTR_STRLEN, "%p", ptr);
614 auto meta = allocs_metadata.find(ptr);
615 if (meta == allocs_metadata.end()) {
616 XBT_WARN("Cannot free: %p was not shared-allocated by SMPI - maybe its size was 0?", ptr);
619 shared_data_t* data = &meta->second.data->second;
620 if (munmap(ptr, meta->second.size) < 0) {
621 XBT_WARN("Unmapping of fd %d failed: %s", data->fd, strerror(errno));
624 if (data->count <= 0) {
626 allocs.erase(allocs.find(meta->second.data->first));
627 XBT_DEBUG("Shared free - with removal - of %p", ptr);
629 XBT_DEBUG("Shared free - no removal - of %p, count = %d", ptr, data->count);
632 XBT_DEBUG("Classic free of %p", ptr);
638 int smpi_shared_known_call(const char* func, const char* input)
640 char* loc = bprintf("%s:%s", func, input);
643 if (calls==nullptr) {
644 calls = xbt_dict_new_homogeneous(nullptr);
647 xbt_dict_get(calls, loc); /* Succeed or throw */
653 if (ex.category != not_found_error)
663 void* smpi_shared_get_call(const char* func, const char* input) {
664 char* loc = bprintf("%s:%s", func, input);
668 calls = xbt_dict_new_homogeneous(nullptr);
670 data = xbt_dict_get(calls, loc);
675 void* smpi_shared_set_call(const char* func, const char* input, void* data) {
676 char* loc = bprintf("%s:%s", func, input);
679 calls = xbt_dict_new_homogeneous(nullptr);
681 xbt_dict_set(calls, loc, data, nullptr);
687 /** Map a given SMPI privatization segment (make a SMPI process active) */
688 void smpi_switch_data_segment(int dest) {
689 if (smpi_loaded_page == dest)//no need to switch, we've already loaded the one we want
693 smpi_really_switch_data_segment(dest);
696 /** Map a given SMPI privatization segment (make a SMPI process active) even if SMPI thinks it is already active
698 * When doing a state restoration, the state of the restored variables might not be consistent with the state of the
699 * virtual memory. In this case, we to change the data segment.
701 void smpi_really_switch_data_segment(int dest) {
702 if(smpi_size_data_exe == 0)//no need to switch
705 #if HAVE_PRIVATIZATION
706 if(smpi_loaded_page==-1){//initial switch, do the copy from the real page here
707 for (int i=0; i< smpi_process_count(); i++){
708 memcpy(smpi_privatisation_regions[i].address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
712 // FIXME, cross-process support (mmap across process when necessary)
713 int current = smpi_privatisation_regions[dest].file_descriptor;
714 XBT_DEBUG("Switching data frame to the one of process %d", dest);
715 void* tmp = mmap (TOPAGE(smpi_start_data_exe), smpi_size_data_exe,
716 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0);
717 if (tmp != TOPAGE(smpi_start_data_exe))
718 xbt_die("Couldn't map the new region");
719 smpi_loaded_page = dest;
723 int smpi_is_privatisation_file(char* file)
725 return strncmp("/dev/shm/my-buffer-", file, std::strlen("/dev/shm/my-buffer-")) == 0;
728 void smpi_initialize_global_memory_segments(){
730 #if !HAVE_PRIVATIZATION
731 smpi_privatize_global_variables=false;
732 xbt_die("You are trying to use privatization on a system that does not support it. Don't.");
736 smpi_get_executable_global_size();
738 XBT_DEBUG ("bss+data segment found : size %d starting at %p", smpi_size_data_exe, smpi_start_data_exe );
740 if (smpi_size_data_exe == 0){//no need to switch
741 smpi_privatize_global_variables=false;
745 smpi_privatisation_regions =
746 static_cast<smpi_privatisation_region_t>( xbt_malloc(smpi_process_count() * sizeof(struct s_smpi_privatisation_region)));
748 for (int i=0; i< smpi_process_count(); i++){
749 //create SIMIX_process_count() mappings of this size with the same data inside
751 void *address = nullptr;
756 snprintf(path, sizeof(path), "/smpi-buffer-%06x", rand()%0xffffff);
757 file_descriptor = shm_open(path, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR);
758 } while (file_descriptor == -1 && errno == EEXIST);
759 if (file_descriptor < 0) {
761 xbt_die("Impossible to create temporary file for memory mapping: %s\n\
762 The open() system call failed with the EMFILE error code (too many files). \n\n\
763 This means that you reached the system limits concerning the amount of files per process. \
764 This is not a surprise if you are trying to virtualize many processes on top of SMPI. \
765 Don't panic -- you should simply increase your system limits and try again. \n\n\
766 First, check what your limits are:\n\
767 cat /proc/sys/fs/file-max # Gives you the system-wide limit\n\
768 ulimit -Hn # Gives you the per process hard limit\n\
769 ulimit -Sn # Gives you the per process soft limit\n\
770 cat /proc/self/limits # Displays any per-process limitation (including the one given above)\n\n\
771 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. \
772 Ask the Internet about tutorials on how to increase the files limit such as: https://rtcamp.com/tutorials/linux/increase-open-files-limit/",
775 xbt_die("Impossible to create temporary file for memory mapping: %s",
779 status = ftruncate(file_descriptor, smpi_size_data_exe);
781 xbt_die("Impossible to set the size of the temporary file for memory mapping");
783 /* Ask for a free region */
784 address = mmap (nullptr, smpi_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");
788 status = shm_unlink(path);
790 xbt_die("Impossible to unlink temporary file for memory mapping");
792 //initialize the values
793 memcpy(address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
795 //store the address of the mapping for further switches
796 smpi_privatisation_regions[i].file_descriptor = file_descriptor;
797 smpi_privatisation_regions[i].address = address;
802 void smpi_destroy_global_memory_segments(){
803 if (smpi_size_data_exe == 0)//no need to switch
805 #if HAVE_PRIVATIZATION
807 for (i=0; i< smpi_process_count(); i++){
808 if(munmap(smpi_privatisation_regions[i].address, smpi_size_data_exe) < 0) {
809 XBT_WARN("Unmapping of fd %d failed: %s", smpi_privatisation_regions[i].file_descriptor, strerror(errno));
811 close(smpi_privatisation_regions[i].file_descriptor);
813 xbt_free(smpi_privatisation_regions);
817 extern "C" { /** These functions will be called from the user code **/
818 smpi_trace_call_location_t* smpi_trace_get_call_location() {
819 return smpi_process_get_call_location();
822 void smpi_trace_set_call_location(const char* file, const int line) {
823 smpi_trace_call_location_t* loc = smpi_process_get_call_location();
825 loc->previous_filename = loc->filename;
826 loc->previous_linenumber = loc->linenumber;
827 loc->filename = file;
828 loc->linenumber = line;
832 * Required for Fortran bindings
834 void smpi_trace_set_call_location_(const char* file, int* line) {
835 smpi_trace_set_call_location(file, *line);
839 * Required for Fortran if -fsecond-underscore is activated
841 void smpi_trace_set_call_location__(const char* file, int* line) {
842 smpi_trace_set_call_location(file, *line);