Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of framagit.org:simgrid/simgrid
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Wed, 10 May 2023 21:22:28 +0000 (23:22 +0200)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Wed, 10 May 2023 21:22:28 +0000 (23:22 +0200)
16 files changed:
ChangeLog
docs/source/Tutorial_DAG.rst
examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
examples/cpp/operation-simple/s4u-operation-simple.cpp
examples/cpp/operation-switch-host/s4u-operation-switch-host.cpp
examples/cpp/operation-variable-load/s4u-operation-variable-load.cpp
examples/python/clusters-multicpu/clusters-multicpu.py
include/simgrid/plugins/operation.hpp
include/xbt/config.hpp
src/mc/api/State.cpp
src/mc/explo/udpor/Unfolding.hpp
src/mc/explo/udpor/maximal_subsets_iterator.hpp
src/plugins/operation.cpp
src/xbt/utils/iter/powerset.hpp
src/xbt/utils/iter/subsets_tests.cpp
src/xbt/utils/iter/variable_for_loop.hpp

index a713a6b..d68448e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -21,6 +21,16 @@ S4U:
  - Allow to set a concurrency limit on disks and hosts, as it was already the case for links.
  - Rename Link::get_usage() to Link::get_load() for consistency with Host::
 
+New plugin: Operation
+ - Operations are designed to represent workflows, i.e, graphs of repeatable Activities.
+ - Documentation: https://simgrid.frama.io/simgrid/Plugins.html#operation
+ - Examples: examples/cpp/operation-*
+
+New plugin: Battery
+ - Enable the management of batteries on hosts.
+ - Documentation: https://simgrid.frama.io/simgrid/Plugins.html#battery
+ - Examples: examples/cpp/battery-*
+  
 Kernel:
  - optimize an internal datastructure (use a set instead of a list for ongoing activities),
    leading to a potentially big performance gain, in particular with many detached comms.
index 621eaf2..37217f2 100644 (file)
@@ -148,6 +148,7 @@ The execution of this code should give you the following output:
 .. literalinclude:: ../../examples/cpp/dag-tuto/s4u-dag-tuto.tesh
    :language: none
    :lines: 4-
+
 Lab 2: Import a DAG from a file
 -------------------------------
 
@@ -214,3 +215,196 @@ It can be imported as a vector of Activities into Simgrid using :cpp:func:`simgr
 
 .. literalinclude:: ../../examples/cpp/dag-from-dax-simple/s4u-dag-from-dax-simple.cpp
    :language: cpp
+
+Lab 3: Scheduling with the Min-Min algorithm
+--------------------------------------------
+
+In this lab we present how to schedule activities imported from a DAX file using the 
+`Min-Min algorithm <https://www.researchgate.net/figure/The-Traditional-Min-Min-Scheduling-Algorithm_fig5_236346423>`_.
+
+The source code for this lab can be found `here <https://framagit.org/simgrid/simgrid/-/blob/stable/examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp>`_.
+
+For code readability we first create the `sg4` namespace.
+
+.. code-block:: cpp
+
+   namespace sg4 = simgrid::s4u;
+
+The core mechanism of the algorithm lies in three functions. 
+They respectively serve the purpose of finding tasks to schedule, 
+finding the best host to execute them and properly scheduling them.
+
+Find Tasks to Schedule
+......................
+
+The role of this function is to retrieve tasks that are ready to be scheduled, i.e, that have their dependencies solved.
+
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 15-38
+
+Find the Best Placement
+.......................
+
+Once we have a task ready to be scheduled, we need to find the best placement for it.
+This is done by evaluating the earliest finish time among all hosts.
+It depends on the duration of the data transfers of the parents of this task to this host.
+
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 40-91
+
+Schedule a Task
+...............
+
+When the best host has been found, the task is scheduled on it:
+
+* it sets the host of the task to schedule
+* it stores the finish time of this task on the host
+* it sets the destination of parents communication
+* it sets the source of any child communication.
+
+.. literalinclude:: ../../examples/cpp/dag-scheduling/s4u-dag-scheduling.cpp
+   :language: cpp
+   :lines: 93-113
+
+Mixing it all Together
+......................
+
+Now that we have the key components of the algorithm let's merge them inside the main function.
+
+.. code-block:: cpp
+
+   int main(int argc, char** argv)
+   {
+   ...
+
+First, we initialize the Simgrid Engine.
+
+.. code-block:: cpp
+
+   sg4::Engine e(&argc, argv);
+
+The Min-Min algorithm schedules unscheduled tasks. 
+To keep track of them we make use of the method :cpp:func:`simgrid::s4u::Engine::track_vetoed_activities`.
+
+.. code-block:: cpp
+
+   std::set<sg4::Activity*> vetoed;
+   e.track_vetoed_activities(&vetoed);
+
+We add the following callback that will be triggered at the end of execution activities.
+This callback stores the finish time of the execution, 
+to use it as a start time for any subsequent communications.
+
+.. code-block:: cpp
+
+  sg4::Activity::on_completion_cb([](sg4::Activity const& activity) {
+    // when an Exec completes, we need to set the potential start time of all its ouput comms
+    const auto* exec = dynamic_cast<sg4::Exec const*>(&activity);
+    if (exec == nullptr) // Only Execs are concerned here
+      return;
+    for (const auto& succ : exec->get_successors()) {
+      auto* comm = dynamic_cast<sg4::Comm*>(succ.get());
+      if (comm != nullptr) {
+        auto* finish_time = new double(exec->get_finish_time());
+        // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential start
+        // time
+        comm->set_data(finish_time);
+      }
+    }
+  });
+
+We load the platform and force sequential execution on hosts.
+
+.. code-block:: cpp
+
+   e.load_platform(argv[1]);
+
+  /* Mark all hosts as sequential, as it ought to be in such a scheduling example.
+   *
+   * It means that the hosts can only compute one thing at a given time. If an execution already takes place on a given
+   * host, any subsequently started execution will be queued until after the first execution terminates */
+  for (auto const& host : e.get_all_hosts()) {
+    host->set_concurrency_limit(1);
+    host->set_data(new double(0.0));
+  }
+
+The tasks are imported from a DAX file.
+
+.. code-block:: cpp
+
+  /* load the DAX file */
+  auto dax = sg4::create_DAG_from_DAX(argv[2]);
+
+We look for the best host for the root task and schedule it. 
+We then advance the simulation to unlock next schedulable tasks.
+
+.. code-block:: cpp
+
+  /* Schedule the root first */
+  double finish_time;
+  auto* root = static_cast<sg4::Exec*>(dax.front().get());
+  auto host  = get_best_host(root, &finish_time);
+  schedule_on(root, host);
+  e.run();
+
+Then, we get to the major loop of the algorithm.
+This loop goes on until all tasks have been scheduled and executed.
+It starts by finding ready tasks using `get_ready_tasks`. 
+It iteratively looks for the task that will finish first among ready tasks using `get_best_host`, and place it using `schedule_on`. 
+When no more tasks can be placed, we advance the simulation.
+
+.. code-block:: cpp
+
+  while (not vetoed.empty()) {
+    XBT_DEBUG("Start new scheduling round");
+    /* Get the set of ready tasks */
+    auto ready_tasks = get_ready_tasks(dax);
+    vetoed.clear();
+
+    if (ready_tasks.empty()) {
+      /* there is no ready exec, let advance the simulation */
+      e.run();
+      continue;
+    }
+    /* For each ready exec:
+     * get the host that minimizes the completion time.
+     * select the exec that has the minimum completion time on its best host.
+     */
+    double min_finish_time   = std::numeric_limits<double>::max();
+    sg4::Exec* selected_task = nullptr;
+    sg4::Host* selected_host = nullptr;
+
+    for (auto exec : ready_tasks) {
+      XBT_DEBUG("%s is ready", exec->get_cname());
+      double finish_time;
+      host = get_best_host(exec, &finish_time);
+      if (finish_time < min_finish_time) {
+        min_finish_time = finish_time;
+        selected_task   = exec;
+        selected_host   = host;
+      }
+    }
+
+    XBT_INFO("Schedule %s on %s", selected_task->get_cname(), selected_host->get_cname());
+    schedule_on(selected_task, selected_host, min_finish_time);
+
+    ready_tasks.clear();
+    e.run();
+  }
+
+Finally, we clean up the memory.
+
+.. code-block:: cpp
+
+   /* Cleanup memory */
+   for (auto const& h : e.get_all_hosts())
+     delete h->get_data<double>();
+
+
+
+
+
+
+
index c61f83f..5386b58 100644 (file)
@@ -37,57 +37,56 @@ static std::vector<sg4::Exec*> get_ready_tasks(const std::vector<sg4::ActivityPt
   return ready_tasks;
 }
 
-static double finish_on_at(const sg4::ExecPtr task, const sg4::Host* host)
-{
-  double data_available      = 0.;
-  double last_data_available = -1.0;
-  /* compute last_data_available */
-  for (const auto& parent : task->get_dependencies()) {
-    /* normal case */
-    if (const auto* comm = dynamic_cast<sg4::Comm*>(parent.get())) {
-      auto source = comm->get_source();
-      XBT_DEBUG("transfer from %s to %s", source->get_cname(), host->get_cname());
-      /* Estimate the redistribution time from this parent */
-      double redist_time;
-      if (comm->get_remaining() <= 1e-6) {
-        redist_time = 0;
-      } else {
-        double bandwidth      = std::numeric_limits<double>::max();
-        auto [links, latency] = source->route_to(host);
-        for (auto const& link : links)
-          bandwidth = std::min(bandwidth, link->get_bandwidth());
-
-        redist_time = latency + comm->get_remaining() / bandwidth;
-      }
-      // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential start
-      // time
-      data_available = *comm->get_data<double>() + redist_time;
-    }
-
-    /* no transfer, control dependency */
-    if (const auto* exec = dynamic_cast<sg4::Exec*>(parent.get()))
-      data_available = exec->get_finish_time();
-
-    if (last_data_available < data_available)
-      last_data_available = data_available;
-  }
-  return std::max(*host->get_data<double>(), last_data_available) + task->get_remaining() / host->get_speed();
-}
-
-static sg4::Host* get_best_host(const sg4::ExecPtr exec)
+static sg4::Host* get_best_host(const sg4::ExecPtr exec, double* min_finish_time)
 {
   sg4::Host* best_host = nullptr;
-  double min_EFT = std::numeric_limits<double>::max();
+  *min_finish_time = std::numeric_limits<double>::max();
 
   for (const auto& host : sg4::Engine::get_instance()->get_all_hosts()) {
-    double EFT = finish_on_at(exec, host);
-    XBT_DEBUG("%s finishes on %s at %f", exec->get_cname(), host->get_cname(), EFT);
+    double data_available      = 0.;
+    double last_data_available = -1.0;
+    /* compute last_data_available */
+    for (const auto& parent : exec->get_dependencies()) {
+      /* normal case */
+      if (const auto* comm = dynamic_cast<sg4::Comm*>(parent.get())) {
+        auto source = comm->get_source();
+        XBT_DEBUG("transfer from %s to %s", source->get_cname(), host->get_cname());
+        /* Estimate the redistribution time from this parent */
+        double redist_time;
+        if (comm->get_remaining() <= 1e-6) {
+          redist_time = 0;
+        } else {
+          double bandwidth      = std::numeric_limits<double>::max();
+          auto [links, latency] = source->route_to(host);
+          for (auto const& link : links)
+            bandwidth = std::min(bandwidth, link->get_bandwidth());
+
+          redist_time = latency + comm->get_remaining() / bandwidth;
+        }
+        // We use the user data field to store the finish time of the predecessor of the comm, i.e., its potential
+        // start time
+        data_available = *comm->get_data<double>() + redist_time;
+     }
+
+      /* no transfer, control dependency */
+      if (const auto* exec = dynamic_cast<sg4::Exec*>(parent.get()))
+        data_available = exec->get_finish_time();
+
+      if (last_data_available < data_available)
+        last_data_available = data_available;
+    }
 
-    if (EFT < min_EFT) {
-      min_EFT   = EFT;
-      best_host = host;
+    double finish_time = std::max(*host->get_data<double>(), last_data_available) +
+                         exec->get_remaining() / host->get_speed();
+
+    XBT_DEBUG("%s finishes on %s at %f", exec->get_cname(), host->get_cname(), finish_time);
+
+    if (finish_time < *min_finish_time) {
+      *min_finish_time = finish_time;
+      best_host        = host;
     }
   }
+
   return best_host;
 }
 
@@ -149,8 +148,9 @@ int main(int argc, char** argv)
   auto dax = sg4::create_DAG_from_DAX(argv[2]);
 
   /* Schedule the root first */
+  double finish_time;
   auto* root = static_cast<sg4::Exec*>(dax.front().get());
-  auto host  = get_best_host(root);
+  auto host  = get_best_host(root, &finish_time);
   schedule_on(root, host);
 
   e.run();
@@ -162,25 +162,25 @@ int main(int argc, char** argv)
     vetoed.clear();
 
     if (ready_tasks.empty()) {
-      /* there is no ready task, let advance the simulation */
+      /* there is no ready exec, let advance the simulation */
       e.run();
       continue;
     }
-    /* For each ready task:
+    /* For each ready exec:
      * get the host that minimizes the completion time.
-     * select the task that has the minimum completion time on its best host.
+     * select the exec that has the minimum completion time on its best host.
      */
-    double min_finish_time            = -1.0;
-    sg4::Exec* selected_task          = nullptr;
-    sg4::Host* selected_host          = nullptr;
-
-    for (auto task : ready_tasks) {
-      XBT_DEBUG("%s is ready", task->get_cname());
-      host               = get_best_host(task);
-      double finish_time = finish_on_at(task, host);
-      if (min_finish_time < 0 || finish_time < min_finish_time) {
+    double min_finish_time   = std::numeric_limits<double>::max();
+    sg4::Exec* selected_task = nullptr;
+    sg4::Host* selected_host = nullptr;
+
+    for (auto exec : ready_tasks) {
+      XBT_DEBUG("%s is ready", exec->get_cname());
+      double finish_time;
+      host = get_best_host(exec, &finish_time);
+      if (finish_time < min_finish_time) {
         min_finish_time = finish_time;
-        selected_task   = task;
+        selected_task   = exec;
         selected_host   = host;
       }
     }
index 70656e8..40a32b2 100644 (file)
@@ -38,7 +38,7 @@ int main(int argc, char* argv[])
   comm->add_successor(exec2);
 
   // Add a function to be called when operations end for log purpose
-  simgrid::plugins::Operation::on_end_cb([](simgrid::plugins::Operation* op) {
+  simgrid::plugins::Operation::on_end_cb([](const simgrid::plugins::Operation* op) {
     XBT_INFO("Operation %s finished (%d)", op->get_name().c_str(), op->get_count());
   });
 
index f8c183d..10b0b4c 100644 (file)
@@ -28,9 +28,9 @@ int main(int argc, char* argv[])
   simgrid::plugins::Operation::init();
 
   // Retrieve hosts
-  auto tremblay = e.host_by_name("Tremblay");
-  auto jupiter  = e.host_by_name("Jupiter");
-  auto fafard   = e.host_by_name("Fafard");
+  auto* tremblay = e.host_by_name("Tremblay");
+  auto* jupiter  = e.host_by_name("Jupiter");
+  auto* fafard   = e.host_by_name("Fafard");
 
   // Create operations
   auto comm0 = simgrid::plugins::CommOp::init("comm0");
@@ -47,15 +47,16 @@ int main(int argc, char* argv[])
   exec2->add_successor(comm2);
 
   // Add a function to be called when operations end for log purpose
-  simgrid::plugins::Operation::on_end_cb([](simgrid::plugins::Operation* op) {
+  simgrid::plugins::Operation::on_end_cb([](const simgrid::plugins::Operation* op) {
     XBT_INFO("Operation %s finished (%d)", op->get_name().c_str(), op->get_count());
   });
 
   // Add a function to be called before each executions of comm0
   // This function modifies the graph of operations by adding or removing
   // successors to comm0
-  int count = 0;
-  comm0->on_this_start([&](simgrid::plugins::Operation* op) {
+  comm0->on_this_start([exec1, exec2, jupiter, fafard](simgrid::plugins::Operation* op) {
+    auto* comm0      = dynamic_cast<simgrid::plugins::CommOp*>(op);
+    static int count = 0;
     if (count % 2 == 0) {
       comm0->set_destination(jupiter);
       comm0->add_successor(exec1);
index 9eea3da..02938b5 100644 (file)
@@ -51,7 +51,7 @@ int main(int argc, char* argv[])
   comm->add_successor(exec);
 
   // Add a function to be called when operations end for log purpose
-  simgrid::plugins::Operation::on_end_cb([](simgrid::plugins::Operation* op) {
+  simgrid::plugins::Operation::on_end_cb([](const simgrid::plugins::Operation* op) {
     XBT_INFO("Operation %s finished (%d)", op->get_name().c_str(), op->get_count());
   });
 
index 8f7240a..79ee80c 100644 (file)
@@ -101,7 +101,7 @@ def create_hostzone(zone: simgrid.NetZone, coord: typing.List[int], ident: int)
         host = host_zone.create_host(cpu_name, speed).seal()
         # the first CPU is the gateway
         if i == 0:
-            gateway = host
+            gateway = host.netpoint
         # create split-duplex link
         link = host_zone.create_split_duplex_link("link-" + cpu_name, link_bw)
         link.set_latency(link_lat).seal()
@@ -111,7 +111,7 @@ def create_hostzone(zone: simgrid.NetZone, coord: typing.List[int], ident: int)
 
     # seal newly created netzone
     host_zone.seal()
-    return host_zone.netpoint, gateway.netpoint
+    return host_zone.netpoint, gateway
 
 #####################################################################################################
 
index 0f2f0e6..6725466 100644 (file)
@@ -4,6 +4,7 @@
 #include <simgrid/s4u/Activity.hpp>
 #include <xbt/Extendable.hpp>
 
+#include <atomic>
 #include <map>
 #include <memory>
 #include <set>
 namespace simgrid::plugins {
 
 class Operation;
-using OperationPtr = std::shared_ptr<Operation>;
+using OperationPtr = boost::intrusive_ptr<Operation>;
+XBT_PUBLIC void intrusive_ptr_release(Operation* o);
+XBT_PUBLIC void intrusive_ptr_add_ref(Operation* o);
 class ExecOp;
-using ExecOpPtr = std::shared_ptr<ExecOp>;
+using ExecOpPtr = boost::intrusive_ptr<ExecOp>;
+XBT_PUBLIC void intrusive_ptr_release(ExecOp* e);
+XBT_PUBLIC void intrusive_ptr_add_ref(ExecOp* e);
 class CommOp;
-using CommOpPtr = std::shared_ptr<CommOp>;
+using CommOpPtr =  boost::intrusive_ptr<CommOp>;
+XBT_PUBLIC void intrusive_ptr_release(CommOp* c);
+XBT_PUBLIC void intrusive_ptr_add_ref(CommOp* c);
 
-class ExtendedAttributeActivity {
-public:
+struct ExtendedAttributeActivity {
   static simgrid::xbt::Extension<simgrid::s4u::Activity, ExtendedAttributeActivity> EXTENSION_ID;
   Operation* operation_;
-
-  ExtendedAttributeActivity(){};
 };
 
 class Operation {
@@ -43,26 +47,29 @@ protected:
   int queued_execs_ = 0;
   int count_        = 0;
   bool working_     = false;
-  simgrid::s4u::ActivityPtr current_activity_;
+  s4u::ActivityPtr current_activity_;
   std::function<void(Operation*)> end_func_;
   std::function<void(Operation*)> start_func_;
-  Operation(const std::string& name);
+  explicit Operation(const std::string& name);
   virtual ~Operation()   = default;
   virtual void execute() = 0;
 
   static xbt::signal<void(Operation*)> on_start;
   static xbt::signal<void(Operation*)> on_end;
+  std::atomic_int_fast32_t refcount_{0};
 
 public:
   static void init();
-  std::string get_name();
+  const std::string& get_name() const { return name_; }
+  const char* get_cname() const { return name_.c_str(); }
   void enqueue_execs(int n);
   void set_amount(double amount);
+  double get_amount() const { return amount_; }
   void add_successor(OperationPtr op);
   void remove_successor(OperationPtr op);
-  void on_this_start(std::function<void(Operation*)> func);
-  void on_this_end(std::function<void(Operation*)> func);
-  int get_count();
+  void on_this_start(const std::function<void(Operation*)>& func);
+  void on_this_end(const std::function<void(Operation*)>& func);
+  int get_count() const;
 
   /** Add a callback fired before an operation activity start.
    * Triggered after the on_this_start function**/
@@ -71,37 +78,58 @@ public:
    * Triggered after the on_this_end function, but before
    * sending tokens to successors.**/
   static void on_end_cb(const std::function<void(Operation*)>& cb) { on_end.connect(cb); }
+
+#ifndef DOXYGEN
+  friend void intrusive_ptr_release(Operation* o)
+  {
+    if (o->refcount_.fetch_sub(1, std::memory_order_release) == 1) {
+      std::atomic_thread_fence(std::memory_order_acquire);
+      delete o;
+    }
+  }
+  friend void intrusive_ptr_add_ref(Operation* o) { o->refcount_.fetch_add(1, std::memory_order_relaxed); }
+#endif
 };
 
 class ExecOp : public Operation {
 private:
-  simgrid::s4u::Host* host_;
+  s4u::Host* host_;
 
-  ExecOp(const std::string& name);
+  explicit ExecOp(const std::string& name);
   void execute() override;
 
 public:
   static ExecOpPtr init(const std::string& name);
-  static ExecOpPtr init(const std::string& name, double flops, simgrid::s4u::Host* host);
-  void set_host(simgrid::s4u::Host* host);
-  void set_flops(double flops);
+  static ExecOpPtr init(const std::string& name, double flops, s4u::Host* host);
+  ExecOpPtr set_host(s4u::Host* host);
+  s4u::Host* get_host() const { return host_; }
+  ExecOpPtr set_flops(double flops);
+  double get_flops() const { return get_amount(); }
+  friend void inline intrusive_ptr_release(ExecOp* e) { intrusive_ptr_release(static_cast<Operation*>(e)); }
+  friend void inline intrusive_ptr_add_ref(ExecOp* e) { intrusive_ptr_add_ref(static_cast<Operation*>(e)); }
 };
 
 class CommOp : public Operation {
 private:
-  simgrid::s4u::Host* source_;
-  simgrid::s4u::Host* destination_;
+  s4u::Host* source_;
+  s4u::Host* destination_;
 
-  CommOp(const std::string& name);
+  explicit CommOp(const std::string& name);
   void execute() override;
 
 public:
   static CommOpPtr init(const std::string& name);
-  static CommOpPtr init(const std::string& name, double bytes, simgrid::s4u::Host* source,
-                        simgrid::s4u::Host* destination);
-  void set_source(simgrid::s4u::Host* source);
-  void set_destination(simgrid::s4u::Host* destination);
-  void set_bytes(double bytes);
+  static CommOpPtr init(const std::string& name, double bytes, s4u::Host* source,
+                        s4u::Host* destination);
+  CommOpPtr set_source(s4u::Host* source);
+  s4u::Host* get_source() const { return source_; }
+  CommOpPtr set_destination(s4u::Host* destination);
+  s4u::Host* get_destination() const { return destination_; }
+  CommOpPtr set_bytes(double bytes);
+  double get_bytes() const { return get_amount(); }
+   friend void inline intrusive_ptr_release(CommOp* c) { intrusive_ptr_release(static_cast<Operation*>(c)); }
+  friend void inline intrusive_ptr_add_ref(CommOp* c) { intrusive_ptr_add_ref(static_cast<Operation*>(c)); }
+
 };
 } // namespace simgrid::plugins
 #endif
index 4cf17bf..372ec9b 100644 (file)
@@ -92,10 +92,10 @@ XBT_PUBLIC void alias(const char* realname, std::initializer_list<const char*> a
  */
 template <class T>
 XBT_PUBLIC void declare_flag(const std::string& name, const std::string& description, T value,
-                             std::function<void(const T&)> callback = std::function<void(const T&)>());
+                             std::function<void(const T&)> callback = nullptr);
 template <class T>
 void declare_flag(const std::string& name, std::initializer_list<const char*> aliases, const std::string& description,
-                  T value, std::function<void(const T&)> callback = std::function<void(const T&)>())
+                  T value, std::function<void(const T&)> callback = nullptr)
 {
   declare_flag(name, description, std::move(value), std::move(callback));
   alias(name.c_str(), aliases);
@@ -265,7 +265,7 @@ public:
        const std::map<std::string, std::string, std::less<>>& valid_values)
       : value_(value), name_(name)
   {
-    simgrid::config::bind_flag(value_, name, desc, valid_values, [](std::string) {});
+    simgrid::config::bind_flag(value_, name, desc, valid_values, [](const std::string&) {});
   }
 
   /* As earlier, a constructor accepting a map of valid values -> their description,
index 0366a31..34a41d6 100644 (file)
@@ -94,7 +94,7 @@ std::size_t State::count_todo_multiples() const
 std::deque<Transition*>& State::get_recipe()
 {
   if (recipe_.empty()) {
-    for (auto* s = this; s != nullptr; s = s->get_parent_state().get())
+    for (const auto* s = this; s != nullptr; s = s->get_parent_state().get())
       if (s->get_transition_in() != nullptr)
         recipe_.push_front(s->get_transition_in().get());
   }
index 140c893..3fa80f2 100644 (file)
@@ -73,7 +73,7 @@ public:
    * to an equivalent event that was already noted by the unfolding
    * at some point in the past
    */
-  template <typename... Args> const UnfoldingEvent* discover_event(Args... args)
+  template <typename... Args> const UnfoldingEvent* discover_event(Args&&... args)
   {
     auto candidate_event = std::make_unique<UnfoldingEvent>(std::forward<Args>(args)...);
     return insert(std::move(candidate_event));
index d172eda..2c3c07f 100644 (file)
@@ -58,7 +58,7 @@ private:
   bool has_started_searching                              = false;
   std::optional<size_t> maximum_subset_size               = std::nullopt;
   std::optional<EventSet> current_maximal_set             = std::nullopt;
-  std::stack<topological_order_position> backtrack_points = std::stack<topological_order_position>();
+  std::stack<topological_order_position, std::vector<topological_order_position>> backtrack_points;
 
   /**
    * @brief A small class which provides functionality for managing
index 0629065..ce34fe6 100644 (file)
@@ -31,11 +31,6 @@ xbt::signal<void(Operation*)> Operation::on_end;
 
 Operation::Operation(const std::string& name) : name_(name) {}
 
-std::string Operation::get_name()
-{
-  return name_;
-}
-
 /**
  *  @param predecessor The Operation to add.
  *  @brief Add a predecessor to this Operation.
@@ -124,7 +119,7 @@ void Operation::init()
     return;
   Operation::inited_                      = true;
   ExtendedAttributeActivity::EXTENSION_ID = simgrid::s4u::Activity::extension_create<ExtendedAttributeActivity>();
-  simgrid::s4u::Activity::on_completion_cb([&](simgrid::s4u::Activity const& activity) {
+  simgrid::s4u::Activity::on_completion_cb([](simgrid::s4u::Activity const& activity) {
     activity.extension<ExtendedAttributeActivity>()->operation_->complete();
   });
 }
@@ -180,9 +175,9 @@ void Operation::remove_successor(OperationPtr successor)
  *  @brief Set a function to be called before each execution.
  *  @note The function is called before the underlying Activity starts.
  */
-void Operation::on_this_start(std::function<void(Operation*)> func)
+void Operation::on_this_start(const std::function<void(Operation*)>& func)
 {
-  simgrid::kernel::actor::simcall_answered([this, func] { start_func_ = func; });
+  simgrid::kernel::actor::simcall_answered([this, &func] { start_func_ = func; });
 }
 
 /** @ingroup plugin_operation
@@ -190,15 +185,15 @@ void Operation::on_this_start(std::function<void(Operation*)> func)
  *  @brief Set a function to be called after each execution.
  *  @note The function is called after the underlying Activity ends, but before sending tokens to successors.
  */
-void Operation::on_this_end(std::function<void(Operation*)> func)
+void Operation::on_this_end(const std::function<void(Operation*)>& func)
 {
-  simgrid::kernel::actor::simcall_answered([this, func] { end_func_ = func; });
+  simgrid::kernel::actor::simcall_answered([this, &func] { end_func_ = func; });
 }
 
 /** @ingroup plugin_operation
  *  @brief Return the number of completed executions.
  */
-int Operation::get_count()
+int Operation::get_count() const
 {
   return count_;
 }
@@ -213,19 +208,15 @@ ExecOp::ExecOp(const std::string& name) : Operation(name) {}
  */
 ExecOpPtr ExecOp::init(const std::string& name)
 {
-  auto op = ExecOpPtr(new ExecOp(name));
-  return op;
+  return ExecOpPtr(new ExecOp(name));
 }
 
 /** @ingroup plugin_operation
  *  @brief Smart Constructor.
  */
-ExecOpPtr ExecOp::init(const std::string& name, double flops, simgrid::s4u::Host* host)
+ExecOpPtr ExecOp::init(const std::string& name, double flops, s4u::Host* host)
 {
-  auto op = ExecOpPtr(new ExecOp(name));
-  op->set_flops(flops);
-  op->set_host(host);
-  return op;
+  return init(name)->set_flops(flops)->set_host(host);
 }
 
 /**
@@ -238,35 +229,37 @@ void ExecOp::execute()
   if (start_func_)
     start_func_(this);
   Operation::on_start(this);
-  simgrid::kernel::actor::simcall_answered([this] {
+  kernel::actor::simcall_answered([this] {
     working_      = true;
     queued_execs_ = std::max(queued_execs_ - 1, 0);
   });
-  simgrid::s4u::ExecPtr exec = simgrid::s4u::Exec::init();
+  s4u::ExecPtr exec = s4u::Exec::init();
   exec->set_name(name_);
   exec->set_flops_amount(amount_);
   exec->set_host(host_);
   exec->start();
   exec->extension_set(new ExtendedAttributeActivity());
   exec->extension<ExtendedAttributeActivity>()->operation_ = this;
-  simgrid::kernel::actor::simcall_answered([this, exec] { current_activity_ = exec; });
+  kernel::actor::simcall_answered([this, exec] { current_activity_ = exec; });
 }
 
 /** @ingroup plugin_operation
  *  @param host The host to set.
  *  @brief Set a new host.
  */
-void ExecOp::set_host(simgrid::s4u::Host* host)
+ExecOpPtr ExecOp::set_host(s4u::Host* host)
 {
-  simgrid::kernel::actor::simcall_answered([this, host] { host_ = host; });
+  kernel::actor::simcall_answered([this, host] { host_ = host; });
+  return this;
 }
 
 /** @ingroup plugin_operation
  *  @param flops The amount of flops to set.
  */
-void ExecOp::set_flops(double flops)
+ExecOpPtr ExecOp::set_flops(double flops)
 {
-  simgrid::kernel::actor::simcall_answered([this, flops] { amount_ = flops; });
+  kernel::actor::simcall_answered([this, flops] { amount_ = flops; });
+  return this;
 }
 
 /**
@@ -279,21 +272,16 @@ CommOp::CommOp(const std::string& name) : Operation(name) {}
  */
 CommOpPtr CommOp::init(const std::string& name)
 {
-  auto op = CommOpPtr(new CommOp(name));
-  return op;
+  return CommOpPtr(new CommOp(name));
 }
 
 /** @ingroup plugin_operation
  *  @brief Smart constructor.
  */
-CommOpPtr CommOp::init(const std::string& name, double bytes, simgrid::s4u::Host* source,
-                       simgrid::s4u::Host* destination)
+CommOpPtr CommOp::init(const std::string& name, double bytes, s4u::Host* source,
+                       s4u::Host* destination)
 {
-  auto op = CommOpPtr(new CommOp(name));
-  op->set_bytes(bytes);
-  op->set_source(source);
-  op->set_destination(destination);
-  return op;
+  return init(name)->set_bytes(bytes)->set_source(source)->set_destination(destination);
 }
 
 /**
@@ -306,43 +294,46 @@ void CommOp::execute()
   if (start_func_)
     start_func_(this);
   Operation::on_start(this);
-  simgrid::kernel::actor::simcall_answered([this] {
+  kernel::actor::simcall_answered([this] {
     working_      = true;
     queued_execs_ = std::max(queued_execs_ - 1, 0);
   });
-  simgrid::s4u::CommPtr comm = simgrid::s4u::Comm::sendto_init(source_, destination_);
+  s4u::CommPtr comm = s4u::Comm::sendto_init(source_, destination_);
   comm->set_name(name_);
   comm->set_payload_size(amount_);
   comm->start();
   comm->extension_set(new ExtendedAttributeActivity());
   comm->extension<ExtendedAttributeActivity>()->operation_ = this;
-  simgrid::kernel::actor::simcall_answered([this, comm] { current_activity_ = comm; });
+  kernel::actor::simcall_answered([this, comm] { current_activity_ = comm; });
 }
 
 /** @ingroup plugin_operation
  *  @param source The host to set.
  *  @brief Set a new source host.
  */
-void CommOp::set_source(simgrid::s4u::Host* source)
+CommOpPtr CommOp::set_source(s4u::Host* source)
 {
-  simgrid::kernel::actor::simcall_answered([this, source] { source_ = source; });
+  kernel::actor::simcall_answered([this, source] { source_ = source; });
+  return this;
 }
 
 /** @ingroup plugin_operation
  *  @param destination The host to set.
  *  @brief Set a new destination host.
  */
-void CommOp::set_destination(simgrid::s4u::Host* destination)
+CommOpPtr CommOp::set_destination(s4u::Host* destination)
 {
-  simgrid::kernel::actor::simcall_answered([this, destination] { destination_ = destination; });
+  kernel::actor::simcall_answered([this, destination] { destination_ = destination; });
+  return this;
 }
 
 /** @ingroup plugin_operation
  *  @param bytes The amount of bytes to set.
  */
-void CommOp::set_bytes(double bytes)
+CommOpPtr CommOp::set_bytes(double bytes)
 {
-  simgrid::kernel::actor::simcall_answered([this, bytes] { amount_ = bytes; });
+  kernel::actor::simcall_answered([this, bytes] { amount_ = bytes; });
+  return this;
 }
 
 } // namespace simgrid::plugins
index d7b2cdf..b83bad7 100644 (file)
@@ -40,8 +40,6 @@ private:
   std::optional<subsets_iterator<Iterator>> current_subset_iter     = std::nullopt;
   std::optional<subsets_iterator<Iterator>> current_subset_iter_end = std::nullopt;
 
-  const std::vector<Iterator> empty_subset = std::vector<Iterator>();
-
   // boost::iterator_facade<...> interface to implement
   void increment();
   bool equal(const powerset_iterator<Iterator>& other) const;
@@ -70,6 +68,7 @@ template <typename Iterator> const std::vector<Iterator>& powerset_iterator<Iter
   if (current_subset_iter.has_value()) {
     return *current_subset_iter.value();
   }
+  static const std::vector<Iterator> empty_subset;
   return empty_subset;
 }
 
index 41bdf41..59c95ae 100644 (file)
@@ -65,8 +65,8 @@ TEST_CASE("simgrid::xbt::powerset_iterator: Iteration General Properties")
       }
     }
 
-    for (const auto& iter : element_counts) {
-      REQUIRE(iter.second == expected_count);
+    for (const auto& [_, count] : element_counts) {
+      REQUIRE(count == expected_count);
     }
   }
 }
@@ -187,4 +187,4 @@ TEST_CASE("simgrid::xbt::variable_for_loop: Edge Cases")
               (outer_loop1.size() * outer_loop2.size() * outer_loop3.size() * outer_loop4.size() * outer_loop5.size()));
     }
   }
-}
\ No newline at end of file
+}
index bd5d29a..cbcb0a2 100644 (file)
@@ -85,11 +85,11 @@ template <typename IterableType> void variable_for_loop<IterableType>::increment
 
   for (auto j = k; j != std::numeric_limits<size_t>::max(); j--) {
     // Attempt to move to the next element of the `j`th collection
-    const auto& new_position = ++current_subset[j];
+    ++current_subset[j];
 
     // If the `j`th element has reached its own end, reset it
     // back to the beginning and keep moving forward
-    if (new_position == underlying_collections[j].get().cend()) {
+    if (current_subset[j] == underlying_collections[j].get().cend()) {
       current_subset[j] = underlying_collections[j].get().cbegin();
     } else {
       // Otherwise we've found the largest element which needed to