X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/81e2987ceb9329c50f0ac8109504aa5c784071e2..4f4d5dd084f0b66318d3830b6165cfec26319639:/src/smpi/smpi_memory.cpp diff --git a/src/smpi/smpi_memory.cpp b/src/smpi/smpi_memory.cpp index 34e3d8fc1e..0c56653942 100644 --- a/src/smpi/smpi_memory.cpp +++ b/src/smpi/smpi_memory.cpp @@ -1,31 +1,44 @@ -/* Copyright (c) 2015. The SimGrid Team. - * All rights reserved. */ +/* Copyright (c) 2015-2017. The SimGrid Team. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it * under the terms of the license (GNU LGPL) which comes with this package. */ -#include +#include +#include +#include + +#include -#include #include #include +#include +#include +#include +#include +#include + +#ifndef WIN32 #include #include -#include "../xbt/memory_map.hpp" +#include "src/xbt/memory_map.hpp" -#include "private.h" +#include "private.hpp" +#include "src/smpi/private.h" +#include "src/smpi/private.hpp" -XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_memory, smpi, - "Memory layout support for SMPI"); +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_memory, smpi, "Memory layout support for SMPI"); -#define TOPAGE(addr) (void *)(((unsigned long)(addr) / xbt_pagesize) * xbt_pagesize) +int smpi_loaded_page = -1; +char* smpi_start_data_exe = nullptr; +int smpi_size_data_exe = 0; +int smpi_privatize_global_variables; -#define PROT_RWX (PROT_READ | PROT_WRITE | PROT_EXEC) -#define PROT_RW (PROT_READ | PROT_WRITE ) -#define PROT_RX (PROT_READ | PROT_EXEC ) +static const int PROT_RWX = (PROT_READ | PROT_WRITE | PROT_EXEC); +static const int PROT_RW = (PROT_READ | PROT_WRITE ); +XBT_ATTRIB_UNUSED static const int PROT_RX = (PROT_READ | PROT_EXEC ); -void smpi_get_executable_global_size(void) +void smpi_get_executable_global_size() { char buffer[PATH_MAX]; char* full_name = realpath(xbt_binary_name, buffer); @@ -38,22 +51,150 @@ void smpi_get_executable_global_size(void) // anonymous data segment. This does not happen in practice, however. // File backed RW entry: - if (i->pathname == full_name - && (i->prot & PROT_RWX) == PROT_RW) { + if (i->pathname == full_name && (i->prot & PROT_RWX) == PROT_RW) { smpi_start_data_exe = (char*) i->start_addr; smpi_size_data_exe = i->end_addr - i->start_addr; ++i; /* Here we are making the assumption that a suitable empty region following the rw- area is the end of the data segment. It would be better to check with the size of the data segment. */ - if (i != map.end() - && i->pathname.empty() - && (i->prot & PROT_RWX) == PROT_RW - && i->start_addr == (std::uint64_t) smpi_start_data_exe + smpi_size_data_exe) { - smpi_size_data_exe = i->end_addr - (std::uint64_t) smpi_start_data_exe; + if (i != map.end() && i->pathname.empty() && (i->prot & PROT_RWX) == PROT_RW + && (char*)i->start_addr == smpi_start_data_exe + smpi_size_data_exe) { + smpi_size_data_exe = (char*)i->end_addr - smpi_start_data_exe; } return; } } xbt_die("Did not find my data segment."); } +#endif + + +/** Map a given SMPI privatization segment (make a SMPI process active) */ +void smpi_switch_data_segment(int dest) { + if (smpi_loaded_page == dest)//no need to switch, we've already loaded the one we want + return; + + // So the job: + smpi_really_switch_data_segment(dest); +} + +/** Map a given SMPI privatization segment (make a SMPI process active) even if SMPI thinks it is already active + * + * When doing a state restoration, the state of the restored variables might not be consistent with the state of the + * virtual memory. In this case, we to change the data segment. + */ +void smpi_really_switch_data_segment(int dest) +{ + if(smpi_size_data_exe == 0)//no need to switch + return; + +#if HAVE_PRIVATIZATION + if(smpi_loaded_page==-1){//initial switch, do the copy from the real page here + for (int i=0; i< smpi_process_count(); i++){ + memcpy(smpi_privatization_regions[i].address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe); + } + } + + // FIXME, cross-process support (mmap across process when necessary) + int current = smpi_privatization_regions[dest].file_descriptor; + XBT_DEBUG("Switching data frame to the one of process %d", dest); + void* tmp = + mmap(TOPAGE(smpi_start_data_exe), smpi_size_data_exe, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0); + if (tmp != TOPAGE(smpi_start_data_exe)) + xbt_die("Couldn't map the new region (errno %d): %s", errno, strerror(errno)); + smpi_loaded_page = dest; +#endif +} + +int smpi_is_privatization_file(char* file) +{ + return strncmp("/dev/shm/my-buffer-", file, std::strlen("/dev/shm/my-buffer-")) == 0; +} + +void smpi_initialize_global_memory_segments() +{ + +#if HAVE_PRIVATIZATION + smpi_get_executable_global_size(); + + XBT_DEBUG ("bss+data segment found : size %d starting at %p", smpi_size_data_exe, smpi_start_data_exe ); + + if (smpi_size_data_exe == 0){//no need to switch + smpi_privatize_global_variables=false; + return; + } + + smpi_privatization_regions = static_cast( + xbt_malloc(smpi_process_count() * sizeof(struct s_smpi_privatization_region))); + + for (int i=0; i< smpi_process_count(); i++){ + // create SIMIX_process_count() mappings of this size with the same data inside + int file_descriptor; + void* address = nullptr; + char path[24]; + int status; + + do { + snprintf(path, sizeof(path), "/smpi-buffer-%06x", rand() % 0xffffff); + file_descriptor = shm_open(path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + } while (file_descriptor == -1 && errno == EEXIST); + if (file_descriptor < 0) { + if (errno == EMFILE) { + xbt_die("Impossible to create temporary file for memory mapping: %s\n\ +The open() system call failed with the EMFILE error code (too many files). \n\n\ +This means that you reached the system limits concerning the amount of files per process. \ +This is not a surprise if you are trying to virtualize many processes on top of SMPI. \ +Don't panic -- you should simply increase your system limits and try again. \n\n\ +First, check what your limits are:\n\ + cat /proc/sys/fs/file-max # Gives you the system-wide limit\n\ + ulimit -Hn # Gives you the per process hard limit\n\ + ulimit -Sn # Gives you the per process soft limit\n\ + cat /proc/self/limits # Displays any per-process limitation (including the one given above)\n\n\ +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. \ +Ask the Internet about tutorials on how to increase the files limit such as: https://rtcamp.com/tutorials/linux/increase-open-files-limit/", + strerror(errno)); + } + xbt_die("Impossible to create temporary file for memory mapping: %s", strerror(errno)); + } + + status = ftruncate(file_descriptor, smpi_size_data_exe); + if (status) + xbt_die("Impossible to set the size of the temporary file for memory mapping"); + + /* Ask for a free region */ + address = mmap(nullptr, smpi_size_data_exe, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0); + if (address == MAP_FAILED) + xbt_die("Couldn't find a free region for memory mapping"); + + status = shm_unlink(path); + if (status) + xbt_die("Impossible to unlink temporary file for memory mapping"); + + // initialize the values + memcpy(address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe); + + // store the address of the mapping for further switches + smpi_privatization_regions[i].file_descriptor = file_descriptor; + smpi_privatization_regions[i].address = address; + } +#else /* ! HAVE_PRIVATIZATION */ + smpi_privatize_global_variables = false; + xbt_die("You are trying to use privatization on a system that does not support it. Don't."); + return; +#endif +} + +void smpi_destroy_global_memory_segments(){ + if (smpi_size_data_exe == 0)//no need to switch + return; +#if HAVE_PRIVATIZATION + for (int i=0; i< smpi_process_count(); i++) { + if (munmap(smpi_privatization_regions[i].address, smpi_size_data_exe) < 0) + XBT_WARN("Unmapping of fd %d failed: %s", smpi_privatization_regions[i].file_descriptor, strerror(errno)); + close(smpi_privatization_regions[i].file_descriptor); + } + xbt_free(smpi_privatization_regions); +#endif +} +