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"
16 #include "xbt/sysdep.h"
18 #include "surf/surf.h"
19 #include "simgrid/sg_config.h"
20 #include "simgrid/modelchecker.h"
21 #include "src/mc/mc_replay.h"
27 #include <sys/types.h>
30 #include <math.h> // sqrt
40 #define MAP_ANONYMOUS MAP_ANON
43 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_bench, smpi, "Logging specific to SMPI (benchmarking)");
45 /* Shared allocations are handled through shared memory segments.
46 * Associated data and metadata are used as follows:
49 * `allocs' dict ---- -.
50 * ---------- shared_data_t shared_metadata_t / | | |
51 * .->| <name> | ---> -------------------- <--. ----------------- | | | |
52 * | ---------- | fd of <name> | | | size of mmap | --| | | |
53 * | | count (2) | |-- | data | \ | | |
54 * `----------------- | <name> | | ----------------- ---- |
55 * -------------------- | ^ |
57 * | | `allocs_metadata' dict |
58 * | | ---------------------- |
59 * | `-- | <addr of mmap #1> |<-'
60 * | .-- | <addr of mmap #2> |<-.
61 * | | ---------------------- |
67 * | shared_metadata_t / | |
68 * | ----------------- | | |
69 * | | size of mmap | --| | |
71 * ----------------- | | |
76 #define PTR_STRLEN (2 + 2 * sizeof(void*) + 1)
78 xbt_dict_t samples = nullptr; /* Allocated on first use */
79 xbt_dict_t calls = nullptr; /* Allocated on first use */
81 double smpi_cpu_threshold;
82 double smpi_running_power;
84 int smpi_loaded_page = -1;
85 char* smpi_start_data_exe = nullptr;
86 int smpi_size_data_exe = 0;
87 bool smpi_privatize_global_variables;
88 double smpi_total_benched_time = 0;
89 smpi_privatisation_region_t smpi_privatisation_regions;
93 /** Some location in the source code
95 * This information is used by SMPI_SHARED_MALLOC to allocate some shared memory for all simulated processes.
97 class smpi_source_location {
99 smpi_source_location(const char* filename, int line)
100 : filename(filename), filename_length(strlen(filename)), line(line) {}
102 /** Pointer to a static string containing the file name */
103 const char* filename = nullptr;
104 int filename_length = 0;
107 bool operator==(smpi_source_location const& that) const
109 return filename_length == that.filename_length
111 && std::memcmp(filename, that.filename, filename_length) == 0;
113 bool operator!=(smpi_source_location const& that) const
115 return !(*this == that);
124 class hash<smpi_source_location> {
126 typedef smpi_source_location argument_type;
127 typedef std::size_t result_type;
128 result_type operator()(smpi_source_location const& loc) const
130 return xbt_str_hash_ext(loc.filename, loc.filename_length)
131 ^ xbt_str_hash_ext((const char*) &loc.line, sizeof(loc.line));
144 std::unordered_map<smpi_source_location, shared_data_t> allocs;
145 typedef std::unordered_map<smpi_source_location, shared_data_t>::value_type shared_data_key_type;
149 shared_data_key_type* data;
152 std::unordered_map<void*, shared_metadata_t> allocs_metadata;
156 static size_t shm_size(int fd) {
159 if(fstat(fd, &st) < 0) {
160 xbt_die("Could not stat fd %d: %s", fd, strerror(errno));
162 return static_cast<size_t>(st.st_size);
166 static void* shm_map(int fd, size_t size, shared_data_key_type* data) {
168 char loc[PTR_STRLEN];
169 shared_metadata_t meta;
171 if(size > shm_size(fd) && (ftruncate(fd, static_cast<off_t>(size)) < 0)) {
172 xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
175 mem = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
176 if(mem == MAP_FAILED) {
177 xbt_die("Could not map fd %d: %s", fd, strerror(errno));
179 snprintf(loc, PTR_STRLEN, "%p", mem);
182 allocs_metadata[mem] = meta;
183 XBT_DEBUG("MMAP %zu to %p", size, mem);
188 void smpi_bench_destroy(void)
191 allocs_metadata.clear();
192 xbt_dict_free(&samples);
193 xbt_dict_free(&calls);
196 extern "C" XBT_PUBLIC(void) smpi_execute_flops_(double *flops);
197 void smpi_execute_flops_(double *flops)
199 smpi_execute_flops(*flops);
202 extern "C" XBT_PUBLIC(void) smpi_execute_(double *duration);
203 void smpi_execute_(double *duration)
205 smpi_execute(*duration);
208 void smpi_execute_flops(double flops) {
209 smx_synchro_t action;
210 XBT_DEBUG("Handle real computation time: %f flops", flops);
211 action = simcall_execution_start("computation", flops, 1, 0, 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_running_power;
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);
227 smpi_execute_flops(flops);
229 TRACE_smpi_computing_out(rank);
232 XBT_DEBUG("Real computation took %g while option smpi/cpu_threshold is set to %g => ignore it",
233 duration, smpi_cpu_threshold);
237 void smpi_bench_begin(void)
239 if (smpi_privatize_global_variables) {
240 smpi_switch_data_segment(smpi_process_index());
243 if (MC_is_active() || MC_record_replay_is_active())
247 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') {
248 int event_set = smpi_process_papi_event_set();
249 // PAPI_start sets everything to 0! See man(3) PAPI_start
250 if (PAPI_LOW_LEVEL_INITED == PAPI_is_initialized()) {
251 if (PAPI_start(event_set) != PAPI_OK) {
252 // TODO This needs some proper handling.
253 XBT_CRITICAL("Could not start PAPI counters.\n");
259 xbt_os_threadtimer_start(smpi_process_timer());
262 void smpi_bench_end(void)
264 if (MC_is_active() || MC_record_replay_is_active())
268 xbt_os_timer_t timer = smpi_process_timer();
269 xbt_os_threadtimer_stop(timer);
273 * An MPI function has been called and now is the right time to update
274 * our PAPI counters for this process.
276 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0') {
277 papi_counter_t& counter_data = smpi_process_papi_counters();
278 int event_set = smpi_process_papi_event_set();
279 std::vector<long long> event_values = std::vector<long long>(counter_data.size());
281 if (PAPI_stop(event_set, &event_values[0]) != PAPI_OK) { // Error
282 XBT_CRITICAL("Could not stop PAPI counters.\n");
285 for (unsigned int i = 0; i < counter_data.size(); i++) {
286 counter_data[i].second += event_values[i];
287 // XBT_DEBUG("[%i] PAPI: Counter %s: Value is now %lli (got increment by %lli\n", smpi_process_index(),
288 // counter_data[i].first.c_str(), counter_data[i].second, event_values[i]);
294 if (smpi_process_get_sampling()) {
295 XBT_CRITICAL("Cannot do recursive benchmarks.");
296 XBT_CRITICAL("Are you trying to make a call to MPI within a SMPI_SAMPLE_ block?");
297 xbt_backtrace_display_current();
298 xbt_die("Aborting.");
301 if (xbt_cfg_get_string("smpi/comp-adjustment-file")[0] != '\0') { // Maybe we need to artificially speed up or slow
302 // down our computation based on our statistical analysis.
304 smpi_trace_call_location_t* loc = smpi_process_get_call_location();
305 std::string key = loc->get_composed_key();
306 std::unordered_map<std::string, double>::const_iterator it = location2speedup.find(key);
307 if (it != location2speedup.end()) {
308 speedup = it->second;
312 // Simulate the benchmarked computation unless disabled via command-line argument
313 if (xbt_cfg_get_boolean("smpi/simulate-computation")) {
314 smpi_execute(xbt_os_timer_elapsed(timer)/speedup);
318 if (xbt_cfg_get_string("smpi/papi-events")[0] != '\0' && TRACE_smpi_is_enabled()) {
319 char container_name[INSTR_DEFAULT_STR_SIZE];
320 smpi_container(smpi_process_index(), container_name, INSTR_DEFAULT_STR_SIZE);
321 container_t container = PJ_container_get(container_name);
322 papi_counter_t& counter_data = smpi_process_papi_counters();
324 for (auto& pair : counter_data) {
325 new_pajeSetVariable(surf_get_clock(), container,
326 PJ_type_get(/* countername */ pair.first.c_str(), container->type), pair.second);
331 smpi_total_benched_time += xbt_os_timer_elapsed(timer);
334 /* Private sleep function used by smpi_sleep() and smpi_usleep() */
335 static unsigned int private_sleep(double secs)
339 XBT_DEBUG("Sleep for: %lf secs", secs);
340 int rank = smpi_comm_rank(MPI_COMM_WORLD);
341 instr_extra_data extra = xbt_new0(s_instr_extra_data_t,1);
342 extra->type=TRACING_SLEEPING;
343 extra->sleep_duration=secs;
344 TRACE_smpi_sleeping_in(rank, extra);
346 simcall_process_sleep(secs);
348 TRACE_smpi_sleeping_out(rank);
354 unsigned int smpi_sleep(unsigned int secs)
356 return private_sleep(static_cast<double>(secs));
359 int smpi_usleep(useconds_t usecs)
361 return static_cast<int>(private_sleep(static_cast<double>(usecs) / 1000000.0));
364 #if _POSIX_TIMERS > 0
365 int smpi_nanosleep(const struct timespec *tp, struct timespec * t)
367 return static_cast<int>(private_sleep(static_cast<double>(tp->tv_sec + tp->tv_nsec / 1000000000.0)));
371 int smpi_gettimeofday(struct timeval *tv, void* tz)
375 now = SIMIX_get_clock();
377 tv->tv_sec = static_cast<time_t>(now);
379 tv->tv_usec = static_cast<useconds_t>((now - tv->tv_sec) * 1e6);
381 tv->tv_usec = static_cast<suseconds_t>((now - tv->tv_sec) * 1e6);
388 #if _POSIX_TIMERS > 0
389 int smpi_clock_gettime(clockid_t clk_id, struct timespec *tp)
391 //there is only one time in SMPI, so clk_id is ignored.
394 now = SIMIX_get_clock();
396 tp->tv_sec = static_cast<time_t>(now);
397 tp->tv_nsec = static_cast<long int>((now - tp->tv_sec) * 1e9);
404 extern double sg_surf_precision;
405 unsigned long long smpi_rastro_resolution (void)
408 double resolution = (1/sg_surf_precision);
410 return static_cast<unsigned long long>(resolution);
413 unsigned long long smpi_rastro_timestamp (void)
416 double now = SIMIX_get_clock();
418 unsigned long long sec = (unsigned long long)now;
419 unsigned long long pre = (now - sec) * smpi_rastro_resolution();
421 return static_cast<unsigned long long>(sec) * smpi_rastro_resolution() + pre;
424 /* ****************************** Functions related to the SMPI_SAMPLE_ macros ************************************/
426 double threshold; /* maximal stderr requested (if positive) */
427 double relstderr; /* observed stderr so far */
428 double mean; /* mean of benched times, to be used if the block is disabled */
429 double sum; /* sum of benched times (to compute the mean and stderr) */
430 double sum_pow2; /* sum of the square of the benched times (to compute the stderr) */
431 int iters; /* amount of requested iterations */
432 int count; /* amount of iterations done so far */
433 int benching; /* 1: we are benchmarking; 0: we have enough data, no bench anymore */
436 static char *sample_location(int global, const char *file, int line) {
438 return bprintf("%s:%d", file, line);
440 return bprintf("%s:%d:%d", file, line, smpi_process_index());
444 static int sample_enough_benchs(local_data_t *data) {
445 int res = data->count >= data->iters;
446 if (data->threshold>0.0) {
448 res = 0; // not enough data
449 if (data->relstderr > data->threshold)
450 res = 0; // stderr too high yet
452 XBT_DEBUG("%s (count:%d iter:%d stderr:%f thres:%f mean:%fs)",
453 (res?"enough benchs":"need more data"), data->count, data->iters, data->relstderr, data->threshold, data->mean);
457 void smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
459 char *loc = sample_location(global, file, line);
462 smpi_bench_end(); /* Take time from previous, unrelated computation into account */
463 smpi_process_set_sampling(1);
465 if (samples==nullptr)
466 samples = xbt_dict_new_homogeneous(free);
468 data = static_cast<local_data_t *>(xbt_dict_get_or_null(samples, loc));
470 xbt_assert(threshold>0 || iters>0,
471 "You should provide either a positive amount of iterations to bench, or a positive maximal stderr (or both)");
472 data = static_cast<local_data_t *>( xbt_new(local_data_t, 1));
475 data->sum_pow2 = 0.0;
477 data->threshold = threshold;
478 data->benching = 1; // If we have no data, we need at least one
480 xbt_dict_set(samples, loc, data, nullptr);
481 XBT_DEBUG("XXXXX First time ever on benched nest %s.",loc);
483 if (data->iters != iters || data->threshold != threshold) {
484 XBT_ERROR("Asked to bench block %s with different settings %d, %f is not %d, %f. "
485 "How did you manage to give two numbers at the same line??",
486 loc, data->iters, data->threshold, iters,threshold);
490 // if we already have some data, check whether sample_2 should get one more bench or whether it should emulate
491 // the computation instead
492 data->benching = (sample_enough_benchs(data) == 0);
493 XBT_DEBUG("XXXX Re-entering the benched nest %s. %s",loc,
494 (data->benching?"more benching needed":"we have enough data, skip computes"));
499 int smpi_sample_2(int global, const char *file, int line)
501 char *loc = sample_location(global, file, line);
505 xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
506 data = static_cast<local_data_t *>(xbt_dict_get(samples, loc));
507 XBT_DEBUG("sample2 %s",loc);
510 if (data->benching==1) {
511 // we need to run a new bench
512 XBT_DEBUG("benchmarking: count:%d iter:%d stderr:%f thres:%f; mean:%f",
513 data->count, data->iters, data->relstderr, data->threshold, data->mean);
516 // Enough data, no more bench (either we got enough data from previous visits to this benched nest, or we just
517 //ran one bench and need to bail out now that our job is done). Just sleep instead
518 XBT_DEBUG("No benchmark (either no need, or just ran one): count >= iter (%d >= %d) or stderr<thres (%f<=%f)."
519 " apply the %fs delay instead", data->count, data->iters, data->relstderr, data->threshold, data->mean);
520 smpi_execute(data->mean);
521 smpi_process_set_sampling(0);
522 res = 0; // prepare to capture future, unrelated computations
528 void smpi_sample_3(int global, const char *file, int line)
530 char *loc = sample_location(global, file, line);
533 xbt_assert(samples, "Y U NO use SMPI_SAMPLE_* macros? Stop messing directly with smpi_sample_* functions!");
534 data = static_cast<local_data_t *>(xbt_dict_get(samples, loc));
535 XBT_DEBUG("sample3 %s",loc);
538 if (data->benching==0) {
542 // ok, benchmarking this loop is over
543 xbt_os_threadtimer_stop(smpi_process_timer());
548 sample = xbt_os_timer_elapsed(smpi_process_timer());
550 data->sum_pow2 += sample * sample;
551 n = static_cast<double>(data->count);
552 data->mean = data->sum / n;
553 data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
554 if (sample_enough_benchs(data)==0) {
555 data->mean = sample; // Still in benching process; We want sample_2 to simulate the exact time of this loop
556 // occurrence before leaving, not the mean over the history
558 XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
559 data->mean, data->relstderr, sample);
561 // That's enough for now, prevent sample_2 to run the same code over and over
567 void *smpi_shared_malloc(size_t size, const char *file, int line)
570 if (xbt_cfg_get_boolean("smpi/use-shared-malloc")){
572 smpi_source_location loc(file, line);
573 auto res = allocs.insert(std::make_pair(loc, shared_data_t()));
574 auto data = res.first;
576 // The insertion did not take place.
577 // Generate a shared memory name from the address of the shared_data:
578 char shmname[32]; // cannot be longer than PSHMNAMLEN = 31 on Mac OS X (shm_open raises ENAMETOOLONG otherwise)
579 snprintf(shmname, 31, "/shmalloc%p", &*data);
580 fd = shm_open(shmname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
583 xbt_die("Please cleanup /dev/shm/%s", shmname);
585 xbt_die("An unhandled error occurred while opening %s. shm_open: %s", shmname, strerror(errno));
587 data->second.fd = fd;
588 data->second.count = 1;
589 mem = shm_map(fd, size, &*data);
590 if (shm_unlink(shmname) < 0) {
591 XBT_WARN("Could not early unlink %s. shm_unlink: %s", shmname, strerror(errno));
593 XBT_DEBUG("Mapping %s at %p through %d", shmname, mem, fd);
595 mem = shm_map(data->second.fd, size, &*data);
596 data->second.count++;
598 XBT_DEBUG("Shared malloc %zu in %p (metadata at %p)", size, mem, &*data);
600 mem = xbt_malloc(size);
601 XBT_DEBUG("Classic malloc %zu in %p", size, mem);
607 void smpi_shared_free(void *ptr)
609 char loc[PTR_STRLEN];
611 if (xbt_cfg_get_boolean("smpi/use-shared-malloc")){
612 snprintf(loc, PTR_STRLEN, "%p", ptr);
613 auto meta = allocs_metadata.find(ptr);
614 if (meta == allocs_metadata.end()) {
615 XBT_WARN("Cannot free: %p was not shared-allocated by SMPI", ptr);
618 shared_data_t* data = &meta->second.data->second;
619 if (munmap(ptr, meta->second.size) < 0) {
620 XBT_WARN("Unmapping of fd %d failed: %s", data->fd, strerror(errno));
623 XBT_DEBUG("Shared free - no removal - of %p, count = %d", ptr, data->count);
624 if (data->count <= 0) {
626 allocs.erase(allocs.find(meta->second.data->first));
627 XBT_DEBUG("Shared free - with removal - of %p", ptr);
630 XBT_DEBUG("Classic free of %p", ptr);
636 int smpi_shared_known_call(const char* func, const char* input)
638 char* loc = bprintf("%s:%s", func, input);
641 if (calls==nullptr) {
642 calls = xbt_dict_new_homogeneous(nullptr);
645 xbt_dict_get(calls, loc); /* Succeed or throw */
651 if (ex.category != not_found_error)
661 void* smpi_shared_get_call(const char* func, const char* input) {
662 char* loc = bprintf("%s:%s", func, input);
666 calls = xbt_dict_new_homogeneous(nullptr);
668 data = xbt_dict_get(calls, loc);
673 void* smpi_shared_set_call(const char* func, const char* input, void* data) {
674 char* loc = bprintf("%s:%s", func, input);
677 calls = xbt_dict_new_homogeneous(nullptr);
679 xbt_dict_set(calls, loc, data, nullptr);
685 /** Map a given SMPI privatization segment (make a SMPI process active) */
686 void smpi_switch_data_segment(int dest) {
687 if (smpi_loaded_page == dest)//no need to switch, we've already loaded the one we want
691 smpi_really_switch_data_segment(dest);
694 /** Map a given SMPI privatization segment (make a SMPI process active) even if SMPI thinks it is already active
696 * When doing a state restoration, the state of the restored variables might not be consistent with the state of the
697 * virtual memory. In this case, we to change the data segment.
699 void smpi_really_switch_data_segment(int dest) {
700 if(smpi_size_data_exe == 0)//no need to switch
703 #if HAVE_PRIVATIZATION
704 if(smpi_loaded_page==-1){//initial switch, do the copy from the real page here
705 for (int i=0; i< smpi_process_count(); i++){
706 memcpy(smpi_privatisation_regions[i].address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
710 // FIXME, cross-process support (mmap across process when necessary)
711 int current = smpi_privatisation_regions[dest].file_descriptor;
712 XBT_DEBUG("Switching data frame to the one of process %d", dest);
713 void* tmp = mmap (TOPAGE(smpi_start_data_exe), smpi_size_data_exe,
714 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0);
715 if (tmp != TOPAGE(smpi_start_data_exe))
716 xbt_die("Couldn't map the new region");
717 smpi_loaded_page = dest;
721 int smpi_is_privatisation_file(char* file)
723 return strncmp("/dev/shm/my-buffer-", file, std::strlen("/dev/shm/my-buffer-")) == 0;
726 void smpi_initialize_global_memory_segments(){
728 #if !HAVE_PRIVATIZATION
729 smpi_privatize_global_variables=false;
730 xbt_die("You are trying to use privatization on a system that does not support it. Don't.");
734 smpi_get_executable_global_size();
736 XBT_DEBUG ("bss+data segment found : size %d starting at %p", smpi_size_data_exe, smpi_start_data_exe );
738 if (smpi_size_data_exe == 0){//no need to switch
739 smpi_privatize_global_variables=false;
743 smpi_privatisation_regions =
744 static_cast<smpi_privatisation_region_t>( xbt_malloc(smpi_process_count() * sizeof(struct s_smpi_privatisation_region)));
746 for (int i=0; i< smpi_process_count(); i++){
747 //create SIMIX_process_count() mappings of this size with the same data inside
748 void *address = nullptr;
749 char path[] = "/dev/shm/my-buffer-XXXXXX";
752 int file_descriptor= mkstemp (path);
753 if (file_descriptor < 0) {
755 xbt_die("Impossible to create temporary file for memory mapping: %s\n\
756 The open() system call failed with the EMFILE error code (too many files). \n\n\
757 This means that you reached the system limits concerning the amount of files per process. \
758 This is not a surprise if you are trying to virtualize many processes on top of SMPI. \
759 Don't panic -- you should simply increase your system limits and try again. \n\n\
760 First, check what your limits are:\n\
761 cat /proc/sys/fs/file-max # Gives you the system-wide limit\n\
762 ulimit -Hn # Gives you the per process hard limit\n\
763 ulimit -Sn # Gives you the per process soft limit\n\
764 cat /proc/self/limits # Displays any per-process limitation (including the one given above)\n\n\
765 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. \
766 Ask the Internet about tutorials on how to increase the files limit such as: https://rtcamp.com/tutorials/linux/increase-open-files-limit/",
769 xbt_die("Impossible to create temporary file for memory mapping: %s",
773 status = unlink (path);
775 xbt_die("Impossible to unlink temporary file for memory mapping");
777 status = ftruncate(file_descriptor, smpi_size_data_exe);
779 xbt_die("Impossible to set the size of the temporary file for memory mapping");
781 /* Ask for a free region */
782 address = mmap (nullptr, smpi_size_data_exe, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0);
783 if (address == MAP_FAILED)
784 xbt_die("Couldn't find a free region for memory mapping");
786 //initialize the values
787 memcpy(address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
789 //store the address of the mapping for further switches
790 smpi_privatisation_regions[i].file_descriptor = file_descriptor;
791 smpi_privatisation_regions[i].address = address;
796 void smpi_destroy_global_memory_segments(){
797 if (smpi_size_data_exe == 0)//no need to switch
799 #if HAVE_PRIVATIZATION
801 for (i=0; i< smpi_process_count(); i++){
802 if(munmap(smpi_privatisation_regions[i].address, smpi_size_data_exe) < 0) {
803 XBT_WARN("Unmapping of fd %d failed: %s", smpi_privatisation_regions[i].file_descriptor, strerror(errno));
805 close(smpi_privatisation_regions[i].file_descriptor);
807 xbt_free(smpi_privatisation_regions);
811 extern "C" { /** These functions will be called from the user code **/
812 smpi_trace_call_location_t* smpi_trace_get_call_location() {
813 return smpi_process_get_call_location();
816 void smpi_trace_set_call_location(const char* file, const int line) {
817 smpi_trace_call_location_t* loc = smpi_process_get_call_location();
819 loc->previous_filename = loc->filename;
820 loc->previous_linenumber = loc->linenumber;
821 loc->filename = file;
822 loc->linenumber = line;
826 * Required for Fortran bindings
828 void smpi_trace_set_call_location_(const char* file, int* line) {
829 smpi_trace_set_call_location(file, *line);
833 * Required for Fortran if -fsecond-underscore is activated
835 void smpi_trace_set_call_location__(const char* file, int* line) {
836 smpi_trace_set_call_location(file, *line);