Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Objectify SD_task_t
authorSUTER Frederic <frederic.suter@cc.in2p3.fr>
Fri, 12 Nov 2021 19:15:46 +0000 (20:15 +0100)
committerSUTER Frederic <frederic.suter@cc.in2p3.fr>
Fri, 12 Nov 2021 19:15:46 +0000 (20:15 +0100)
include/simgrid/simdag.h
src/simdag/sd_daxloader.cpp
src/simdag/sd_dotloader.cpp
src/simdag/sd_global.cpp
src/simdag/sd_task.cpp
src/simdag/simdag_private.hpp

index cfabc7b..3b6ffad 100644 (file)
 
 #ifdef __cplusplus
 #include <set>
+
+namespace simgrid {
+namespace sd {
+class Task;
+XBT_PUBLIC std::set<Task*>* simulate(double how_long);
+} // namespace sd
+} // namespace simgrid
+
+using sg_sd_Task = simgrid::sd::Task;
+#else
+typedef struct sd_Task sg_sd_Task;
 #endif
 
-SG_BEGIN_DECL
+#ifdef __cplusplus
+extern "C" {
+#endif
 
 /** @brief Link opaque datatype
     @ingroup SD_link_api
@@ -34,8 +47,8 @@ typedef sg_link_t SD_link_t;
     Each task has a <em>@ref e_SD_task_state_t "state"</em> indicating whether the task is scheduled, running, done, ...
 
     */
-typedef struct s_SD_task_t* SD_task_t;
-typedef const struct s_SD_task_t* const_SD_task_t;
+typedef sg_sd_Task* SD_task_t;
+typedef const sg_sd_Task* const_SD_task_t;
 
 /** @brief Task states
     @ingroup SD_task_api */
@@ -196,13 +209,7 @@ XBT_PUBLIC xbt_dynar_t SD_PTG_dotload(const char* filename);
 //SD_route_get_size
 //SD_route_get_list
 //TRACE_sd_set_task_category
-SG_END_DECL
-
 #ifdef __cplusplus
-namespace simgrid {
-namespace sd {
-XBT_PUBLIC std::set<SD_task_t>* simulate(double how_long);
-}
 }
 #endif
 
index af8a699..5608da5 100644 (file)
@@ -21,8 +21,8 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_daxparse, sd, "Parsing DAX files");
 /* Ensure that transfer tasks have unique names even though a file is used several times */
 void uniq_transfer_task_name(SD_task_t task)
 {
-  const_SD_task_t child  = *(task->successors->begin());
-  const_SD_task_t parent = *(task->predecessors->begin());
+  const_SD_task_t child  = *(task->get_successors().begin());
+  const_SD_task_t parent = *(task->get_predecessors().begin());
 
   std::string new_name =
       std::string(SD_task_get_name(parent)) + "_" + SD_task_get_name(task) + "_" + SD_task_get_name(child);
@@ -32,17 +32,18 @@ void uniq_transfer_task_name(SD_task_t task)
 
 static bool children_are_marked(const_SD_task_t task)
 {
-  return std::none_of(task->successors->begin(), task->successors->end(),
-                      [](const SD_task_t& elm) { return not elm->marked; }) &&
-         std::none_of(task->outputs->begin(), task->outputs->end(),
-                      [](const SD_task_t& elm) { return not elm->marked; });
+  return std::none_of(task->get_successors().begin(), task->get_successors().end(),
+                      [](const SD_task_t& elm) { return not elm->is_marked(); }) &&
+         std::none_of(task->get_outputs().begin(), task->get_outputs().end(),
+                      [](const SD_task_t& elm) { return not elm->is_marked(); });
 }
 
 static bool parents_are_marked(const_SD_task_t task)
 {
-  return std::none_of(task->predecessors->begin(), task->predecessors->end(),
-                      [](const SD_task_t& elm) { return not elm->marked; }) &&
-         std::none_of(task->inputs->begin(), task->inputs->end(), [](const SD_task_t& elm) { return not elm->marked; });
+  return std::none_of(task->get_predecessors().begin(), task->get_predecessors().end(),
+                      [](const SD_task_t& elm) { return not elm->is_marked(); }) &&
+         std::none_of(task->get_inputs().begin(), task->get_inputs().end(),
+                      [](const SD_task_t& elm) { return not elm->is_marked(); });
 }
 
 bool acyclic_graph_detail(const_xbt_dynar_t dag)
@@ -51,22 +52,22 @@ bool acyclic_graph_detail(const_xbt_dynar_t dag)
   SD_task_t task = nullptr;
   std::vector<SD_task_t> current;
   xbt_dynar_foreach (dag, count, task)
-    if (task->kind != SD_TASK_COMM_E2E && task->successors->empty() && task->outputs->empty())
+    if (task->get_kind() != SD_TASK_COMM_E2E && task->get_successors().empty() && task->get_outputs().empty())
       current.push_back(task);
 
   while (not current.empty()) {
     std::vector<SD_task_t> next;
     for (auto const& t : current) {
       //Mark task
-      t->marked = true;
-      for (SD_task_t const& input : *t->inputs) {
-        input->marked = true;
+      t->mark();
+      for (SD_task_t const& input : t->get_inputs()) {
+        input->mark();
         // Inputs are communication, hence they can have only one predecessor
-        SD_task_t input_pred = *(input->predecessors->begin());
+        SD_task_t input_pred = *(input->get_predecessors().begin());
         if (children_are_marked(input_pred))
           next.push_back(input_pred);
       }
-      for (SD_task_t const& pred : *t->predecessors) {
+      for (SD_task_t const& pred : t->get_predecessors()) {
         if (children_are_marked(pred))
           next.push_back(pred);
       }
@@ -78,8 +79,8 @@ bool acyclic_graph_detail(const_xbt_dynar_t dag)
   bool all_marked = true;
   //test if all tasks are marked
   xbt_dynar_foreach(dag,count,task){
-    if (task->kind != SD_TASK_COMM_E2E && not task->marked) {
-      XBT_WARN("the task %s is not marked",task->name);
+    if (task->get_kind() != SD_TASK_COMM_E2E && not task->is_marked()) {
+      XBT_WARN("the task %s is not marked", task->get_cname());
       all_marked = false;
       break;
     }
@@ -88,8 +89,8 @@ bool acyclic_graph_detail(const_xbt_dynar_t dag)
   if (not all_marked) {
     XBT_VERB("there is at least one cycle in your task graph");
     xbt_dynar_foreach(dag,count,task){
-      if(task->kind != SD_TASK_COMM_E2E && task->predecessors->empty() && task->inputs->empty()){
-        task->marked = true;
+      if (task->get_kind() != SD_TASK_COMM_E2E && task->get_predecessors().empty() && task->get_inputs().empty()) {
+        task->mark();
         current.push_back(task);
       }
     }
@@ -98,15 +99,15 @@ bool acyclic_graph_detail(const_xbt_dynar_t dag)
       std::vector<SD_task_t> next;
       //test if the current iteration is done
       for (auto const& t : current) {
-        t->marked = true;
-        for (SD_task_t const& output : *t->outputs) {
-          output->marked = true;
+        t->mark();
+        for (SD_task_t const& output : t->get_outputs()) {
+          output->mark();
           // outputs are communication, hence they can have only one successor
-          SD_task_t output_succ = *(output->successors->begin());
+          SD_task_t output_succ = *(output->get_successors().begin());
           if (parents_are_marked(output_succ))
             next.push_back(output_succ);
         }
-        for (SD_task_t const& succ : *t->successors) {
+        for (SD_task_t const& succ : t->get_successors()) {
           if (parents_are_marked(succ))
             next.push_back(succ);
         }
@@ -117,8 +118,8 @@ bool acyclic_graph_detail(const_xbt_dynar_t dag)
 
     all_marked = true;
     xbt_dynar_foreach(dag,count,task){
-      if (task->kind != SD_TASK_COMM_E2E && not task->marked) {
-        XBT_WARN("the task %s is in a cycle",task->name);
+      if (task->get_kind() != SD_TASK_COMM_E2E && not task->is_marked()) {
+        XBT_WARN("the task %s is in a cycle", task->get_cname());
         all_marked = false;
       }
     }
@@ -149,7 +150,7 @@ xbt_dynar_t SD_daxload(const char *filename)
   result              = xbt_dynar_new(sizeof(SD_task_t), nullptr);
   SD_task_t root_task = SD_task_create_comp_seq("root", nullptr, 0);
   /* by design the root task is always SCHEDULABLE */
-  SD_task_set_state(root_task, SD_SCHEDULABLE);
+  root_task->set_state(SD_SCHEDULABLE);
 
   xbt_dynar_push(result, &root_task);
   SD_task_t end_task = SD_task_create_comp_seq("end", nullptr, 0);
@@ -168,30 +169,30 @@ xbt_dynar_t SD_daxload(const char *filename)
   for (auto const& elm : files) {
     file = elm.second;
     SD_task_t newfile;
-    if (file->predecessors->empty()) {
-      for (SD_task_t const& it : *file->successors) {
-        newfile = SD_task_create_comm_e2e(file->name, nullptr, file->amount);
+    if (file->get_predecessors().empty()) {
+      for (SD_task_t const& it : file->get_successors()) {
+        newfile = SD_task_create_comm_e2e(file->get_cname(), nullptr, file->get_amount());
         SD_task_dependency_add(root_task, newfile);
         SD_task_dependency_add(newfile, it);
         xbt_dynar_push(result, &newfile);
       }
     }
-    if (file->successors->empty()) {
-      for (SD_task_t const& it : *file->predecessors) {
-        newfile = SD_task_create_comm_e2e(file->name, nullptr, file->amount);
+    if (file->get_successors().empty()) {
+      for (SD_task_t const& it : file->get_predecessors()) {
+        newfile = SD_task_create_comm_e2e(file->get_cname(), nullptr, file->get_amount());
         SD_task_dependency_add(it, newfile);
         SD_task_dependency_add(newfile, end_task);
         xbt_dynar_push(result, &newfile);
       }
     }
-    for (SD_task_t const& it : *file->predecessors) {
-      for (SD_task_t const& it2 : *file->successors) {
+    for (SD_task_t const& it : file->get_predecessors()) {
+      for (SD_task_t const& it2 : file->get_successors()) {
         if (it == it2) {
           XBT_WARN("File %s is produced and consumed by task %s."
                    "This loop dependency will prevent the execution of the task.",
-                   file->name, it->name);
+                   file->get_cname(), it->get_cname());
         }
-        newfile = SD_task_create_comm_e2e(file->name, nullptr, file->amount);
+        newfile = SD_task_create_comm_e2e(file->get_cname(), nullptr, file->get_amount());
         SD_task_dependency_add(it, newfile);
         SD_task_dependency_add(newfile, it2);
         xbt_dynar_push(result, &newfile);
@@ -213,9 +214,9 @@ xbt_dynar_t SD_daxload(const char *filename)
        * if they don't produce files, connect them to the end node.
        */
       if ((file != root_task) && (file != end_task)) {
-        if (file->inputs->empty())
+        if (file->get_inputs().empty())
           SD_task_dependency_add(root_task, file);
-        if (file->outputs->empty())
+        if (file->get_outputs().empty())
           SD_task_dependency_add(file, end_task);
       }
     }
@@ -278,16 +279,16 @@ void STag_dax__uses()
     files[A_dax__uses_file] = file;
   } else {
     file = it->second;
-    if (file->amount < size || file->amount > size) {
-      XBT_WARN("Ignore file %s size redefinition from %.0f to %.0f", A_dax__uses_file, SD_task_get_amount(file), size);
+    if (file->get_amount() < size || file->get_amount() > size) {
+      XBT_WARN("Ignore file %s size redefinition from %.0f to %.0f", A_dax__uses_file, file->get_amount(), size);
     }
   }
   if (is_input) {
     SD_task_dependency_add(file, current_job);
   } else {
     SD_task_dependency_add(current_job, file);
-    if ((file->predecessors->size() + file->inputs->size()) > 1) {
-      XBT_WARN("File %s created at more than one location...", file->name);
+    if (file->has_unsolved_dependencies() > 1) {
+      XBT_WARN("File %s created at more than one location...", file->get_cname());
     }
   }
 }
@@ -315,11 +316,11 @@ void STag_dax__parent()
   if (job != jobs.end()) {
     SD_task_t parent = job->second;
     SD_task_dependency_add(parent, current_child);
-    XBT_DEBUG("Control-flow dependency from %s to %s", current_child->name, parent->name);
+    XBT_DEBUG("Control-flow dependency from %s to %s", current_child->get_cname(), parent->get_cname());
   } else {
     throw std::out_of_range(std::string("Parse error on line ") + std::to_string(dax_lineno) +
-                            ": Asked to add a dependency from " + current_child->name + " to " + A_dax__parent_ref +
-                            ", but " + A_dax__parent_ref + " does not exist");
+                            ": Asked to add a dependency from " + current_child->get_name() + " to " +
+                            A_dax__parent_ref + ", but " + A_dax__parent_ref + " does not exist");
   }
 }
 
index 99f1bf1..1ad743a 100644 (file)
@@ -93,7 +93,7 @@ xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool sched
 
         if ((performer != -1 && order != -1) && performer < static_cast<int>(sg_host_count())) {
           /* required parameters are given and less performers than hosts are required */
-          XBT_DEBUG ("Task '%s' is scheduled on workstation '%d' in position '%d'", task->name, performer, order);
+          XBT_DEBUG("Task '%s' is scheduled on workstation '%d' in position '%d'", task->get_cname(), performer, order);
           auto comp = computers.find(char_performer);
           if (comp != computers.end()) {
             computer = comp->second;
@@ -102,12 +102,12 @@ xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool sched
             computers.insert({char_performer, computer});
           }
           if (static_cast<unsigned int>(order) < computer->size()) {
-            const s_SD_task_t* task_test = computer->at(order);
+            const_SD_task_t task_test = computer->at(order);
             if (task_test && task_test != task) {
               /* the user gave the same order to several tasks */
               schedule_success = false;
               XBT_VERB("Task '%s' wants to start on performer '%s' at the same position '%s' as task '%s'",
-                       task_test->name, char_performer, char_order, task->name);
+                       task_test->get_cname(), char_performer, char_order, task->get_cname());
               continue;
             }
           } else
@@ -117,7 +117,7 @@ xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool sched
         } else {
           /* one of required parameters is not given */
           schedule_success = false;
-          XBT_VERB("The schedule is ignored, task '%s' can not be scheduled on %d hosts", task->name, performer);
+          XBT_VERB("The schedule is ignored, task '%s' can not be scheduled on %d hosts", task->get_cname(), performer);
         }
       }
     } else {
@@ -132,7 +132,7 @@ xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool sched
   else
     root = jobs.at("root");
 
-  SD_task_set_state(root, SD_SCHEDULABLE);   /* by design the root task is always SCHEDULABLE */
+  root->set_state(SD_SCHEDULABLE);           /* by design the root task is always SCHEDULABLE */
   xbt_dynar_insert_at(result, 0, &root);     /* Put it at the beginning of the dynar */
 
   if (jobs.find("end") == jobs.end())
@@ -180,19 +180,19 @@ xbt_dynar_t SD_dotload_generic(const char* filename, bool sequential, bool sched
     }
   }
 
-  XBT_DEBUG("All tasks have been created, put %s at the end of the dynar", end->name);
+  XBT_DEBUG("All tasks have been created, put %s at the end of the dynar", end->get_cname());
   xbt_dynar_push(result, &end);
 
   /* Connect entry tasks to 'root', and exit tasks to 'end'*/
   unsigned i;
   xbt_dynar_foreach (result, i, task){
-    if (task->predecessors->empty() && task->inputs->empty() && task != root) {
-      XBT_DEBUG("Task '%s' has no source. Add dependency from 'root'", task->name);
+    if (task->has_unsolved_dependencies() == 0 && task != root) {
+      XBT_DEBUG("Task '%s' has no source. Add dependency from 'root'", task->get_cname());
       SD_task_dependency_add(root, task);
     }
 
-    if (task->successors->empty() && task->outputs->empty() && task != end) {
-      XBT_DEBUG("Task '%s' has no destination. Add dependency to 'end'", task->name);
+    if (task->is_waited_by() == 0 && task != end) {
+      XBT_DEBUG("Task '%s' has no destination. Add dependency to 'end'", task->get_cname());
       SD_task_dependency_add(task, end);
     }
   }
index 8c7b9f7..3112880 100644 (file)
@@ -21,17 +21,17 @@ std::unique_ptr<simgrid::sd::Global> sd_global = nullptr;
 namespace simgrid {
 namespace sd {
 
-std::set<SD_task_t>* simulate(double how_long)
+std::set<Task*>* simulate(double how_long)
 {
   XBT_VERB("Run simulation for %f seconds", how_long);
+
   auto engine = sd_global->engine_->get_impl();
-  simgrid::kernel::EngineImpl::get_instance();
   sd_global->watch_point_reached = false;
   sd_global->return_set.clear();
 
   /* explore the runnable tasks */
   while (not sd_global->runnable_tasks.empty())
-    SD_task_run(*(sd_global->runnable_tasks.begin()));
+    (*(sd_global->runnable_tasks.begin()))->run();
 
   double elapsed_time = 0.0;
   double total_time   = 0.0;
@@ -47,60 +47,32 @@ std::set<SD_task_t>* simulate(double how_long)
 
     /* let's see which tasks are done */
     for (auto const& model : engine->get_all_models()) {
-      const simgrid::kernel::resource::Action* action = model->extract_done_action();
+      const kernel::resource::Action* action = model->extract_done_action();
       while (action != nullptr && action->get_data() != nullptr) {
-        auto* task = static_cast<SD_task_t>(action->get_data());
-        XBT_VERB("Task '%s' done", SD_task_get_name(task));
-        SD_task_set_state(task, SD_DONE);
+        auto* task = static_cast<Task*>(action->get_data());
+        XBT_VERB("Task '%s' done", task->get_cname());
+        task->set_state(SD_DONE);
 
         /* the state has changed. Add it only if it's the first change */
         sd_global->return_set.emplace(task);
 
         /* remove the dependencies after this task */
-        for (auto const& succ : *task->successors) {
-          succ->predecessors->erase(task);
-          succ->inputs->erase(task);
-          XBT_DEBUG("Release dependency on %s: %zu remain(s). Becomes schedulable if %zu=0", SD_task_get_name(succ),
-                    succ->predecessors->size() + succ->inputs->size(), succ->predecessors->size());
-
-          if (SD_task_get_state(succ) == SD_NOT_SCHEDULED && succ->predecessors->empty())
-            SD_task_set_state(succ, SD_SCHEDULABLE);
-
-          if (SD_task_get_state(succ) == SD_SCHEDULED && succ->predecessors->empty() && succ->inputs->empty())
-            SD_task_set_state(succ, SD_RUNNABLE);
-
-          if (SD_task_get_state(succ) == SD_RUNNABLE && not sd_global->watch_point_reached)
-            SD_task_run(succ);
-        }
-        task->successors->clear();
-
-        for (auto const& output : *task->outputs) {
-          output->start_time = task->finish_time;
-          output->predecessors->erase(task);
-          if (SD_task_get_state(output) == SD_SCHEDULED)
-            SD_task_set_state(output, SD_RUNNABLE);
-          else
-            SD_task_set_state(output, SD_SCHEDULABLE);
-
-          SD_task_t comm_dst = *(output->successors->begin());
-          if (SD_task_get_state(comm_dst) == SD_NOT_SCHEDULED && comm_dst->predecessors->empty()) {
-            XBT_DEBUG("%s is a transfer, %s may be ready now if %zu=0", SD_task_get_name(output),
-                      SD_task_get_name(comm_dst), comm_dst->predecessors->size());
-            SD_task_set_state(comm_dst, SD_SCHEDULABLE);
-          }
-          if (SD_task_get_state(output) == SD_RUNNABLE && not sd_global->watch_point_reached)
-            SD_task_run(output);
-        }
-        task->outputs->clear();
+        for (auto const& succ : task->get_successors())
+          succ->released_by(task);
+        task->clear_successors();
+
+        for (auto const& output : task->get_outputs())
+          output->produced_by(task);
+        task->clear_outputs();
         action = model->extract_done_action();
       }
 
       /* let's see which tasks have just failed */
       action = model->extract_failed_action();
       while (action != nullptr) {
-        auto* task = static_cast<SD_task_t>(action->get_data());
-        XBT_VERB("Task '%s' failed", SD_task_get_name(task));
-        SD_task_set_state(task, SD_FAILED);
+        auto* task = static_cast<Task*>(action->get_data());
+        XBT_VERB("Task '%s' failed", task->get_cname());
+        task->set_state(SD_FAILED);
         sd_global->return_set.insert(task);
         action = model->extract_failed_action();
       }
@@ -110,7 +82,7 @@ std::set<SD_task_t>* simulate(double how_long)
   if (not sd_global->watch_point_reached && how_long < 0 && not sd_global->initial_tasks.empty()) {
     XBT_WARN("Simulation is finished but %zu tasks are still not done", sd_global->initial_tasks.size());
     for (auto const& t : sd_global->initial_tasks)
-      XBT_WARN("%s is in %s state", SD_task_get_name(t), __get_state_name(SD_task_get_state(t)));
+      XBT_WARN("%s is in %s state", t->get_cname(), __get_state_name(t->get_state()));
   }
 
   XBT_DEBUG("elapsed_time = %f, total_time = %f, watch_point_reached = %d", elapsed_time, total_time,
index 4d88fa1..5ac5034 100644 (file)
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_task, sd, "Logging specific to SimDag (task)");
 
-/* Destroys the data memorized by SD_task_schedule. Task state must be SD_SCHEDULED or SD_RUNNABLE. */
-static void __SD_task_destroy_scheduling_data(SD_task_t task)
+namespace simgrid {
+
+template class xbt::Extendable<sd::Task>;
+
+namespace sd {
+
+Task* Task::create(const std::string& name, double amount, void* userdata)
 {
-  if (task->state != SD_SCHEDULED && task->state != SD_RUNNABLE)
-    throw std::invalid_argument(
-        simgrid::xbt::string_printf("Task '%s' must be SD_SCHEDULED or SD_RUNNABLE", SD_task_get_name(task)));
+  auto task = new Task();
+  task->set_name(name);
+  task->set_amount(amount);
+  task->set_data(userdata);
+  task->allocation_ = new std::vector<sg_host_t>();
+  sd_global->initial_tasks.insert(task);
+
+  return task;
+}
+
+Task* Task::create_comm_e2e(const std::string& name, double amount, void* userdata)
+{
+  auto task              = create(name, amount, userdata);
+  task->bytes_amount_    = xbt_new0(double, 4);
+  task->bytes_amount_[2] = amount;
+  task->set_kind(SD_TASK_COMM_E2E);
+
+  return task;
+}
+
+Task* Task::create_comp_seq(const std::string& name, double amount, void* userdata)
+{
+  auto task              = create(name, amount, userdata);
+  task->flops_amount_    = xbt_new0(double, 1);
+  task->flops_amount_[0] = amount;
+  task->set_kind(SD_TASK_COMP_SEQ);
+
+  return task;
+}
+
+Task* Task::create_comp_par_amdahl(const std::string& name, double amount, void* userdata, double alpha)
+{
+  xbt_assert(alpha < 1. && alpha >= 0., "Invalid parameter: alpha must be in [0.;1.[");
+
+  auto task = create(name, amount, userdata);
+  task->set_alpha(alpha);
+  task->set_kind(SD_TASK_COMP_PAR_AMDAHL);
+
+  return task;
+}
+
+Task* Task::create_comm_par_mxn_1d_block(const std::string& name, double amount, void* userdata)
+{
+  auto task = create(name, amount, userdata);
+  task->set_kind(SD_TASK_COMM_PAR_MXN_1D_BLOCK);
+
+  return task;
+}
+
+void Task::distribute_comp_amdahl(int count)
+{
+  xbt_assert(kind_ == SD_TASK_COMP_PAR_AMDAHL,
+             "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
+             "Cannot use this function.",
+             get_cname());
+  flops_amount_ = xbt_new0(double, count);
+  for (int i = 0; i < count; i++)
+    flops_amount_[i] = (alpha_ + (1 - alpha_) / count) * amount_;
+}
+
+void Task::build_MxN_1D_block_matrix(int src_nb, int dst_nb)
+{
+  xbt_assert(kind_ == SD_TASK_COMM_PAR_MXN_1D_BLOCK,
+             "Task %s is not a SD_TASK_COMM_PAR_MXN_1D_BLOCK typed task."
+             "Cannot use this function.",
+             get_cname());
+  xbt_free(bytes_amount_);
+  bytes_amount_ = xbt_new0(double, allocation_->size() * allocation_->size());
+
+  for (int i = 0; i < src_nb; i++) {
+    double src_start = i * amount_ / src_nb;
+    double src_end   = src_start + amount_ / src_nb;
+    for (int j = 0; j < dst_nb; j++) {
+      double dst_start = j * amount_ / dst_nb;
+      double dst_end   = dst_start + amount_ / dst_nb;
+      XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)", i, j, src_start, src_end, dst_start, dst_end);
+      bytes_amount_[i * (src_nb + dst_nb) + src_nb + j] = 0.0;
+      if ((src_end > dst_start) && (dst_end > src_start)) { /* There is something to send */
+        bytes_amount_[i * (src_nb + dst_nb) + src_nb + j] = std::min(src_end, dst_end) - std::max(src_start, dst_start);
+        XBT_VERB("==> %.2f", bytes_amount_[i * (src_nb + dst_nb) + src_nb + j]);
+      }
+    }
+  }
+}
+
+bool Task::is_parent_of(Task* task) const
+{
+  return (successors_.find(task) != successors_.end() || outputs_.find(task) != outputs_.end());
+}
+
+bool Task::is_child_of(Task* task) const
+{
+  return (inputs_.find(task) != inputs_.end() || predecessors_.find(task) != predecessors_.end());
+}
+
+void Task::set_amount(double amount)
+{
+  amount_ = amount;
+  if (kind_ == SD_TASK_COMP_SEQ)
+    flops_amount_[0] = amount;
+  if (kind_ == SD_TASK_COMM_E2E) {
+    bytes_amount_[2] = amount;
+  }
+}
+
+void Task::set_rate(double rate)
+{
+  xbt_assert(kind_ == SD_TASK_COMM_E2E, "The rate can be modified for end-to-end communications only.");
+  if (state_ < SD_RUNNING) {
+    rate_ = rate;
+  } else {
+    XBT_WARN("Task %p has started. Changing rate is ineffective.", this);
+  }
+}
+void Task::set_state(e_SD_task_state_t new_state)
+{
+  std::set<Task*>::iterator idx;
+  XBT_DEBUG("Set state of '%s' to %d", get_cname(), new_state);
+  if ((new_state == SD_NOT_SCHEDULED || new_state == SD_SCHEDULABLE) && state_ == SD_FAILED) {
+    sd_global->completed_tasks.erase(this);
+    sd_global->initial_tasks.insert(this);
+  }
+
+  if (new_state == SD_SCHEDULED && state_ == SD_RUNNABLE) {
+    sd_global->initial_tasks.insert(this);
+    sd_global->runnable_tasks.erase(this);
+  }
+
+  if (new_state == SD_RUNNABLE) {
+    idx = sd_global->initial_tasks.find(this);
+    if (idx != sd_global->initial_tasks.end()) {
+      sd_global->runnable_tasks.insert(*idx);
+      sd_global->initial_tasks.erase(idx);
+    }
+  }
+
+  if (new_state == SD_RUNNING)
+    sd_global->runnable_tasks.erase(this);
+
+  if (new_state == SD_DONE || new_state == SD_FAILED) {
+    sd_global->completed_tasks.insert(this);
+    start_time_ = surf_action_->get_start_time();
+    if (new_state == SD_DONE) {
+      finish_time_ = surf_action_->get_finish_time();
+#if SIMGRID_HAVE_JEDULE
+      jedule_log_sd_event(this);
+#endif
+    } else
+      finish_time_ = simgrid_get_clock();
+    surf_action_->unref();
+    surf_action_ = nullptr;
+    allocation_->clear();
+  }
+
+  state_ = new_state;
+
+  if (watch_points_ & new_state) {
+    XBT_VERB("Watch point reached with task '%s'!", get_cname());
+    sd_global->watch_point_reached = true;
+    unwatch(new_state); /* remove the watch point */
+  }
+}
+
+double Task::get_alpha() const
+{
+  xbt_assert(kind_ == SD_TASK_COMP_PAR_AMDAHL, "Alpha parameter is not defined for this kind of task");
+  return alpha_;
+}
+
+double Task::get_remaining_amount() const
+{
+  if (surf_action_)
+    return surf_action_->get_remains();
+  else
+    return (state_ == SD_DONE) ? 0 : amount_;
+}
+
+double Task::get_start_time() const
+{
+  if (surf_action_)
+    return surf_action_->get_start_time();
+  else
+    return start_time_;
+}
+
+double Task::get_finish_time() const
+{
+  if (surf_action_) /* should never happen as actions are destroyed right after their completion */
+    return surf_action_->get_finish_time();
+  else
+    return finish_time_;
+}
+
+void Task::set_sender_side_allocation(unsigned long count, const std::vector<s4u::Host*>* sender)
+{
+  for (unsigned long i = 0; i < count; i++)
+    allocation_->push_back(sender->at(i));
+}
+
+void Task::set_receiver_side_allocation(unsigned long count, const std::vector<s4u::Host*>* receiver)
+{
+  for (unsigned long i = 0; i < count; i++)
+    allocation_->insert(allocation_->begin() + i, receiver->at(i));
+}
+
+void Task::watch(e_SD_task_state_t state)
+{
+  if (state & SD_NOT_SCHEDULED)
+    throw std::invalid_argument("Cannot add a watch point for state SD_NOT_SCHEDULED");
+
+  watch_points_ = watch_points_ | state;
+}
+
+void Task::unwatch(e_SD_task_state_t state)
+{
+  xbt_assert(state != SD_NOT_SCHEDULED, "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
+  watch_points_ = watch_points_ & ~state;
+}
+
+void Task::dump() const
+{
+  XBT_INFO("Displaying task %s", get_cname());
+  if (state_ == SD_RUNNABLE)
+    XBT_INFO("  - state: runnable");
+  else if (state_ < SD_RUNNABLE)
+    XBT_INFO("  - state: %s not runnable", __get_state_name(state_));
+  else
+    XBT_INFO("  - state: not runnable %s", __get_state_name(state_));
+
+  if (kind_ != 0) {
+    switch (kind_) {
+      case SD_TASK_COMM_E2E:
+        XBT_INFO("  - kind: end-to-end communication");
+        break;
+      case SD_TASK_COMP_SEQ:
+        XBT_INFO("  - kind: sequential computation");
+        break;
+      case SD_TASK_COMP_PAR_AMDAHL:
+        XBT_INFO("  - kind: parallel computation following Amdahl's law");
+        break;
+      case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
+        XBT_INFO("  - kind: MxN data redistribution assuming 1D block distribution");
+        break;
+      default:
+        XBT_INFO("  - (unknown kind %d)", kind_);
+    }
+  }
+
+  XBT_INFO("  - amount: %.0f", amount_);
+  if (kind_ == SD_TASK_COMP_PAR_AMDAHL)
+    XBT_INFO("  - alpha: %.2f", alpha_);
+  XBT_INFO("  - Dependencies to satisfy: %zu", has_unsolved_dependencies());
+  if (has_unsolved_dependencies() > 0) {
+    XBT_INFO("  - pre-dependencies:");
+    for (auto const& it : predecessors_)
+      XBT_INFO("    %s", it->get_cname());
+
+    for (auto const& it : inputs_)
+      XBT_INFO("    %s", it->get_cname());
+  }
+  if ((outputs_.size() + successors_.size()) > 0) {
+    XBT_INFO("  - post-dependencies:");
+
+    for (auto const& it : successors_)
+      XBT_INFO("    %s", it->get_cname());
+    for (auto const& it : outputs_)
+      XBT_INFO("    %s", it->get_cname());
+  }
+}
+
+void Task::released_by(Task* pred)
+{
+  predecessors_.erase(pred);
+  inputs_.erase(pred);
+  XBT_DEBUG("Release dependency on %s: %zu remain(s). Becomes schedulable if %zu=0", get_cname(),
+            has_unsolved_dependencies(), predecessors_.size());
+
+  if (state_ == SD_NOT_SCHEDULED && predecessors_.empty())
+    set_state(SD_SCHEDULABLE);
+
+  if (state_ == SD_SCHEDULED && has_unsolved_dependencies() == 0)
+    set_state(SD_RUNNABLE);
+
+  if (state_ == SD_RUNNABLE && not sd_global->watch_point_reached)
+    run();
+}
+
+void Task::produced_by(Task* pred)
+{
+  start_time_ = pred->get_finish_time();
+  predecessors_.erase(pred);
+  if (state_ == SD_SCHEDULED)
+    set_state(SD_RUNNABLE);
+  else
+    set_state(SD_SCHEDULABLE);
+
+  Task* comm_dst = *(successors_.begin());
+  if (comm_dst->get_state() == SD_NOT_SCHEDULED && comm_dst->get_predecessors().empty()) {
+    XBT_DEBUG("%s is a transfer, %s may be ready now if %zu=0", get_cname(), comm_dst->get_cname(),
+              comm_dst->get_predecessors().size());
+    comm_dst->set_state(SD_SCHEDULABLE);
+  }
+  if (state_ == SD_RUNNABLE && not sd_global->watch_point_reached)
+    run();
+}
+
+void Task::do_schedule()
+{
+  if (state_ > SD_SCHEDULABLE)
+    throw std::invalid_argument(simgrid::xbt::string_printf("Task '%s' has already been scheduled", get_cname()));
+
+  if (has_unsolved_dependencies() == 0)
+    set_state(SD_RUNNABLE);
+  else
+    set_state(SD_SCHEDULED);
+}
+
+void Task::schedule(const std::vector<s4u::Host*>& hosts, const double* flops_amount, const double* bytes_amount,
+                    double rate)
+{
+  unsigned long host_count = hosts.size();
+  rate_                    = rate;
+
+  if (flops_amount) {
+    flops_amount_ = static_cast<double*>(xbt_realloc(flops_amount_, sizeof(double) * host_count));
+    memcpy(flops_amount_, flops_amount, sizeof(double) * host_count);
+  } else {
+    xbt_free(flops_amount_);
+    flops_amount_ = nullptr;
+  }
+
+  unsigned long communication_nb = host_count * host_count;
+  if (bytes_amount) {
+    bytes_amount_ = static_cast<double*>(xbt_realloc(bytes_amount_, sizeof(double) * communication_nb));
+    memcpy(bytes_amount_, bytes_amount, sizeof(double) * communication_nb);
+  } else {
+    xbt_free(bytes_amount_);
+    bytes_amount_ = nullptr;
+  }
+
+  for (unsigned long i = 0; i < host_count; i++)
+    allocation_->push_back(hosts[i]);
+
+  do_schedule();
+}
+
+void Task::schedulev(const std::vector<s4u::Host*>& hosts)
+{
+  xbt_assert(kind_ == SD_TASK_COMP_SEQ || kind_ == SD_TASK_COMP_PAR_AMDAHL,
+             "Task %s is not typed. Cannot automatically schedule it.", get_cname());
+
+  for (unsigned long i = 0; i < hosts.size(); i++)
+    allocation_->push_back(hosts[i]);
+
+  XBT_VERB("Schedule computation task %s on %zu host(s)", get_cname(), allocation_->size());
+
+  if (kind_ == SD_TASK_COMP_SEQ) {
+    if (not flops_amount_) { /*This task has failed and is rescheduled. Reset the flops_amount*/
+      flops_amount_    = xbt_new0(double, 1);
+      flops_amount_[0] = amount_;
+    }
+    XBT_VERB("It costs %.f flops", flops_amount_[0]);
+  }
+
+  if (kind_ == SD_TASK_COMP_PAR_AMDAHL) {
+    distribute_comp_amdahl(hosts.size());
+    XBT_VERB("%.f flops will be distributed following Amdahl's Law", flops_amount_[0]);
+  }
+
+  do_schedule();
+
+  /* Iterate over all inputs and outputs to say where I am located (and start them if runnable) */
+  for (auto const& input : inputs_) {
+    unsigned long src_nb = input->get_allocation_size();
+    unsigned long dst_nb = hosts.size();
+    if (src_nb == 0)
+      XBT_VERB("Sender side of '%s' not scheduled. Set receiver side to '%s''s allocation", input->get_cname(),
+               get_cname());
+    input->set_sender_side_allocation(dst_nb, allocation_);
+
+    if (input->get_allocation_size() > allocation_->size()) {
+      if (kind_ == SD_TASK_COMP_PAR_AMDAHL)
+        input->build_MxN_1D_block_matrix(src_nb, dst_nb);
+
+      input->do_schedule();
+      XBT_VERB("Auto-Schedule Communication task '%s'. Send %.f bytes from %zu hosts to %zu hosts.", input->get_cname(),
+               input->get_amount(), src_nb, dst_nb);
+    }
+  }
+
+  for (auto const& output : outputs_) {
+    unsigned long src_nb = hosts.size();
+    unsigned long dst_nb = output->get_allocation_size();
+    if (dst_nb == 0)
+      XBT_VERB("Receiver side of '%s' not scheduled. Set sender side to '%s''s allocation", output->get_cname(),
+               get_cname());
+    output->set_receiver_side_allocation(src_nb, allocation_);
+
+    if (output->get_allocation_size() > allocation_->size()) {
+      if (kind_ == SD_TASK_COMP_PAR_AMDAHL)
+        output->build_MxN_1D_block_matrix(src_nb, dst_nb);
+
+      output->do_schedule();
+      XBT_VERB("Auto-Schedule Communication task %s. Send %.f bytes from %zu hosts to %zu hosts.", output->get_cname(),
+               output->get_amount(), src_nb, dst_nb);
+    }
+  }
+}
+
+void Task::unschedule()
+{
+  if (state_ == SD_NOT_SCHEDULED || state_ == SD_SCHEDULABLE)
+    throw std::invalid_argument(xbt::string_printf(
+        "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED", get_cname()));
+
+  if (state_ == SD_SCHEDULED || state_ == SD_RUNNABLE) /* if the task is scheduled or runnable */ {
+    allocation_->clear();
+    if (kind_ == SD_TASK_COMP_PAR_AMDAHL || kind_ == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
+      /* Don't free scheduling data for typed tasks */
+      xbt_free(flops_amount_);
+      xbt_free(bytes_amount_);
+      bytes_amount_ = nullptr;
+      flops_amount_ = nullptr;
+    }
+  }
+
+  if (state_ == SD_RUNNING)
+    /* the task should become SD_FAILED */
+    surf_action_->cancel();
+  else {
+    if (has_unsolved_dependencies() == 0)
+      set_state(SD_SCHEDULABLE);
+    else
+      set_state(SD_NOT_SCHEDULED);
+  }
+  start_time_ = -1.0;
+}
+
+void Task::run()
+{
+  xbt_assert(state_ == SD_RUNNABLE, "Task '%s' is not runnable! Task state: %d", get_cname(), (int)state_);
+  xbt_assert(not allocation_->empty(), "Task '%s': host_list is empty!", get_cname());
+
+  XBT_VERB("Executing task '%s'", get_cname());
+
+  /* Beware! The scheduling data are now used by the surf action directly! no copy was done */
+  auto host_model = allocation_->front()->get_netpoint()->get_englobing_zone()->get_host_model();
+  surf_action_    = host_model->execute_parallel(*allocation_, flops_amount_, bytes_amount_, rate_);
 
-  xbt_free(task->flops_amount);
-  xbt_free(task->bytes_amount);
-  task->bytes_amount = nullptr;
-  task->flops_amount = nullptr;
+  surf_action_->set_data(this);
+
+  XBT_DEBUG("surf_action = %p", surf_action_);
+
+  set_state(SD_RUNNING);
+  sd_global->return_set.insert(this);
+}
+
+void Task::destroy()
+{
+  XBT_DEBUG("Destroying task %s...", get_cname());
+
+  /* First Remove all dependencies associated with the task. */
+  while (not predecessors_.empty())
+    SD_task_dependency_remove(*(predecessors_.begin()), this);
+  while (not inputs_.empty())
+    SD_task_dependency_remove(*(inputs_.begin()), this);
+  while (not successors_.empty())
+    SD_task_dependency_remove(this, *(successors_.begin()));
+  while (not outputs_.empty())
+    SD_task_dependency_remove(this, *(outputs_.begin()));
+
+  if (state_ == SD_SCHEDULED || state_ == SD_RUNNABLE) {
+    xbt_free(flops_amount_);
+    xbt_free(bytes_amount_);
+    bytes_amount_ = nullptr;
+    flops_amount_ = nullptr;
+  }
+
+  xbt_free(flops_amount_);
+  xbt_free(bytes_amount_);
+
+  delete allocation_;
+
+  if (surf_action_ != nullptr)
+    surf_action_->unref();
+
+  XBT_DEBUG("Task destroyed.");
 }
+} // namespace sd
+} // namespace simgrid
+
+/* **************************** Public C interface *************************** */
 
 /**
  * @brief Creates a new task.
@@ -36,36 +524,7 @@ static void __SD_task_destroy_scheduling_data(SD_task_t task)
  */
 SD_task_t SD_task_create(const char* name, void* data, double amount)
 {
-  auto* task     = xbt_new0(s_SD_task_t, 1);
-  task->kind     = SD_TASK_NOT_TYPED;
-  task->state    = SD_NOT_SCHEDULED;
-  sd_global->initial_tasks.insert(task);
-
-  task->marked       = false;
-  task->start_time   = -1.0;
-  task->finish_time  = -1.0;
-  task->surf_action  = nullptr;
-  task->watch_points = 0;
-
-  task->inputs       = new std::set<SD_task_t>();
-  task->outputs      = new std::set<SD_task_t>();
-  task->predecessors = new std::set<SD_task_t>();
-  task->successors   = new std::set<SD_task_t>();
-
-  task->data       = data;
-  task->name       = xbt_strdup(name);
-  task->amount     = amount;
-  task->allocation = new std::vector<sg_host_t>();
-  task->rate       = -1;
-  return task;
-}
-
-static inline SD_task_t SD_task_create_sized(const char* name, void* data, double amount, int count)
-{
-  SD_task_t task     = SD_task_create(name, data, amount);
-  task->bytes_amount = xbt_new0(double, count* count);
-  task->flops_amount = xbt_new0(double, count);
-  return task;
+  return simgrid::sd::Task::create(name, amount, data);
 }
 
 /** @brief create an end-to-end communication task that can then be auto-scheduled
@@ -79,11 +538,7 @@ static inline SD_task_t SD_task_create_sized(const char* name, void* data, doubl
  */
 SD_task_t SD_task_create_comm_e2e(const char* name, void* data, double amount)
 {
-  SD_task_t res        = SD_task_create_sized(name, data, amount, 2);
-  res->bytes_amount[2] = amount;
-  res->kind            = SD_TASK_COMM_E2E;
-
-  return res;
+  return simgrid::sd::Task::create_comm_e2e(name, amount, data);
 }
 
 /** @brief create a sequential computation task that can then be auto-scheduled
@@ -101,11 +556,7 @@ SD_task_t SD_task_create_comm_e2e(const char* name, void* data, double amount)
  */
 SD_task_t SD_task_create_comp_seq(const char* name, void* data, double flops_amount)
 {
-  SD_task_t res        = SD_task_create_sized(name, data, flops_amount, 1);
-  res->flops_amount[0] = flops_amount;
-  res->kind            = SD_TASK_COMP_SEQ;
-
-  return res;
+  return simgrid::sd::Task::create_comp_seq(name, flops_amount, data);
 }
 
 /** @brief create a parallel computation task that can then be auto-scheduled
@@ -125,13 +576,7 @@ SD_task_t SD_task_create_comp_seq(const char* name, void* data, double flops_amo
  */
 SD_task_t SD_task_create_comp_par_amdahl(const char* name, void* data, double flops_amount, double alpha)
 {
-  xbt_assert(alpha < 1. && alpha >= 0., "Invalid parameter: alpha must be in [0.;1.[");
-
-  SD_task_t res = SD_task_create(name, data, flops_amount);
-  res->alpha    = alpha;
-  res->kind     = SD_TASK_COMP_PAR_AMDAHL;
-
-  return res;
+  return simgrid::sd::Task::create_comp_par_amdahl(name, flops_amount, data, alpha);
 }
 
 /** @brief create a complex data redistribution task that can then be  auto-scheduled
@@ -150,10 +595,7 @@ SD_task_t SD_task_create_comp_par_amdahl(const char* name, void* data, double fl
  */
 SD_task_t SD_task_create_comm_par_mxn_1d_block(const char* name, void* data, double amount)
 {
-  SD_task_t res = SD_task_create(name, data, amount);
-  res->kind     = SD_TASK_COMM_PAR_MXN_1D_BLOCK;
-
-  return res;
+  return simgrid::sd::Task::create_comm_par_mxn_1d_block(name, amount, data);
 }
 
 /**
@@ -166,36 +608,7 @@ SD_task_t SD_task_create_comm_par_mxn_1d_block(const char* name, void* data, dou
  */
 void SD_task_destroy(SD_task_t task)
 {
-  XBT_DEBUG("Destroying task %s...", SD_task_get_name(task));
-
-  /* First Remove all dependencies associated with the task. */
-  while (not task->predecessors->empty())
-    SD_task_dependency_remove(*(task->predecessors->begin()), task);
-  while (not task->inputs->empty())
-    SD_task_dependency_remove(*(task->inputs->begin()), task);
-  while (not task->successors->empty())
-    SD_task_dependency_remove(task, *(task->successors->begin()));
-  while (not task->outputs->empty())
-    SD_task_dependency_remove(task, *(task->outputs->begin()));
-
-  if (task->state == SD_SCHEDULED || task->state == SD_RUNNABLE)
-    __SD_task_destroy_scheduling_data(task);
-
-  xbt_free(task->name);
-
-  if (task->surf_action != nullptr)
-    task->surf_action->unref();
-
-  delete task->allocation;
-  xbt_free(task->bytes_amount);
-  xbt_free(task->flops_amount);
-  delete task->inputs;
-  delete task->outputs;
-  delete task->predecessors;
-  delete task->successors;
-  xbt_free(task);
-
-  XBT_DEBUG("Task destroyed.");
+  task->destroy();
 }
 
 /**
@@ -207,7 +620,7 @@ void SD_task_destroy(SD_task_t task)
  */
 void* SD_task_get_data(const_SD_task_t task)
 {
-  return task->data;
+  return task->get_data();
 }
 
 /**
@@ -221,7 +634,7 @@ void* SD_task_get_data(const_SD_task_t task)
  */
 void SD_task_set_data(SD_task_t task, void* data)
 {
-  task->data = data;
+  task->set_data(data);
 }
 
 /**
@@ -239,12 +652,7 @@ void SD_task_set_data(SD_task_t task, void* data)
  */
 void SD_task_set_rate(SD_task_t task, double rate)
 {
-  xbt_assert(task->kind == SD_TASK_COMM_E2E, "The rate can be modified for end-to-end communications only.");
-  if (task->state < SD_RUNNING) {
-    task->rate = rate;
-  } else {
-    XBT_WARN("Task %p has started. Changing rate is ineffective.", task);
-  }
+  task->set_rate(rate);
 }
 
 /**
@@ -257,60 +665,8 @@ void SD_task_set_rate(SD_task_t task, double rate)
  */
 e_SD_task_state_t SD_task_get_state(const_SD_task_t task)
 {
-  return task->state;
+  return task->get_state();
 }
-
-/* Changes the state of a task. Updates the sd_global->watch_point_reached flag.
- */
-void SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
-{
-  std::set<SD_task_t>::iterator idx;
-  XBT_DEBUG("Set state of '%s' to %d", task->name, new_state);
-  if ((new_state == SD_NOT_SCHEDULED || new_state == SD_SCHEDULABLE) && task->state == SD_FAILED) {
-    sd_global->completed_tasks.erase(task);
-    sd_global->initial_tasks.insert(task);
-  }
-
-  if (new_state == SD_SCHEDULED && task->state == SD_RUNNABLE) {
-    sd_global->initial_tasks.insert(task);
-    sd_global->runnable_tasks.erase(task);
-  }
-
-  if (new_state == SD_RUNNABLE) {
-    idx = sd_global->initial_tasks.find(task);
-    if (idx != sd_global->initial_tasks.end()) {
-      sd_global->runnable_tasks.insert(*idx);
-      sd_global->initial_tasks.erase(idx);
-    }
-  }
-
-  if (new_state == SD_RUNNING)
-    sd_global->runnable_tasks.erase(task);
-
-  if (new_state == SD_DONE || new_state == SD_FAILED) {
-    sd_global->completed_tasks.insert(task);
-    task->start_time = task->surf_action->get_start_time();
-    if (new_state == SD_DONE) {
-      task->finish_time = task->surf_action->get_finish_time();
-#if SIMGRID_HAVE_JEDULE
-      jedule_log_sd_event(task);
-#endif
-    } else
-      task->finish_time = simgrid_get_clock();
-    task->surf_action->unref();
-    task->surf_action = nullptr;
-    task->allocation->clear();
-  }
-
-  task->state = new_state;
-
-  if (task->watch_points & new_state) {
-    XBT_VERB("Watch point reached with task '%s'!", task->name);
-    sd_global->watch_point_reached = true;
-    SD_task_unwatch(task, new_state); /* remove the watch point */
-  }
-}
-
 /**
  * @brief Returns the name of a task
  *
@@ -319,14 +675,13 @@ void SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state)
  */
 const char* SD_task_get_name(const_SD_task_t task)
 {
-  return task->name;
+  return task->get_cname();
 }
 
 /** @brief Allows to change the name of a task */
 void SD_task_set_name(SD_task_t task, const char* name)
 {
-  xbt_free(task->name);
-  task->name = xbt_strdup(name);
+  task->set_name(name);
 }
 
 /** @brief Returns the dynar of the parents of a task
@@ -339,9 +694,9 @@ xbt_dynar_t SD_task_get_parents(const_SD_task_t task)
 {
   xbt_dynar_t parents = xbt_dynar_new(sizeof(SD_task_t), nullptr);
 
-  for (auto const& it : *task->predecessors)
+  for (auto const& it : task->get_predecessors())
     xbt_dynar_push(parents, &it);
-  for (auto const& it : *task->inputs)
+  for (auto const& it : task->get_inputs())
     xbt_dynar_push(parents, &it);
 
   return parents;
@@ -356,9 +711,9 @@ xbt_dynar_t SD_task_get_children(const_SD_task_t task)
 {
   xbt_dynar_t children = xbt_dynar_new(sizeof(SD_task_t), nullptr);
 
-  for (auto const& it : *task->successors)
+  for (auto const& it : task->get_successors())
     xbt_dynar_push(children, &it);
-  for (auto const& it : *task->outputs)
+  for (auto const& it : task->get_outputs())
     xbt_dynar_push(children, &it);
 
   return children;
@@ -372,7 +727,7 @@ xbt_dynar_t SD_task_get_children(const_SD_task_t task)
  */
 int SD_task_get_workstation_count(const_SD_task_t task)
 {
-  return static_cast<int>(task->allocation->size());
+  return static_cast<int>(task->get_allocation_size());
 }
 
 /**
@@ -383,7 +738,7 @@ int SD_task_get_workstation_count(const_SD_task_t task)
  */
 sg_host_t* SD_task_get_workstation_list(const_SD_task_t task)
 {
-  return task->allocation->data();
+  return task->get_allocation()->data();
 }
 
 /**
@@ -395,7 +750,7 @@ sg_host_t* SD_task_get_workstation_list(const_SD_task_t task)
  */
 double SD_task_get_amount(const_SD_task_t task)
 {
-  return task->amount;
+  return task->get_amount();
 }
 
 /** @brief Sets the total amount of work of a task
@@ -408,11 +763,7 @@ double SD_task_get_amount(const_SD_task_t task)
  */
 void SD_task_set_amount(SD_task_t task, double amount)
 {
-  task->amount = amount;
-  if (task->kind == SD_TASK_COMP_SEQ)
-    task->flops_amount[0] = amount;
-  if (task->kind == SD_TASK_COMM_E2E)
-    task->bytes_amount[2] = amount;
+  task->set_amount(amount);
 }
 
 /**
@@ -423,8 +774,7 @@ void SD_task_set_amount(SD_task_t task, double amount)
  */
 double SD_task_get_alpha(const_SD_task_t task)
 {
-  xbt_assert(SD_task_get_kind(task) == SD_TASK_COMP_PAR_AMDAHL, "Alpha parameter is not defined for this kind of task");
-  return task->alpha;
+  return task->get_alpha();
 }
 
 /**
@@ -436,75 +786,26 @@ double SD_task_get_alpha(const_SD_task_t task)
  */
 double SD_task_get_remaining_amount(const_SD_task_t task)
 {
-  if (task->surf_action)
-    return task->surf_action->get_remains();
-  else
-    return (task->state == SD_DONE) ? 0 : task->amount;
+  return task->get_remaining_amount();
 }
 
 e_SD_task_kind_t SD_task_get_kind(const_SD_task_t task)
 {
-  return task->kind;
+  return task->get_kind();
 }
 
 /** @brief Displays debugging information about a task */
 void SD_task_dump(const_SD_task_t task)
 {
-  XBT_INFO("Displaying task %s", SD_task_get_name(task));
-  if (task->state == SD_RUNNABLE)
-    XBT_INFO("  - state: runnable");
-  else if (task->state < SD_RUNNABLE)
-    XBT_INFO("  - state: %s not runnable", __get_state_name(task->state));
-  else
-    XBT_INFO("  - state: not runnable %s", __get_state_name(task->state));
-
-  if (task->kind != 0) {
-    switch (task->kind) {
-      case SD_TASK_COMM_E2E:
-        XBT_INFO("  - kind: end-to-end communication");
-        break;
-      case SD_TASK_COMP_SEQ:
-        XBT_INFO("  - kind: sequential computation");
-        break;
-      case SD_TASK_COMP_PAR_AMDAHL:
-        XBT_INFO("  - kind: parallel computation following Amdahl's law");
-        break;
-      case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
-        XBT_INFO("  - kind: MxN data redistribution assuming 1D block distribution");
-        break;
-      default:
-        XBT_INFO("  - (unknown kind %d)", task->kind);
-    }
-  }
-
-  XBT_INFO("  - amount: %.0f", SD_task_get_amount(task));
-  if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
-    XBT_INFO("  - alpha: %.2f", task->alpha);
-  XBT_INFO("  - Dependencies to satisfy: %zu", task->inputs->size() + task->predecessors->size());
-  if ((task->inputs->size() + task->predecessors->size()) > 0) {
-    XBT_INFO("  - pre-dependencies:");
-    for (auto const& it : *task->predecessors)
-      XBT_INFO("    %s", it->name);
-
-    for (auto const& it : *task->inputs)
-      XBT_INFO("    %s", it->name);
-  }
-  if ((task->outputs->size() + task->successors->size()) > 0) {
-    XBT_INFO("  - post-dependencies:");
-
-    for (auto const& it : *task->successors)
-      XBT_INFO("    %s", it->name);
-    for (auto const& it : *task->outputs)
-      XBT_INFO("    %s", it->name);
-  }
+  task->dump();
 }
 
 /** @brief Dumps the task in dotty formalism into the FILE* passed as second argument */
 void SD_task_dotty(const_SD_task_t task, void* out)
 {
   auto* fout = static_cast<FILE*>(out);
-  fprintf(fout, "  T%p [label=\"%.20s\"", task, task->name);
-  switch (task->kind) {
+  fprintf(fout, "  T%p [label=\"%.20s\"", task, task->get_cname());
+  switch (task->get_kind()) {
     case SD_TASK_COMM_E2E:
     case SD_TASK_COMM_PAR_MXN_1D_BLOCK:
       fprintf(fout, ", shape=box");
@@ -517,9 +818,9 @@ void SD_task_dotty(const_SD_task_t task, void* out)
       xbt_die("Unknown task type!");
   }
   fprintf(fout, "];\n");
-  for (auto const& it : *task->predecessors)
+  for (auto const& it : task->get_predecessors())
     fprintf(fout, " T%p -> T%p;\n", it, task);
-  for (auto const& it : *task->inputs)
+  for (auto const& it : task->get_inputs())
     fprintf(fout, " T%p -> T%p;\n", it, task);
 }
 
@@ -539,39 +840,39 @@ void SD_task_dependency_add(SD_task_t src, SD_task_t dst)
     throw std::invalid_argument(
         simgrid::xbt::string_printf("Cannot add a dependency between task '%s' and itself", SD_task_get_name(src)));
 
-  if (src->state == SD_DONE || src->state == SD_FAILED)
+  if (src->get_state() == SD_DONE || src->get_state() == SD_FAILED)
     throw std::invalid_argument(simgrid::xbt::string_printf(
-        "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNABLE, or SD_RUNNING", src->name));
+        "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, SD_RUNNABLE, or SD_RUNNING",
+        src->get_cname()));
 
-  if (dst->state == SD_DONE || dst->state == SD_FAILED || dst->state == SD_RUNNING)
+  if (dst->get_state() == SD_DONE || dst->get_state() == SD_FAILED || dst->get_state() == SD_RUNNING)
     throw std::invalid_argument(simgrid::xbt::string_printf(
-        "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, or SD_RUNNABLE", dst->name));
+        "Task '%s' must be SD_NOT_SCHEDULED, SD_SCHEDULABLE, SD_SCHEDULED, or SD_RUNNABLE", dst->get_cname()));
 
-  if (dst->inputs->find(src) != dst->inputs->end() || src->outputs->find(dst) != src->outputs->end() ||
-      src->successors->find(dst) != src->successors->end() || dst->predecessors->find(src) != dst->predecessors->end())
+  if (dst->is_child_of(src) || src->is_parent_of(dst))
     throw std::invalid_argument(simgrid::xbt::string_printf(
-        "A dependency already exists between task '%s' and task '%s'", src->name, dst->name));
+        "A dependency already exists between task '%s' and task '%s'", src->get_cname(), dst->get_cname()));
 
-  XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s", src->name, dst->name);
+  XBT_DEBUG("SD_task_dependency_add: src = %s, dst = %s", src->get_cname(), dst->get_cname());
 
-  if (src->kind == SD_TASK_COMM_E2E || src->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
-    if (dst->kind == SD_TASK_COMP_SEQ || dst->kind == SD_TASK_COMP_PAR_AMDAHL)
-      dst->inputs->insert(src);
+  if (src->get_kind() == SD_TASK_COMM_E2E || src->get_kind() == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
+    if (dst->get_kind() == SD_TASK_COMP_SEQ || dst->get_kind() == SD_TASK_COMP_PAR_AMDAHL)
+      dst->add_input(src);
     else
-      dst->predecessors->insert(src);
-    src->successors->insert(dst);
+      dst->add_predecessor(src);
+    src->add_successor(dst);
   } else {
-    if (dst->kind == SD_TASK_COMM_E2E || dst->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK)
-      src->outputs->insert(dst);
+    if (dst->get_kind() == SD_TASK_COMM_E2E || dst->get_kind() == SD_TASK_COMM_PAR_MXN_1D_BLOCK)
+      src->add_output(dst);
     else
-      src->successors->insert(dst);
-    dst->predecessors->insert(src);
+      src->add_successor(dst);
+    dst->add_predecessor(src);
   }
 
   /* if the task was runnable, the task goes back to SD_SCHEDULED because of the new dependency*/
-  if (dst->state == SD_RUNNABLE) {
-    XBT_DEBUG("SD_task_dependency_add: %s was runnable and becomes scheduled!", dst->name);
-    SD_task_set_state(dst, SD_SCHEDULED);
+  if (dst->get_state() == SD_RUNNABLE) {
+    XBT_DEBUG("SD_task_dependency_add: %s was runnable and becomes scheduled!", dst->get_cname());
+    dst->set_state(SD_SCHEDULED);
   }
 }
 
@@ -588,15 +889,13 @@ int SD_task_dependency_exists(const_SD_task_t src, SD_task_t dst)
 {
   xbt_assert(src != nullptr || dst != nullptr, "Invalid parameter: both src and dst are nullptr");
 
-  if (src) {
-    if (dst) {
-      return (src->successors->find(dst) != src->successors->end() || src->outputs->find(dst) != src->outputs->end());
-    } else {
-      return static_cast<int>(src->successors->size() + src->outputs->size());
-    }
-  } else {
-    return static_cast<int>(dst->predecessors->size() + dst->inputs->size());
-  }
+  if (src)
+    if (dst)
+      return src->is_parent_of(dst);
+    else
+      return static_cast<int>(src->is_waited_by());
+  else
+    return static_cast<int>(dst->has_unsolved_dependencies());
 }
 
 /**
@@ -608,30 +907,30 @@ int SD_task_dependency_exists(const_SD_task_t src, SD_task_t dst)
  */
 void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
 {
-  XBT_DEBUG("SD_task_dependency_remove: src = %s, dst = %s", SD_task_get_name(src), SD_task_get_name(dst));
+  XBT_DEBUG("SD_task_dependency_remove: src = %s, dst = %s", src->get_cname(), dst->get_cname());
 
-  if (src->successors->find(dst) == src->successors->end() && src->outputs->find(dst) == src->outputs->end())
+  if (not src->is_parent_of(dst))
     throw std::invalid_argument(simgrid::xbt::string_printf(
-        "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'", src->name,
-        dst->name, dst->name, src->name));
+        "No dependency found between task '%s' and '%s': task '%s' is not a successor of task '%s'", src->get_cname(),
+        dst->get_cname(), dst->get_cname(), src->get_cname()));
 
-  if (src->kind == SD_TASK_COMM_E2E || src->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
-    if (dst->kind == SD_TASK_COMP_SEQ || dst->kind == SD_TASK_COMP_PAR_AMDAHL)
-      dst->inputs->erase(src);
+  if (src->get_kind() == SD_TASK_COMM_E2E || src->get_kind() == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
+    if (dst->get_kind() == SD_TASK_COMP_SEQ || dst->get_kind() == SD_TASK_COMP_PAR_AMDAHL)
+      dst->rm_input(src);
     else
-      dst->predecessors->erase(src);
-    src->successors->erase(dst);
+      dst->rm_predecessor(src);
+    src->rm_successor(dst);
   } else {
-    if (dst->kind == SD_TASK_COMM_E2E || dst->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK)
-      src->outputs->erase(dst);
+    if (dst->get_kind() == SD_TASK_COMM_E2E || dst->get_kind() == SD_TASK_COMM_PAR_MXN_1D_BLOCK)
+      src->rm_output(dst);
     else
-      src->successors->erase(dst);
-    dst->predecessors->erase(src);
+      src->rm_successor(dst);
+    dst->rm_predecessor(src);
   }
 
   /* if the task was scheduled and dependencies are satisfied, we can make it runnable */
-  if (dst->predecessors->empty() && dst->inputs->empty() && dst->state == SD_SCHEDULED)
-    SD_task_set_state(dst, SD_RUNNABLE);
+  if (dst->has_unsolved_dependencies() == 0 && dst->get_state() == SD_SCHEDULED)
+    dst->set_state(SD_RUNNABLE);
 }
 
 /**
@@ -646,10 +945,7 @@ void SD_task_dependency_remove(SD_task_t src, SD_task_t dst)
  */
 void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
 {
-  if (state & SD_NOT_SCHEDULED)
-    throw std::invalid_argument("Cannot add a watch point for state SD_NOT_SCHEDULED");
-
-  task->watch_points = task->watch_points | state;
+  task->watch(state);
 }
 
 /**
@@ -661,8 +957,7 @@ void SD_task_watch(SD_task_t task, e_SD_task_state_t state)
  */
 void SD_task_unwatch(SD_task_t task, e_SD_task_state_t state)
 {
-  xbt_assert(state != SD_NOT_SCHEDULED, "SimDag error: Cannot have a watch point for state SD_NOT_SCHEDULED");
-  task->watch_points = task->watch_points & ~state;
+  task->unwatch(state);
 }
 
 /**
@@ -701,18 +996,6 @@ double SD_task_get_execution_time(const_SD_task_t /*task*/, int host_count, cons
   return max_time;
 }
 
-static inline void SD_task_do_schedule(SD_task_t task)
-{
-  if (SD_task_get_state(task) > SD_SCHEDULABLE)
-    throw std::invalid_argument(
-        simgrid::xbt::string_printf("Task '%s' has already been scheduled", SD_task_get_name(task)));
-
-  if (task->predecessors->empty() && task->inputs->empty())
-    SD_task_set_state(task, SD_RUNNABLE);
-  else
-    SD_task_set_state(task, SD_SCHEDULED);
-}
-
 /**
  * @brief Schedules a task
  *
@@ -731,30 +1014,12 @@ void SD_task_schedule(SD_task_t task, int host_count, const sg_host_t* host_list
                       const double* bytes_amount, double rate)
 {
   xbt_assert(host_count > 0, "host_count must be positive");
-
-  task->rate = rate;
-
-  if (flops_amount) {
-    task->flops_amount = static_cast<double*>(xbt_realloc(task->flops_amount, sizeof(double) * host_count));
-    memcpy(task->flops_amount, flops_amount, sizeof(double) * host_count);
-  } else {
-    xbt_free(task->flops_amount);
-    task->flops_amount = nullptr;
-  }
-
-  int communication_nb = host_count * host_count;
-  if (bytes_amount) {
-    task->bytes_amount = static_cast<double*>(xbt_realloc(task->bytes_amount, sizeof(double) * communication_nb));
-    memcpy(task->bytes_amount, bytes_amount, sizeof(double) * communication_nb);
-  } else {
-    xbt_free(task->bytes_amount);
-    task->bytes_amount = nullptr;
-  }
+  std::vector<sg_host_t> hosts(host_count);
 
   for (int i = 0; i < host_count; i++)
-    task->allocation->push_back(host_list[i]);
+    hosts[i] = host_list[i];
 
-  SD_task_do_schedule(task);
+  task->schedule(hosts, flops_amount, bytes_amount, rate);
 }
 
 /**
@@ -769,49 +1034,7 @@ void SD_task_schedule(SD_task_t task, int host_count, const sg_host_t* host_list
  */
 void SD_task_unschedule(SD_task_t task)
 {
-  if (task->state == SD_NOT_SCHEDULED || task->state == SD_SCHEDULABLE)
-    throw std::invalid_argument(simgrid::xbt::string_printf(
-        "Task %s: the state must be SD_SCHEDULED, SD_RUNNABLE, SD_RUNNING or SD_FAILED", task->name));
-
-  if (task->state == SD_SCHEDULED || task->state == SD_RUNNABLE) /* if the task is scheduled or runnable */ {
-    task->allocation->clear();
-    if (task->kind == SD_TASK_COMP_PAR_AMDAHL || task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK) {
-      /* Don't free scheduling data for typed tasks */
-      __SD_task_destroy_scheduling_data(task);
-    }
-  }
-
-  if (SD_task_get_state(task) == SD_RUNNING)
-    /* the task should become SD_FAILED */
-    task->surf_action->cancel();
-  else {
-    if (task->predecessors->empty() && task->inputs->empty())
-      SD_task_set_state(task, SD_SCHEDULABLE);
-    else
-      SD_task_set_state(task, SD_NOT_SCHEDULED);
-  }
-  task->start_time = -1.0;
-}
-
-/* Runs a task. */
-void SD_task_run(SD_task_t task)
-{
-  xbt_assert(task->state == SD_RUNNABLE, "Task '%s' is not runnable! Task state: %d", task->name, (int)task->state);
-  xbt_assert(task->allocation != nullptr, "Task '%s': host_list is nullptr!", task->name);
-
-  XBT_VERB("Executing task '%s'", task->name);
-
-  /* Beware! The scheduling data are now used by the surf action directly! no copy was done */
-  auto host_model = (*task->allocation).front()->get_netpoint()->get_englobing_zone()->get_host_model();
-  task->surf_action =
-      host_model->execute_parallel(*task->allocation, task->flops_amount, task->bytes_amount, task->rate);
-
-  task->surf_action->set_data(task);
-
-  XBT_DEBUG("surf_action = %p", task->surf_action);
-
-  SD_task_set_state(task, SD_RUNNING);
-  sd_global->return_set.insert(task);
+  task->unschedule();
 }
 
 /**
@@ -824,10 +1047,7 @@ void SD_task_run(SD_task_t task)
  */
 double SD_task_get_start_time(const_SD_task_t task)
 {
-  if (task->surf_action)
-    return task->surf_action->get_start_time();
-  else
-    return task->start_time;
+  return task->get_start_time();
 }
 
 /**
@@ -842,50 +1062,17 @@ double SD_task_get_start_time(const_SD_task_t task)
  */
 double SD_task_get_finish_time(const_SD_task_t task)
 {
-  if (task->surf_action) /* should never happen as actions are destroyed right after their completion */
-    return task->surf_action->get_finish_time();
-  else
-    return task->finish_time;
+  return task->get_finish_time();
 }
 
 void SD_task_distribute_comp_amdahl(SD_task_t task, int count)
 {
-  xbt_assert(task->kind == SD_TASK_COMP_PAR_AMDAHL,
-             "Task %s is not a SD_TASK_COMP_PAR_AMDAHL typed task."
-             "Cannot use this function.",
-             task->name);
-  task->flops_amount = xbt_new0(double, count);
-  task->bytes_amount = xbt_new0(double, count* count);
-
-  for (int i = 0; i < count; i++) {
-    task->flops_amount[i] = (task->alpha + (1 - task->alpha) / count) * task->amount;
-  }
+  task->distribute_comp_amdahl(count);
 }
 
 void SD_task_build_MxN_1D_block_matrix(SD_task_t task, int src_nb, int dst_nb)
 {
-  xbt_assert(task->kind == SD_TASK_COMM_PAR_MXN_1D_BLOCK,
-             "Task %s is not a SD_TASK_COMM_PAR_MXN_1D_BLOCK typed task."
-             "Cannot use this function.",
-             task->name);
-  xbt_free(task->bytes_amount);
-  task->bytes_amount = xbt_new0(double, task->allocation->size() * task->allocation->size());
-
-  for (int i = 0; i < src_nb; i++) {
-    double src_start = i * task->amount / src_nb;
-    double src_end   = src_start + task->amount / src_nb;
-    for (int j = 0; j < dst_nb; j++) {
-      double dst_start = j * task->amount / dst_nb;
-      double dst_end   = dst_start + task->amount / dst_nb;
-      XBT_VERB("(%d->%d): (%.2f, %.2f)-> (%.2f, %.2f)", i, j, src_start, src_end, dst_start, dst_end);
-      task->bytes_amount[i * (src_nb + dst_nb) + src_nb + j] = 0.0;
-      if ((src_end > dst_start) && (dst_end > src_start)) { /* There is something to send */
-        task->bytes_amount[i * (src_nb + dst_nb) + src_nb + j] =
-            std::min(src_end, dst_end) - std::max(src_start, dst_start);
-        XBT_VERB("==> %.2f", task->bytes_amount[i * (src_nb + dst_nb) + src_nb + j]);
-      }
-    }
-  }
+  task->build_MxN_1D_block_matrix(src_nb, dst_nb);
 }
 
 /** @brief Auto-schedules a task.
@@ -896,69 +1083,12 @@ void SD_task_build_MxN_1D_block_matrix(SD_task_t task, int src_nb, int dst_nb)
  *
  * To be auto-schedulable, a task must be a typed computation SD_TASK_COMP_SEQ or SD_TASK_COMP_PAR_AMDAHL.
  */
-void SD_task_schedulev(SD_task_t task, int count, const sg_host_t* list)
+void SD_task_schedulev(SD_task_t task, int count, const sg_host_t* host_list)
 {
-  xbt_assert(task->kind == SD_TASK_COMP_SEQ || task->kind == SD_TASK_COMP_PAR_AMDAHL,
-             "Task %s is not typed. Cannot automatically schedule it.", SD_task_get_name(task));
-
+  std::vector<sg_host_t> list(count);
   for (int i = 0; i < count; i++)
-    task->allocation->push_back(list[i]);
-
-  XBT_VERB("Schedule computation task %s on %zu host(s)", task->name, task->allocation->size());
-
-  if (task->kind == SD_TASK_COMP_SEQ) {
-    if (not task->flops_amount) { /*This task has failed and is rescheduled. Reset the flops_amount*/
-      task->flops_amount    = xbt_new0(double, 1);
-      task->flops_amount[0] = task->amount;
-    }
-    XBT_VERB("It costs %.f flops", task->flops_amount[0]);
-  }
-
-  if (task->kind == SD_TASK_COMP_PAR_AMDAHL) {
-    SD_task_distribute_comp_amdahl(task, count);
-    XBT_VERB("%.f flops will be distributed following Amdahl's Law", task->flops_amount[0]);
-  }
-
-  SD_task_do_schedule(task);
-
-  /* Iterate over all inputs and outputs to say where I am located (and start them if runnable) */
-  for (auto const& input : *task->inputs) {
-    int src_nb = static_cast<int>(input->allocation->size());
-    int dst_nb = count;
-    if (input->allocation->empty())
-      XBT_VERB("Sender side of '%s' not scheduled. Set receiver side to '%s''s allocation", input->name, task->name);
-
-    for (int i = 0; i < count; i++)
-      input->allocation->push_back(task->allocation->at(i));
-
-    if (input->allocation->size() > task->allocation->size()) {
-      if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
-        SD_task_build_MxN_1D_block_matrix(input, src_nb, dst_nb);
-
-      SD_task_do_schedule(input);
-      XBT_VERB("Auto-Schedule Communication task '%s'. Send %.f bytes from %d hosts to %d hosts.", input->name,
-               input->amount, src_nb, dst_nb);
-    }
-  }
-
-  for (auto const& output : *task->outputs) {
-    int src_nb = count;
-    int dst_nb = static_cast<int>(output->allocation->size());
-    if (output->allocation->empty())
-      XBT_VERB("Receiver side of '%s' not scheduled. Set sender side to '%s''s allocation", output->name, task->name);
-
-    for (int i = 0; i < count; i++)
-      output->allocation->insert(output->allocation->begin() + i, task->allocation->at(i));
-
-    if (output->allocation->size() > task->allocation->size()) {
-      if (task->kind == SD_TASK_COMP_PAR_AMDAHL)
-        SD_task_build_MxN_1D_block_matrix(output, src_nb, dst_nb);
-
-      SD_task_do_schedule(output);
-      XBT_VERB("Auto-Schedule Communication task %s. Send %.f bytes from %d hosts to %d hosts.", output->name,
-               output->amount, src_nb, dst_nb);
-    }
-  }
+    list[i] = host_list[i];
+  task->schedulev(list);
 }
 
 /** @brief autoschedule a task on a list of hosts
@@ -975,5 +1105,5 @@ void SD_task_schedulel(SD_task_t task, int count, ...)
     list[i] = va_arg(ap, sg_host_t);
 
   va_end(ap);
-  SD_task_schedulev(task, count, list.data());
+  task->schedulev(list);
 }
index 8fcae45..d868968 100644 (file)
@@ -3,8 +3,11 @@
 /* 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 "simgrid/s4u/Engine.hpp"
-#include "simgrid/simdag.h"
+#include <simgrid/s4u/Engine.hpp>
+#include <simgrid/s4u/Host.hpp>
+#include <simgrid/simdag.h>
+#include <xbt/Extendable.hpp>
+
 #include <set>
 #include <string>
 #include <vector>
 #endif
 
 namespace simgrid{
+extern template class XBT_PUBLIC xbt::Extendable<sd::Task>;
+
 namespace sd{
+class Global;
+
+class Task : public xbt::Extendable<Task> {
+  friend sd::Global;
+
+  std::string name_;
+  double amount_;
+
+  e_SD_task_kind_t kind_   = SD_TASK_NOT_TYPED;
+  e_SD_task_state_t state_ = SD_NOT_SCHEDULED;
+  bool marked_             = false; /* used to check if the task DAG has some cycle*/
+  double start_time_       = -1;
+  double finish_time_      = -1;
+  kernel::resource::Action* surf_action_;
+  unsigned short watch_points_ = 0; /* bit field xor()ed with masks */
+  double rate_                 = -1;
+
+  double alpha_ = 0; /* used by typed parallel tasks */
+
+  /* dependencies */
+  std::set<Task*> inputs_;
+  std::set<Task*> outputs_;
+  std::set<Task*> predecessors_;
+  std::set<Task*> successors_;
+
+  /* scheduling parameters (only exist in state SD_SCHEDULED) */
+  std::vector<s4u::Host*>* allocation_;
+  double* flops_amount_;
+  double* bytes_amount_;
+
+protected:
+  void set_start_time(double start) { start_time_ = start; }
+
+  void set_sender_side_allocation(unsigned long count, const std::vector<s4u::Host*>* sender);
+  void set_receiver_side_allocation(unsigned long count, const std::vector<s4u::Host*>* receiver);
+
+public:
+  static Task* create(const std::string& name, double amount, void* userdata);
+  static Task* create_comm_e2e(const std::string& name, double amount, void* userdata);
+  static Task* create_comp_seq(const std::string& name, double amount, void* userdata);
+  static Task* create_comp_par_amdahl(const std::string& name, double amount, void* userdata, double alpha);
+  static Task* create_comm_par_mxn_1d_block(const std::string& name, double amount, void* userdata);
+
+  void distribute_comp_amdahl(int count);
+  void build_MxN_1D_block_matrix(int src_nb, int dst_nb);
+
+  void add_input(Task* task) { inputs_.insert(task); }
+  void rm_input(Task* task) { inputs_.erase(task); }
+  void add_predecessor(Task* task) { predecessors_.insert(task); }
+  void rm_predecessor(Task* task) { predecessors_.erase(task); }
+  void add_successor(Task* task) { successors_.insert(task); }
+  void rm_successor(Task* task) { successors_.erase(task); }
+  void clear_successors() { successors_.clear(); }
+  void add_output(Task* task) { outputs_.insert(task); }
+  void rm_output(Task* task) { outputs_.erase(task); }
+  void clear_outputs() { outputs_.clear(); }
+
+  void set_name(const std::string& name) { name_ = name; }
+  const std::string& get_name() const { return name_; }
+  const char* get_cname() const { return name_.c_str(); }
+
+  void set_amount(double amount);
+  double get_amount() const { return amount_; }
+  double get_remaining_amount() const;
+
+  double get_start_time() const;
+  double get_finish_time() const;
+
+  void set_state(e_SD_task_state_t new_state);
+  e_SD_task_state_t get_state() const { return state_; }
+
+  void mark() { marked_ = true; }
+  void unmark() { marked_ = false; }
+  bool is_marked() const { return marked_; }
+
+  const std::set<Task*>& get_inputs() const { return inputs_; }
+  const std::set<Task*>& get_predecessors() const { return predecessors_; }
+  const std::set<Task*>& get_successors() const { return successors_; }
+  const std::set<Task*>& get_outputs() const { return outputs_; }
+
+  bool is_parent_of(Task* task) const;
+  bool is_child_of(Task* task) const;
+
+  unsigned long has_unsolved_dependencies() const { return (predecessors_.size() + inputs_.size()); }
+  unsigned long is_waited_by() const { return (successors_.size() + outputs_.size()); }
+  void released_by(Task* pred);
+  void produced_by(Task* pred);
+
+  void set_kind(e_SD_task_kind_t kind) { kind_ = kind; }
+  e_SD_task_kind_t get_kind() const { return kind_; }
+
+  void set_alpha(double alpha) { alpha_ = alpha; }
+  double get_alpha() const;
+  void set_rate(double rate);
+
+  unsigned int get_allocation_size() const { return allocation_->size(); }
+  std::vector<s4u::Host*>* get_allocation() const { return allocation_; }
+
+  void watch(e_SD_task_state_t state);
+  void unwatch(e_SD_task_state_t state);
+
+  void dump() const;
+
+  void do_schedule();
+  void schedule(const std::vector<s4u::Host*>& hosts, const double* flops_amount, const double* bytes_amount,
+                double rate);
+  void schedulev(const std::vector<s4u::Host*>& hosts);
+  void unschedule();
+
+  void run();
+  void destroy();
+};
+
 class Global {
 public:
   explicit Global(int* argc, char** argv) : engine_(new simgrid::s4u::Engine(argc, argv)) {}
   bool watch_point_reached = false; /* has a task just reached a watch point? */
-  std::set<SD_task_t> initial_tasks;
-  std::set<SD_task_t> runnable_tasks;
-  std::set<SD_task_t> completed_tasks;
-  std::set<SD_task_t> return_set;
+  std::set<Task*> initial_tasks;
+  std::set<Task*> runnable_tasks;
+  std::set<Task*> completed_tasks;
+  std::set<Task*> return_set;
   s4u::Engine* engine_;
 };
 
-std::set<SD_task_t>* simulate (double how_long);
-}
-}
+} // namespace sd
+} // namespace simgrid
 
 extern XBT_PRIVATE std::unique_ptr<simgrid::sd::Global> sd_global;
 
-/* Task */
-struct s_SD_task_t {
-  e_SD_task_state_t state;
-  void *data;                   /* user data */
-  char *name;
-  e_SD_task_kind_t kind;
-  double amount;
-  double alpha;          /* used by typed parallel tasks */
-  double start_time;
-  double finish_time;
-  simgrid::kernel::resource::Action* surf_action;
-  unsigned short watch_points;  /* bit field xor()ed with masks */
-
-  bool marked = false; /* used to check if the task DAG has some cycle*/
-
-  /* dependencies -- cannot be embedded in the struct since it's not handled as a real C++ class */
-  std::set<SD_task_t> *inputs;
-  std::set<SD_task_t> *outputs;
-  std::set<SD_task_t> *predecessors;
-  std::set<SD_task_t> *successors;
-
-  /* scheduling parameters (only exist in state SD_SCHEDULED) */
-  std::vector<sg_host_t> *allocation;
-  double *flops_amount;
-  double *bytes_amount;
-  double rate;
-};
-
 /* SimDag private functions */
-XBT_PRIVATE void SD_task_set_state(SD_task_t task, e_SD_task_state_t new_state);
-XBT_PRIVATE void SD_task_run(SD_task_t task);
 XBT_PRIVATE bool acyclic_graph_detail(const_xbt_dynar_t dag);
 XBT_PRIVATE void uniq_transfer_task_name(SD_task_t task);
 XBT_PRIVATE const char *__get_state_name(e_SD_task_state_t state);