+simgrid::sd::Global *sd_global = nullptr;
+
+namespace simgrid{
+namespace sd{
+Global::Global(){
+ watch_point_reached = false;
+ initial_tasks = new std::set<SD_task_t>();
+ runnable_tasks = new std::set<SD_task_t>();
+ completed_tasks = new std::set<SD_task_t>();
+ return_set = new std::set<SD_task_t>();
+}
+
+Global::~Global(){
+ delete initial_tasks;
+ delete runnable_tasks;
+ delete completed_tasks;
+ delete return_set;
+}
+
+std::set<SD_task_t>* simulate(double how_long){
+ XBT_VERB("Run simulation for %f seconds", how_long);
+
+ 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()));
+
+ double elapsed_time = 0.0;
+ double total_time = 0.0;
+ /* main loop */
+ while (elapsed_time >= 0 && (how_long < 0 || 0.00001 < (how_long - total_time)) &&
+ not sd_global->watch_point_reached) {
+
+ XBT_DEBUG("Total time: %f", total_time);
+
+ elapsed_time = surf_solve(how_long > 0 ? surf_get_clock() + how_long - total_time: -1.0);
+ XBT_DEBUG("surf_solve() returns %f", elapsed_time);
+ if (elapsed_time > 0.0)
+ total_time += elapsed_time;
+
+ /* let's see which tasks are done */
+ for (auto const& model : *all_existing_models) {
+ simgrid::kernel::resource::Action* action = surf_model_extract_done_action_set(model);
+ while (action != nullptr && action->getData() != nullptr) {
+ SD_task_t task = static_cast<SD_task_t>(action->getData());
+ XBT_VERB("Task '%s' done", SD_task_get_name(task));
+ SD_task_set_state(task, SD_DONE);
+
+ /* the state has changed. Add it only if it's the first change */
+ if (sd_global->return_set->find(task) == sd_global->return_set->end())
+ sd_global->return_set->insert(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();
+ action = surf_model_extract_done_action_set(model);
+ }
+
+ /* let's see which tasks have just failed */
+ action = surf_model_extract_failed_action_set(model);
+ while (action != nullptr) {
+ SD_task_t task = static_cast<SD_task_t>(action->getData());
+ XBT_VERB("Task '%s' failed", SD_task_get_name(task));
+ SD_task_set_state(task, SD_FAILED);
+ sd_global->return_set->insert(task);
+ action = surf_model_extract_failed_action_set(model);
+ }
+ }
+ }
+
+ 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_DEBUG("elapsed_time = %f, total_time = %f, watch_point_reached = %d",
+ elapsed_time, total_time, sd_global->watch_point_reached);
+ XBT_DEBUG("current time = %f", surf_get_clock());
+
+ return sd_global->return_set;
+}
+}
+}
+
+/**
+ * \brief helper for pretty printing of task state
+ * \param state the state of a task
+ * \return the equivalent as a readable string
+ */
+const char *__get_state_name(e_SD_task_state_t state){
+ static std::string state_names[7] =
+ { "not scheduled", "schedulable", "scheduled", "runnable","running", "done", "failed" };
+ return state_names[static_cast<int>(log2(static_cast<double>(state)))].data();
+}