Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
context: rewrite some comments, and useless cosmetics
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Sat, 5 Jan 2019 22:28:31 +0000 (23:28 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 6 Jan 2019 00:44:50 +0000 (01:44 +0100)
src/include/xbt/parmap.hpp
src/kernel/context/ContextBoost.cpp
src/kernel/context/ContextRaw.cpp
src/kernel/context/ContextSwapped.cpp
src/kernel/context/ContextUnix.cpp

index c589364..97c03bb 100644 (file)
@@ -272,9 +272,7 @@ template <typename T> typename Parmap<T>::Synchro* Parmap<T>::new_synchro(e_xbt_
   return res;
 }
 
-/**
- * @brief Main function of a worker thread.
- */
+/** @brief Main function of a worker thread */
 template <typename T> void* Parmap<T>::worker_main(void* arg)
 {
   ThreadData* data      = static_cast<ThreadData*>(arg);
@@ -287,7 +285,7 @@ template <typename T> void* Parmap<T>::worker_main(void* arg)
 
   /* Worker's main loop */
   while (1) {
-    round++;
+    round++; // New scheduling round
     parmap.synchro->worker_wait(round);
     if (parmap.status == PARMAP_DESTROY)
       break;
index b2e2331..b3d609b 100644 (file)
@@ -21,13 +21,13 @@ BoostContextFactory::BoostContextFactory()
 {
   BoostContext::set_maestro(nullptr);
   if (parallel_)
-    ParallelBoostContext::initialize();
+    SwappedContext::initialize();
 }
 
 BoostContextFactory::~BoostContextFactory()
 {
   if (parallel_)
-    ParallelBoostContext::finalize();
+    SwappedContext::finalize();
 }
 
 smx_context_t BoostContextFactory::create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup_func,
@@ -169,8 +169,8 @@ void ParallelBoostContext::resume()
 {
   worker_id_ = threads_working_.fetch_add(1, std::memory_order_relaxed);
 
-  ParallelBoostContext* worker_context = static_cast<ParallelBoostContext*>(self());
-  workers_context_[worker_id_]         = worker_context;
+  SwappedContext* worker_context = static_cast<SwappedContext*>(self());
+  workers_context_[worker_id_]   = worker_context;
 
   Context::set_current(this);
   worker_context->swap_into(this);
index 6898c5f..9da74ac 100644 (file)
@@ -191,14 +191,14 @@ RawContextFactory::RawContextFactory() : ContextFactory("RawContextFactory"), pa
   RawContext::set_maestro(nullptr);
   if (parallel_) {
     // TODO: choose dynamically when SIMIX_context_get_parallel_threshold() > 1
-    ParallelRawContext::initialize();
+    SwappedContext::initialize();
   }
 }
 
 RawContextFactory::~RawContextFactory()
 {
   if (parallel_)
-    ParallelRawContext::finalize();
+    SwappedContext::finalize();
 }
 
 Context* RawContextFactory::create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup_func,
@@ -312,9 +312,9 @@ void ParallelRawContext::suspend()
 
 void ParallelRawContext::resume()
 {
-  worker_id_                         = threads_working_.fetch_add(1, std::memory_order_relaxed);
-  ParallelRawContext* worker_context = static_cast<ParallelRawContext*>(self());
-  workers_context_[worker_id_]       = worker_context;
+  worker_id_                     = threads_working_.fetch_add(1, std::memory_order_relaxed);
+  SwappedContext* worker_context = static_cast<SwappedContext*>(self());
+  workers_context_[worker_id_]   = worker_context;
   XBT_DEBUG("Saving worker stack %zu", worker_id_);
   Context::set_current(this);
   worker_context->swap_into(this);
index be10ff8..7bf0790 100644 (file)
@@ -141,6 +141,27 @@ SwappedContext::~SwappedContext()
   xbt_free(stack_);
 }
 
+/** Maestro wants to run all read_to_run actors */
+void SwappedContext::run_all()
+{
+  if (simix_global->process_to_run.empty())
+    return;
+  smx_actor_t first_process = simix_global->process_to_run.front();
+  process_index_            = 1;
+  /* execute the first process */
+  static_cast<SwappedContext*>(first_process->context_)->resume();
+}
+
+/** Maestro wants to yield back to a given actor */
+void SwappedContext::resume()
+{
+  // Maestro is always the calling thread of this function (ie, self() == maestro)
+  SwappedContext* old = static_cast<SwappedContext*>(self());
+  Context::set_current(this);
+  old->swap_into(this);
+}
+
+/** The actor wants to yield back to maestro */
 void SwappedContext::suspend()
 {
   /* determine the next context */
@@ -149,11 +170,11 @@ void SwappedContext::suspend()
   process_index_++;
 
   if (i < simix_global->process_to_run.size()) {
-    /* execute the next process */
+    /* Actually swap into the next actor directly without transiting to maestro */
     XBT_DEBUG("Run next process");
     next_context = static_cast<SwappedContext*>(simix_global->process_to_run[i]->context_);
   } else {
-    /* all processes were run, return to maestro */
+    /* all processes were run, actually return to maestro */
     XBT_DEBUG("No more process to run");
     next_context = static_cast<SwappedContext*>(get_maestro());
   }
@@ -161,22 +182,6 @@ void SwappedContext::suspend()
   this->swap_into(next_context);
 }
 
-void SwappedContext::resume()
-{
-  SwappedContext* old = static_cast<SwappedContext*>(self());
-  Context::set_current(this);
-  old->swap_into(this);
-}
-
-void SwappedContext::run_all()
-{
-  if (simix_global->process_to_run.empty())
-    return;
-  smx_actor_t first_process = simix_global->process_to_run.front();
-  process_index_            = 1;
-  /* execute the first process */
-  static_cast<SwappedContext*>(first_process->context_)->resume();
-}
 } // namespace context
 } // namespace kernel
 } // namespace simgrid
index 4e204b0..f7df368 100644 (file)
@@ -35,13 +35,13 @@ UContextFactory::UContextFactory() : ContextFactory("UContextFactory"), parallel
 {
   UContext::set_maestro(nullptr);
   if (parallel_)
-    ParallelUContext::initialize();
+    SwappedContext::initialize();
 }
 
 UContextFactory::~UContextFactory()
 {
   if (parallel_)
-    ParallelUContext::finalize();
+    SwappedContext::finalize();
 }
 
 Context* UContextFactory::create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup, smx_actor_t process)
@@ -151,13 +151,17 @@ void UContext::stop()
 void ParallelUContext::run_all()
 {
   threads_working_ = 0;
-  // Parmap_apply ensures that every working thread get an index in the process_to_run array (through an atomic
-  // fetch_and_add), and runs the ParallelUContext::resume function on that index
 
-  // We lazily create the parmap because the parmap creates context with simix_global->context_factory (which might not
-  // be initialized when bootstrapping):
+  // We lazily create the parmap so that all options are actually processed when doing so.
   if (parmap_ == nullptr)
     parmap_ = new simgrid::xbt::Parmap<smx_actor_t>(SIMIX_context_get_nthreads(), SIMIX_context_get_parallel_mode());
+
+  // Usually, Parmap::apply() executes the provided function on all elements of the array.
+  // Here, the executed function does not return the control to the parmap before all the array is processed:
+  //   - suspend() should switch back to the worker_context (either maestro or one of its minions) to return
+  //     the control to the parmap. Instead, it uses parmap_->next() to steal another work, and does it directly.
+  //     It only yields back to worker_context when the work array is exhausted.
+  //   - So, resume() is only launched from the parmap for the first job of each minion.
   parmap_->apply(
       [](smx_actor_t process) {
         ParallelUContext* context = static_cast<ParallelUContext*>(process->context_);
@@ -166,59 +170,58 @@ void ParallelUContext::run_all()
       simix_global->process_to_run);
 }
 
+/** Run one particular simulated process on the current thread.
+ *
+ * Only applied to the N first elements of the parmap array, where N is the amount of worker threads in the parmap.
+ * See ParallelUContext::run_all for details.
+ */
+void ParallelUContext::resume()
+{
+  // Save the thread number (my body) in an os-thread-specific area
+  worker_id_ = threads_working_.fetch_add(1, std::memory_order_relaxed);
+  // Save my current soul (either maestro, or one of the minions) in a permanent area
+  SwappedContext* worker_context = static_cast<SwappedContext*>(self());
+  workers_context_[worker_id_]   = worker_context;
+  // Switch my soul and the actor's one
+  Context::set_current(this);
+  worker_context->swap_into(this);
+  // No body runs that soul anymore at this point, but it is stored in a safe place.
+  // When the executed actor will do a blocking action, SIMIX_process_yield() will call suspend(), below.
+}
+
 /** Yield
  *
- * This function is called when a simulated process wants to yield back to the maestro in a blocking simcall. This
- * naturally occurs within SIMIX_context_suspend(self->context), called from SIMIX_process_yield() Actually, it does not
- * really yield back to maestro, but into the next process that must be executed. If no one is to be executed, then it
- * yields to the initial soul that was in this working thread (that was saved in resume_parallel).
+ * This function is called when a simulated process wants to yield back to the maestro in a blocking simcall,
+ * ie in SIMIX_process_yield().
+ *
+ * Actually, it does not really yield back to maestro, but directly into the next executable actor.
+ *
+ * This makes the parmap::apply awkward (see ParallelUContext::run_all()) because it only apply regularly
+ * on the few first elements of the array, but it saves a lot of context switches back to maestro,
+ * and directly forth to the next executable actor.
  */
 void ParallelUContext::suspend()
 {
-  /* determine the next context */
-  // Get the next soul to embody now:
+  // Get some more work to directly swap into the next executable actor instead of yielding back to the parmap
   boost::optional<smx_actor_t> next_work = parmap_->next();
   SwappedContext* next_context;
   if (next_work) {
-    // There is a next soul to embody (ie, a next process to resume)
+    // There is a next soul to embody (ie, another executable actor)
     XBT_DEBUG("Run next process");
     next_context = static_cast<ParallelUContext*>(next_work.get()->context_);
   } else {
-    // All processes were run, go to the barrier
+    // All actors were run, go back to the parmap context
     XBT_DEBUG("No more processes to run");
     // worker_id_ is the identity of my body, stored in thread_local when starting the scheduling round
-    // Deduce the initial soul of that body
     next_context = workers_context_[worker_id_];
     // When given that soul, the body will wait for the next scheduling round
   }
 
+  // Get the next soul to run, either from another actor or the initial minion's one
   Context::set_current(next_context);
-  // Get the next soul to run, either simulated or initial minion's one:
   this->swap_into(next_context);
 }
 
-/** Run one particular simulated process on the current thread. */
-void ParallelUContext::resume()
-{
-  // What is my containing body? Store its number in os-thread-specific area :
-  worker_id_ = threads_working_.fetch_add(1, std::memory_order_relaxed);
-  // Get my current soul:
-  ParallelUContext* worker_context = static_cast<ParallelUContext*>(self());
-  // Write down that this soul is hosted in that body (for now)
-  workers_context_[worker_id_] = worker_context;
-  // Write in simix that I switched my soul
-  Context::set_current(this);
-  // Actually do that using the relevant library call:
-  worker_context->swap_into(this);
-  // No body runs that soul anymore at this point.  Instead the current body took the soul of simulated process The
-  // simulated process wakes back after the call to "SIMIX_context_suspend(self->context);" within
-  // smx_process.c::SIMIX_process_yield()
-
-  // From now on, the simulated processes will change their soul with the next soul to execute (in suspend_parallel,
-  // below).  When nobody is to be executed in this scheduling round, the last simulated process will take back the
-  // initial soul of the current working thread
-}
-
 XBT_PRIVATE ContextFactory* sysv_factory()
 {
   XBT_VERB("Activating SYSV context factory");