Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Setup argc/argv for the Fortran run-time environment only once.
[simgrid.git] / src / smpi / internals / smpi_global.cpp
index e267174..db19072 100644 (file)
@@ -4,6 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "mc/mc.h"
+#include "simgrid/Exception.hpp"
 #include "simgrid/plugins/file_system.h"
 #include "simgrid/s4u/Engine.hpp"
 #include "smpi_coll.hpp"
@@ -12,7 +13,6 @@
 #include "smpi_host.hpp"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
-#include "src/simix/smx_private.hpp"
 #include "src/smpi/include/smpi_actor.hpp"
 #include "xbt/config.hpp"
 #include "xbt/file.hpp"
@@ -77,8 +77,6 @@ static std::vector<std::string> privatize_libs_paths;
 // No instance gets manually created; check also the smpirun.in script as
 // this default name is used there as well (when the <actor> tag is generated).
 static const std::string smpi_default_instance_name("smpirun");
-static simgrid::config::Flag<double> smpi_init_sleep(
-  "smpi/init", "Time to inject inside a call to MPI_Init", 0.0);
 
 static simgrid::config::Flag<std::string>
     smpi_hostfile("smpi/hostfile",
@@ -230,57 +228,61 @@ static void smpi_init_papi()
   // the configuration as given by the user (counter data as a pair of (counter_name, counter_counter))
   // and the (computed) event_set.
 
-  if (not smpi_cfg_papi_events_file().empty()) {
-    if (PAPI_library_init(PAPI_VER_CURRENT) != PAPI_VER_CURRENT)
-      XBT_ERROR("Could not initialize PAPI library; is it correctly installed and linked?"
-                " Expected version is %u", PAPI_VER_CURRENT);
-
-    using Tokenizer = boost::tokenizer<boost::char_separator<char>>;
-    boost::char_separator<char> separator_units(";");
-    std::string str = smpi_cfg_papi_events_file();
-    Tokenizer tokens(str, separator_units);
-
-    // Iterate over all the computational units. This could be processes, hosts, threads, ranks... You name it.
-    // I'm not exactly sure what we will support eventually, so I'll leave it at the general term "units".
-    for (auto const& unit_it : tokens) {
-      boost::char_separator<char> separator_events(":");
-      Tokenizer event_tokens(unit_it, separator_events);
-
-      int event_set = PAPI_NULL;
-      if (PAPI_create_eventset(&event_set) != PAPI_OK) {
-        // TODO: Should this let the whole simulation die?
-        XBT_CRITICAL("Could not create PAPI event set during init.");
-      }
+  if (smpi_cfg_papi_events_file().empty())
+    return;
 
-      // NOTE: We cannot use a map here, as we must obey the order of the counters
-      // This is important for PAPI: We need to map the values of counters back to the event_names (so, when PAPI_read()
-      // has finished)!
-      papi_counter_t counters2values;
-
-      // Iterate over all counters that were specified for this specific unit.
-      // Note that we need to remove the name of the unit (that could also be the "default" value), which always comes
-      // first. Hence, we start at ++(events.begin())!
-      for (Tokenizer::iterator events_it = ++(event_tokens.begin()); events_it != event_tokens.end(); ++events_it) {
-        int event_code   = PAPI_NULL;
-        auto* event_name = const_cast<char*>((*events_it).c_str());
-        if (PAPI_event_name_to_code(event_name, &event_code) != PAPI_OK) {
-          XBT_CRITICAL("Could not find PAPI event '%s'. Skipping.", event_name);
-          continue;
-        }
-        if (PAPI_add_event(event_set, event_code) != PAPI_OK) {
-          XBT_ERROR("Could not add PAPI event '%s'. Skipping.", event_name);
-          continue;
-        }
-        XBT_DEBUG("Successfully added PAPI event '%s' to the event set.", event_name);
+  if (PAPI_library_init(PAPI_VER_CURRENT) != PAPI_VER_CURRENT) {
+    XBT_ERROR("Could not initialize PAPI library; is it correctly installed and linked? Expected version is %u",
+              PAPI_VER_CURRENT);
+    return;
+  }
 
-        counters2values.emplace_back(*events_it, 0LL);
-      }
+  using Tokenizer = boost::tokenizer<boost::char_separator<char>>;
+  boost::char_separator<char> separator_units(";");
+  std::string str = smpi_cfg_papi_events_file();
+  Tokenizer tokens(str, separator_units);
+
+  // Iterate over all the computational units. This could be processes, hosts, threads, ranks... You name it.
+  // I'm not exactly sure what we will support eventually, so I'll leave it at the general term "units".
+  for (auto const& unit_it : tokens) {
+    boost::char_separator<char> separator_events(":");
+    Tokenizer event_tokens(unit_it, separator_events);
+
+    int event_set = PAPI_NULL;
+    if (PAPI_create_eventset(&event_set) != PAPI_OK) {
+      // TODO: Should this let the whole simulation die?
+      XBT_CRITICAL("Could not create PAPI event set during init.");
+      break;
+    }
 
-      std::string unit_name    = *(event_tokens.begin());
-      papi_process_data config = {.counter_data = std::move(counters2values), .event_set = event_set};
+    // NOTE: We cannot use a map here, as we must obey the order of the counters
+    // This is important for PAPI: We need to map the values of counters back to the event_names (so, when PAPI_read()
+    // has finished)!
+    papi_counter_t counters2values;
+
+    // Iterate over all counters that were specified for this specific unit.
+    // Note that we need to remove the name of the unit (that could also be the "default" value), which always comes
+    // first. Hence, we start at ++(events.begin())!
+    for (Tokenizer::iterator events_it = ++(event_tokens.begin()); events_it != event_tokens.end(); ++events_it) {
+      int event_code   = PAPI_NULL;
+      auto* event_name = const_cast<char*>((*events_it).c_str());
+      if (PAPI_event_name_to_code(event_name, &event_code) != PAPI_OK) {
+        XBT_CRITICAL("Could not find PAPI event '%s'. Skipping.", event_name);
+        continue;
+      }
+      if (PAPI_add_event(event_set, event_code) != PAPI_OK) {
+        XBT_ERROR("Could not add PAPI event '%s'. Skipping.", event_name);
+        continue;
+      }
+      XBT_DEBUG("Successfully added PAPI event '%s' to the event set.", event_name);
 
-      units2papi_setup.insert(std::make_pair(unit_name, std::move(config)));
+      counters2values.emplace_back(*events_it, 0LL);
     }
+
+    std::string unit_name    = *(event_tokens.begin());
+    papi_process_data config = {.counter_data = std::move(counters2values), .event_set = event_set};
+
+    units2papi_setup.insert(std::make_pair(unit_name, std::move(config)));
   }
 #endif
 }
@@ -290,52 +292,41 @@ using smpi_c_entry_point_type       = int (*)(int argc, char** argv);
 using smpi_fortran_entry_point_type = void (*)();
 
 template <typename F>
-static int smpi_run_entry_point(const F& entry_point, const std::string& executable_path, std::vector<std::string> args)
+static int smpi_run_entry_point(const F& entry_point, const std::string& executable_path,
+                                const std::vector<std::string>& args)
 {
   // copy C strings, we need them writable
-  auto* args4argv = new std::vector<char*>(args.size());
-  std::transform(begin(args), end(args), begin(*args4argv), [](const std::string& s) { return xbt_strdup(s.c_str()); });
+  std::vector<char*> args4argv(args.size());
+  std::transform(begin(args) + 1, end(args), begin(args4argv) + 1,
+                 [](const std::string& s) { return xbt_strdup(s.c_str()); });
 
   // set argv[0] to executable_path
-  xbt_free((*args4argv)[0]);
-  (*args4argv)[0] = xbt_strdup(executable_path.c_str());
+  args4argv[0] = xbt_strdup(executable_path.c_str());
+  // add the final NULL
+  args4argv.push_back(nullptr);
 
-#if !SMPI_IFORT
   // take a copy of args4argv to keep reference of the allocated strings
-  const std::vector<char*> args2str(*args4argv);
-#endif
-  int argc = args4argv->size();
-  args4argv->push_back(nullptr);
-  char** argv = args4argv->data();
-
-#if SMPI_IFORT
-  for_rtl_init_ (&argc, argv);
-#elif SMPI_FLANG
-  __io_set_argc(argc);
-  __io_set_argv(argv);
-#elif SMPI_GFORTRAN
-  _gfortran_set_args(argc, argv);
-#endif 
-  int res = entry_point(argc, argv);
+  const std::vector<char*> args2str(args4argv);
+
+  try {
+    int argc    = static_cast<int>(args4argv.size() - 1);
+    char** argv = args4argv.data();
+    int res = entry_point(argc, argv);
+    if (res != 0) {
+      XBT_WARN("SMPI process did not return 0. Return value : %d", res);
+      if (smpi_exit_status == 0)
+        smpi_exit_status = res;
+    }
+  } catch (simgrid::ForcefulKillException const& e) {
+    XBT_DEBUG("Caught a ForcefulKillException: %s", e.what());
+  }
 
-#if SMPI_IFORT
-  for_rtl_finish_ ();
-#else
   for (char* s : args2str)
     xbt_free(s);
-  delete args4argv;
-#endif
 
-  if (res != 0){
-    XBT_WARN("SMPI process did not return 0. Return value : %d", res);
-    if (smpi_exit_status == 0)
-      smpi_exit_status = res;
-  }
   return 0;
 }
 
-
-// TODO, remove the number of functions involved here
 static smpi_entry_point_type smpi_resolve_function(void* handle)
 {
   auto* entry_point_fortran = reinterpret_cast<smpi_fortran_entry_point_type>(dlsym(handle, "user_main_"));
@@ -380,17 +371,17 @@ static void smpi_copy_file(const std::string& src, const std::string& target, of
   while (ssize_t got = read(fdin, buf.data(), buf.size())) {
     if (got == -1) {
       xbt_assert(errno == EINTR, "Cannot read from %s", src.c_str());
-    } else {
-      const unsigned char* p = buf.data();
-      ssize_t todo           = got;
-      while (ssize_t done = write(fdout, p, todo)) {
-        if (done == -1) {
-          xbt_assert(errno == EINTR, "Cannot write into %s", target.c_str());
-        } else {
-          p += done;
-          todo -= done;
-        }
+      continue;
+    }
+    const unsigned char* p = buf.data();
+    ssize_t todo           = got;
+    while (ssize_t done = write(fdout, p, todo)) {
+      if (done == -1) {
+        xbt_assert(errno == EINTR, "Cannot write into %s", target.c_str());
+        continue;
       }
+      p += done;
+      todo -= done;
     }
   }
   close(fdin);
@@ -443,7 +434,7 @@ static void smpi_init_privatization_dlopen(const std::string& executable)
   }
 
   simgrid::s4u::Engine::get_instance()->register_default([executable, fdin_size](std::vector<std::string> args) {
-    return std::function<void()>([executable, fdin_size, args] {
+    return simgrid::kernel::actor::ActorCode([executable, fdin_size, args = std::move(args)] {
       static std::size_t rank = 0;
       // Copy the dynamic library:
       simgrid::xbt::Path path(executable);
@@ -468,7 +459,7 @@ static void smpi_init_privatization_dlopen(const std::string& executable)
 
           // Copy the dynamic library, the new name must be the same length as the old one
           // just replace the name with 7 digits for the rank and the rest of the name.
-          auto pad                   = std::min<unsigned>(7, libname.length());
+          auto pad                   = std::min<size_t>(7, libname.length());
           std::string target_libname = std::string(pad - std::to_string(rank).length(), '0') + std::to_string(rank) + libname.substr(pad);
           std::string target_lib = simgrid::config::get_value<std::string>("smpi/tmpdir") + "/" + target_libname;
           target_libs.push_back(target_lib);
@@ -519,7 +510,7 @@ static void smpi_init_privatization_no_dlopen(const std::string& executable)
 
   // Execute the same entry point for each simulated process:
   simgrid::s4u::Engine::get_instance()->register_default([entry_point, executable](std::vector<std::string> args) {
-    return std::function<void()>([entry_point, executable, args] {
+    return simgrid::kernel::actor::ActorCode([entry_point, executable, args = std::move(args)] {
       if (smpi_cfg_privatization() == SmpiPrivStrategies::MMAP) {
         simgrid::smpi::ActorExt* ext = smpi_process();
         /* Now using the segment index of this process  */
@@ -541,15 +532,12 @@ int smpi_main(const char* executable, int argc, char* argv[])
   }
 
   smpi_init_options_internal(true);
-  simgrid::instr::init();
-  SIMIX_global_init(&argc, argv);
-
-  auto engine              = simgrid::s4u::Engine::get_instance();
+  simgrid::s4u::Engine engine(&argc, argv);
 
   sg_storage_file_system_init();
   // parse the platform file: get the host list
-  engine->load_platform(argv[1]);
-  simgrid::kernel::activity::CommImpl::set_copy_data_callback(smpi_comm_copy_buffer_callback);
+  engine.load_platform(argv[1]);
+  engine.set_default_comm_data_copy_callback(smpi_comm_copy_buffer_callback);
 
   if (smpi_cfg_privatization() == SmpiPrivStrategies::DLOPEN)
     smpi_init_privatization_dlopen(executable);
@@ -558,11 +546,27 @@ int smpi_main(const char* executable, int argc, char* argv[])
 
   simgrid::smpi::colls::set_collectives();
   simgrid::smpi::colls::smpi_coll_cleanup_callback = nullptr;
-  
+
+  std::vector<char*> args4argv(argv + 1, argv + argc + 1); // last element is NULL
+  args4argv[0]     = xbt_strdup(executable);
+  int real_argc    = argc - 1;
+  char** real_argv = args4argv.data();
+
+  // Setup argc/argv for the Fortran run-time environment
+#if SMPI_IFORT
+  for_rtl_init_(&real_argc, real_argv);
+#elif SMPI_FLANG
+  __io_set_argc(real_argc);
+  __io_set_argv(real_argv);
+#elif SMPI_GFORTRAN
+  _gfortran_set_args(real_argc, real_argv);
+#endif
+
   SMPI_init();
 
-  int rank_counts = smpi_deployment_smpirun(engine, smpi_hostfile.get(), smpi_np.get(), smpi_replay.get(),
-                                            smpi_map.get(), argc - 2, argv + 2);
+  const std::vector<const char*> args(real_argv + 1, real_argv + real_argc);
+  int rank_counts =
+      smpi_deployment_smpirun(&engine, smpi_hostfile.get(), smpi_np.get(), smpi_replay.get(), smpi_map.get(), args);
 
   SMPI_app_instance_register(smpi_default_instance_name.c_str(), nullptr, rank_counts);
   MPI_COMM_WORLD = *smpi_deployment_comm_world(smpi_default_instance_name);
@@ -574,13 +578,18 @@ int smpi_main(const char* executable, int argc, char* argv[])
   if (MC_is_active()) {
     MC_run();
   } else {
-    simgrid::kernel::EngineImpl::get_instance()->run();
+    engine.get_impl()->run();
 
     xbt_os_walltimer_stop(global_timer);
     simgrid::smpi::utils::print_time_analysis(xbt_os_timer_elapsed(global_timer));
   }
   SMPI_finalize();
 
+#if SMPI_IFORT
+  for_rtl_finish_();
+#endif
+  xbt_free(args4argv[0]);
+
   return smpi_exit_status;
 }
 
@@ -627,11 +636,23 @@ void SMPI_finalize()
 
 void smpi_mpi_init() {
   smpi_init_fortran_types();
-  if(smpi_init_sleep > 0)
-    simgrid::s4u::this_actor::sleep_for(smpi_init_sleep);
+  if(_smpi_init_sleep > 0)
+    simgrid::s4u::this_actor::sleep_for(_smpi_init_sleep);
+  if (not MC_is_active()) {
+    smpi_deployment_startup_barrier(smpi_process()->get_instance_id());
+  }
 }
 
 void SMPI_thread_create() {
   TRACE_smpi_init(simgrid::s4u::this_actor::get_pid(), __func__);
   smpi_process()->mark_as_initialized();
 }
+
+void smpi_exit(int res){
+  if(res != 0){
+    XBT_WARN("SMPI process did not return 0. Return value : %d", res);
+    smpi_exit_status = res;
+  }
+  simgrid::s4u::this_actor::exit();
+  THROW_IMPOSSIBLE;
+}