Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
portability cheating: avoid the configurations that are known to be broken
[simgrid.git] / src / smpi / smpi_global.cpp
index a05d57f..3770ba2 100644 (file)
@@ -14,6 +14,7 @@
 #include "private.h"
 #include "private.hpp"
 #include "simgrid/s4u/Mailbox.hpp"
+#include "smpi/smpi_shared_malloc.hpp"
 #include "simgrid/sg_config.h"
 #include "src/kernel/activity/SynchroComm.hpp"
 #include "src/mc/mc_record.h"
@@ -94,7 +95,10 @@ int smpi_process_count()
 
 simgrid::smpi::Process* smpi_process()
 {
-  simgrid::MsgActorExt* msgExt = static_cast<simgrid::MsgActorExt*>(SIMIX_process_self()->data);
+  smx_actor_t me = SIMIX_process_self();
+  if (me == nullptr) // This happens sometimes (eg, when linking against NS3 because it pulls openMPI...)
+    return nullptr;
+  simgrid::MsgActorExt* msgExt = static_cast<simgrid::MsgActorExt*>(me->data);
   return static_cast<simgrid::smpi::Process*>(msgExt->data);
 }
 
@@ -115,6 +119,14 @@ int smpi_process_index(){
   return smpi_process()->index();
 }
 
+void * smpi_process_get_user_data(){
+  return smpi_process()->get_user_data();
+}
+
+void smpi_process_set_user_data(void *data){
+  return smpi_process()->set_user_data(data);
+}
+
 
 int smpi_global_size()
 {
@@ -129,49 +141,86 @@ void smpi_comm_set_copy_data_callback(void (*callback) (smx_activity_t, void*, s
   smpi_comm_copy_data_callback = callback;
 }
 
-void smpi_comm_copy_buffer_callback(smx_activity_t synchro, void *buff, size_t buff_size)
+static void print(std::vector<std::pair<size_t, size_t>> vec) {
+  std::fprintf(stderr, "{");
+  for (auto elt : vec) {
+    std::fprintf(stderr, "(0x%zx, 0x%zx),", elt.first, elt.second);
+    }
+    std::fprintf(stderr, "}\n");
+}
+static void memcpy_private(void* dest, const void* src, std::vector<std::pair<size_t, size_t>>& private_blocks)
 {
+  for(auto block : private_blocks) {
+    memcpy((uint8_t*)dest+block.first, (uint8_t*)src+block.first, block.second-block.first);
+  }
+}
 
-  simgrid::kernel::activity::Comm *comm = dynamic_cast<simgrid::kernel::activity::Comm*>(synchro);
+static void check_blocks(std::vector<std::pair<size_t, size_t>> &private_blocks, size_t buff_size) {
+  for(auto block : private_blocks) {
+    xbt_assert(block.first <= block.second && block.second <= buff_size, "Oops, bug in shared malloc.");
+  }
+}
 
+void smpi_comm_copy_buffer_callback(smx_activity_t synchro, void *buff, size_t buff_size)
+{
+  simgrid::kernel::activity::Comm *comm = dynamic_cast<simgrid::kernel::activity::Comm*>(synchro);
+  int src_shared                        = 0;
+  int dst_shared                        = 0;
+  size_t src_offset                     = 0;
+  size_t dst_offset                     = 0;
+  std::vector<std::pair<size_t, size_t>> src_private_blocks;
+  std::vector<std::pair<size_t, size_t>> dst_private_blocks;
   XBT_DEBUG("Copy the data over");
-  if(smpi_is_shared(buff)){
+  if((src_shared=smpi_is_shared(buff, src_private_blocks, &src_offset))) {
     XBT_DEBUG("Sender %p is shared. Let's ignore it.", buff);
-  }else if(smpi_is_shared((char*)comm->dst_buff)){
+    src_private_blocks = shift_and_frame_private_blocks(src_private_blocks, src_offset, buff_size);
+  }
+  else {
+    src_private_blocks.clear();
+    src_private_blocks.push_back(std::make_pair(0, buff_size));
+  }
+  if((dst_shared=smpi_is_shared((char*)comm->dst_buff, dst_private_blocks, &dst_offset))) {
     XBT_DEBUG("Receiver %p is shared. Let's ignore it.", (char*)comm->dst_buff);
-  }else{
-    void* tmpbuff=buff;
-    if((smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP) && (static_cast<char*>(buff) >= smpi_start_data_exe)
-        && (static_cast<char*>(buff) < smpi_start_data_exe + smpi_size_data_exe )
-      ){
-         XBT_DEBUG("Privatization : We are copying from a zone inside global memory... Saving data to temp buffer !");
-
-         smpi_switch_data_segment(
-             (static_cast<simgrid::smpi::Process*>((static_cast<simgrid::MsgActorExt*>(comm->src_proc->data)->data))->index()));
-         tmpbuff = static_cast<void*>(xbt_malloc(buff_size));
-         memcpy(tmpbuff, buff, buff_size);
-    }
-
-    if((smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP) && ((char*)comm->dst_buff >= smpi_start_data_exe)
-        && ((char*)comm->dst_buff < smpi_start_data_exe + smpi_size_data_exe )){
-         XBT_DEBUG("Privatization : We are copying to a zone inside global memory - Switch data segment");
-         smpi_switch_data_segment(
-             (static_cast<simgrid::smpi::Process*>((static_cast<simgrid::MsgActorExt*>(comm->dst_proc->data)->data))->index()));
-    }
-
-    XBT_DEBUG("Copying %zu bytes from %p to %p", buff_size, tmpbuff,comm->dst_buff);
-    memcpy(comm->dst_buff, tmpbuff, buff_size);
+    dst_private_blocks = shift_and_frame_private_blocks(dst_private_blocks, dst_offset, buff_size);
+  }
+  else {
+    dst_private_blocks.clear();
+    dst_private_blocks.push_back(std::make_pair(0, buff_size));
+  }
+  check_blocks(src_private_blocks, buff_size);
+  check_blocks(dst_private_blocks, buff_size);
+  auto private_blocks = merge_private_blocks(src_private_blocks, dst_private_blocks);
+  check_blocks(private_blocks, buff_size);
+  void* tmpbuff=buff;
+  if((smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP) && (static_cast<char*>(buff) >= smpi_start_data_exe)
+      && (static_cast<char*>(buff) < smpi_start_data_exe + smpi_size_data_exe )
+    ){
+       XBT_DEBUG("Privatization : We are copying from a zone inside global memory... Saving data to temp buffer !");
+
+       smpi_switch_data_segment(
+           (static_cast<simgrid::smpi::Process*>((static_cast<simgrid::MsgActorExt*>(comm->src_proc->data)->data))->index()));
+       tmpbuff = static_cast<void*>(xbt_malloc(buff_size));
+       memcpy_private(tmpbuff, buff, private_blocks);
+  }
 
-    if (comm->detached) {
-      // if this is a detached send, the source buffer was duplicated by SMPI
-      // sender to make the original buffer available to the application ASAP
-      xbt_free(buff);
-      //It seems that the request is used after the call there this should be free somewhere else but where???
-      //xbt_free(comm->comm.src_data);// inside SMPI the request is kept inside the user data and should be free
-      comm->src_buff = nullptr;
-    }
-    if(tmpbuff!=buff)xbt_free(tmpbuff);
+  if((smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP) && ((char*)comm->dst_buff >= smpi_start_data_exe)
+      && ((char*)comm->dst_buff < smpi_start_data_exe + smpi_size_data_exe )){
+       XBT_DEBUG("Privatization : We are copying to a zone inside global memory - Switch data segment");
+       smpi_switch_data_segment(
+           (static_cast<simgrid::smpi::Process*>((static_cast<simgrid::MsgActorExt*>(comm->dst_proc->data)->data))->index()));
+  }
+  XBT_DEBUG("Copying %zu bytes from %p to %p", buff_size, tmpbuff,comm->dst_buff);
+  memcpy_private(comm->dst_buff, tmpbuff, private_blocks);
+
+  if (comm->detached) {
+    // if this is a detached send, the source buffer was duplicated by SMPI
+    // sender to make the original buffer available to the application ASAP
+    xbt_free(buff);
+    //It seems that the request is used after the call there this should be free somewhere else but where???
+    //xbt_free(comm->comm.src_data);// inside SMPI the request is kept inside the user data and should be free
+    comm->src_buff = nullptr;
   }
+  if(tmpbuff!=buff)xbt_free(tmpbuff);
 
 }
 
@@ -402,13 +451,13 @@ static void smpi_init_logs(){
 
 static void smpi_init_options(){
     //return if already called
-    if(smpi_cpu_threshold!=-1)
+    if (smpi_cpu_threshold > -1)
       return;
     simgrid::smpi::Colls::set_collectives();
     simgrid::smpi::Colls::smpi_coll_cleanup_callback=nullptr;
     smpi_cpu_threshold = xbt_cfg_get_double("smpi/cpu-threshold");
     smpi_host_speed = xbt_cfg_get_double("smpi/host-speed");
-    const char* smpi_privatize_option = xbt_cfg_get_string("smpi/privatize-global-variables");
+    const char* smpi_privatize_option               = xbt_cfg_get_string("smpi/privatization");
     if (std::strcmp(smpi_privatize_option, "no") == 0)
       smpi_privatize_global_variables = SMPI_PRIVATIZE_NONE;
     else if (std::strcmp(smpi_privatize_option, "yes") == 0)
@@ -425,8 +474,14 @@ static void smpi_init_options(){
       smpi_privatize_global_variables = SMPI_PRIVATIZE_NONE;
 
     else
-      xbt_die("Invalid value for smpi/privatize-global-variables: %s",
-        smpi_privatize_option);
+      xbt_die("Invalid value for smpi/privatization: '%s'", smpi_privatize_option);
+
+#if defined(__FreeBSD__)
+    if (smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP) {
+      XBT_INFO("Mixing mmap privatization is broken on FreeBSD, switching to dlopen privatization instead.");
+      smpi_privatize_global_variables = SMPI_PRIVATIZE_DLOPEN;
+    }
+#endif
 
     if (smpi_cpu_threshold < 0)
       smpi_cpu_threshold = DBL_MAX;
@@ -444,20 +499,9 @@ static void smpi_init_options(){
     }
 }
 
-static int execute_command(const char * const argv[])
-{
-  pid_t pid;
-  int status;
-  if (posix_spawnp(&pid, argv[0], nullptr, nullptr, (char* const*) argv, environ) != 0)
-    return 127;
-  if (waitpid(pid, &status, 0) != pid)
-    return 127;
-  return status;
-}
-
 typedef std::function<int(int argc, char *argv[])> smpi_entry_point_type;
 typedef int (* smpi_c_entry_point_type)(int argc, char **argv);
-typedef void (* smpi_fortran_entry_point_type)(void);
+typedef void (*smpi_fortran_entry_point_type)();
 
 static int smpi_run_entry_point(smpi_entry_point_type entry_point, std::vector<std::string> args)
 {
@@ -478,20 +522,17 @@ static int smpi_run_entry_point(smpi_entry_point_type entry_point, std::vector<s
 // TODO, remove the number of functions involved here
 static smpi_entry_point_type smpi_resolve_function(void* handle)
 {
-  smpi_fortran_entry_point_type entry_point2 =
-    (smpi_fortran_entry_point_type) dlsym(handle, "user_main_");
-  if (entry_point2 != nullptr) {
-    // fprintf(stderr, "EP user_main_=%p\n", entry_point2);
-    return [entry_point2](int argc, char** argv) {
+  smpi_fortran_entry_point_type entry_point_fortran = (smpi_fortran_entry_point_type)dlsym(handle, "user_main_");
+  if (entry_point_fortran != nullptr) {
+    return [entry_point_fortran](int argc, char** argv) {
       smpi_process_init(&argc, &argv);
-      entry_point2();
+      entry_point_fortran();
       return 0;
     };
   }
 
-  smpi_c_entry_point_type entry_point = (smpi_c_entry_point_type) dlsym(handle, "main");
+  smpi_c_entry_point_type entry_point = (smpi_c_entry_point_type)dlsym(handle, "main");
   if (entry_point != nullptr) {
-    // fprintf(stderr, "EP main=%p\n", entry_point);
     return entry_point;
   }
 
@@ -531,29 +572,31 @@ int smpi_main(const char* executable, int argc, char *argv[])
 
     std::string executable_copy = executable;
 
-    // Prepare the copy of the binary (open the file and get its size)
-    // (fdin will remain open for the whole process execution. That's a sort of leak but we can live with it)
-    int fdin = open(executable_copy.c_str(), O_RDONLY);
-    xbt_assert(fdin >= 0, "Cannot read from %s", executable_copy.c_str());
+    // Prepare the copy of the binary (get its size)
     struct stat fdin_stat;
-    fstat(fdin, &fdin_stat);
+    stat(executable_copy.c_str(), &fdin_stat);
     off_t fdin_size = fdin_stat.st_size;
 
-    simix_global->default_function = [executable_copy, fdin, fdin_size](std::vector<std::string> args) {
-      return std::function<void()>([executable_copy, fdin, fdin_size, args] {
+    simix_global->default_function = [executable_copy, fdin_size](std::vector<std::string> args) {
+      return std::function<void()>([executable_copy, fdin_size, args] {
 
         // Copy the dynamic library:
         std::string target_executable = executable_copy
           + "_" + std::to_string(getpid())
           + "_" + std::to_string(rank++) + ".so";
 
-        int fdout = open(target_executable.c_str(), O_WRONLY);
+        int fdin = open(executable_copy.c_str(), O_RDONLY);
+        xbt_assert(fdin >= 0, "Cannot read from %s", executable_copy.c_str());
+        int fdout = open(target_executable.c_str(), O_CREAT | O_RDWR, S_IRWXU);
         xbt_assert(fdout >= 0, "Cannot write into %s", target_executable.c_str());
 
 #if HAVE_SENDFILE
-        sendfile(fdout, fdin, NULL, fdin_size);
+        ssize_t sent_size = sendfile(fdout, fdin, NULL, fdin_size);
+        xbt_assert(sent_size == fdin_size,
+                   "Error while copying %s: only %zd bytes copied instead of %ld (errno: %d -- %s)",
+                   target_executable.c_str(), sent_size, fdin_size, errno, strerror(errno));
 #else
-        XBT_WARN("Copy %d bytes into %s", static_cast<int>(fdin_size), target_executable.c_str());
+        XBT_VERB("Copy %d bytes into %s", static_cast<int>(fdin_size), target_executable.c_str());
         const int bufsize = 1024 * 1024 * 4;
         char buf[bufsize];
         while (int got = read(fdin, buf, bufsize)) {
@@ -573,13 +616,15 @@ int smpi_main(const char* executable, int argc, char *argv[])
           }
         }
 #endif
+        close(fdin);
         close(fdout);
 
         // Load the copy and resolve the entry point:
         void* handle = dlopen(target_executable.c_str(), RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
-        unlink(target_executable.c_str());
+        if (xbt_cfg_get_boolean("smpi/keep-temps") == false)
+          unlink(target_executable.c_str());
         if (handle == nullptr)
-          xbt_die("dlopen failed");
+          xbt_die("dlopen failed: %s (errno: %d -- %s)", dlerror(), errno, strerror(errno));
         smpi_entry_point_type entry_point = smpi_resolve_function(handle);
         if (!entry_point)
           xbt_die("Could not resolve entry point");
@@ -594,7 +639,7 @@ int smpi_main(const char* executable, int argc, char *argv[])
     // Load the dynamic library and resolve the entry point:
     void* handle = dlopen(executable, RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
     if (handle == nullptr)
-      xbt_die("dlopen failed for %s", executable);
+      xbt_die("dlopen failed for %s: %s (errno: %d -- %s)", executable, dlerror(), errno, strerror(errno));
     smpi_entry_point_type entry_point = smpi_resolve_function(handle);
     if (!entry_point)
       xbt_die("main not found in %s", executable);