X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/5ff119db4c1bee3bb8e1b9693dfd382cb462db57..e2f13c6eb4d0c1b07e1b32a75016431dd75a68d2:/src/kernel/EngineImpl.cpp diff --git a/src/kernel/EngineImpl.cpp b/src/kernel/EngineImpl.cpp index 515de4d7bd..926bdb9288 100644 --- a/src/kernel/EngineImpl.cpp +++ b/src/kernel/EngineImpl.cpp @@ -6,6 +6,7 @@ #include "src/kernel/EngineImpl.hpp" #include "mc/mc.h" #include "simgrid/Exception.hpp" +#include "simgrid/kernel/Timer.hpp" #include "simgrid/kernel/routing/NetPoint.hpp" #include "simgrid/kernel/routing/NetZoneImpl.hpp" #include "simgrid/s4u/Host.hpp" @@ -15,6 +16,7 @@ #include "src/mc/mc_record.hpp" #include "src/mc/mc_replay.hpp" #include "src/simix/smx_private.hpp" +#include "src/smpi/include/smpi_actor.hpp" #include "src/surf/network_interface.hpp" #include "src/surf/xml/platf.hpp" // FIXME: KILLME. There must be a better way than mimicking XML here @@ -27,6 +29,12 @@ config::Flag cfg_breakpoint{"debug/breakpoint", "When non-negative, raise a SIGTRAP after given (simulated) time", -1.0}; EngineImpl::~EngineImpl() { + + while (not timer::kernel_timers().empty()) { + delete timer::kernel_timers().top().second; + timer::kernel_timers().pop(); + } + /* Since hosts_ is a std::map, the hosts are destroyed in the lexicographic order, which ensures that the output is * reproducible. */ @@ -41,6 +49,12 @@ EngineImpl::~EngineImpl() for (auto const& kv : links_) if (kv.second) kv.second->destroy(); + + /* Free the remaining data structures */ +#if SIMGRID_HAVE_MC + xbt_dynar_free(&actors_vector_); + xbt_dynar_free(&dead_actors_vector_); +#endif } void EngineImpl::load_deployment(const std::string& file) const @@ -96,7 +110,33 @@ void EngineImpl::wake_all_waiting_actors() const } } } +/** + * @brief Executes the actors in actors_to_run. + * + * The actors in actors_to_run are run (in parallel if possible). On exit, actors_to_run is empty, and actors_that_ran + * contains the list of actors that just ran. The two lists are swapped so, be careful when using them before and after + * a call to this function. + */ +void EngineImpl::run_all_actors() +{ + simix_global->context_factory->run_all(); + + actors_to_run_.swap(actors_that_ran_); + actors_to_run_.clear(); +} +actor::ActorImpl* EngineImpl::get_actor_by_pid(aid_t pid) +{ + auto item = actor_list_.find(pid); + if (item != actor_list_.end()) + return item->second; + + // Search the trash + for (auto& a : actors_to_destroy_) + if (a.get_pid() == pid) + return &a; + return nullptr; // Not found, even in the trash +} /** Execute all the tasks that are queued, e.g. `.then()` callbacks of futures. */ bool EngineImpl::execute_tasks() { @@ -119,13 +159,78 @@ bool EngineImpl::execute_tasks() return true; } -void EngineImpl::rm_daemon(actor::ActorImpl* actor) +void EngineImpl::remove_daemon(actor::ActorImpl* actor) { auto it = daemons_.find(actor); xbt_assert(it != daemons_.end(), "The dying daemon is not a daemon after all. Please report that bug."); daemons_.erase(it); } +void EngineImpl::add_actor_to_run_list_no_check(actor::ActorImpl* actor) +{ + XBT_DEBUG("Inserting [%p] %s(%s) in the to_run list", actor, actor->get_cname(), actor->get_host()->get_cname()); + actors_to_run_.push_back(actor); +} + +void EngineImpl::add_actor_to_run_list(actor::ActorImpl* actor) +{ + if (std::find(begin(actors_to_run_), end(actors_to_run_), actor) != end(actors_to_run_)) { + XBT_DEBUG("Actor %s is already in the to_run list", actor->get_cname()); + } else { + XBT_DEBUG("Inserting [%p] %s(%s) in the to_run list", actor, actor->get_cname(), actor->get_host()->get_cname()); + actors_to_run_.push_back(actor); + } +} +void EngineImpl::empty_trash() +{ + while (not actors_to_destroy_.empty()) { + actor::ActorImpl* actor = &actors_to_destroy_.front(); + actors_to_destroy_.pop_front(); + XBT_DEBUG("Getting rid of %s (refcount: %d)", actor->get_cname(), actor->get_refcount()); + intrusive_ptr_release(actor); + } +#if SIMGRID_HAVE_MC + xbt_dynar_reset(dead_actors_vector_); +#endif +} + +void EngineImpl::display_all_actor_status() const +{ + XBT_INFO("%zu actors are still running, waiting for something.", actor_list_.size()); + /* List the actors and their state */ + XBT_INFO("Legend of the following listing: \"Actor (@): \""); + for (auto const& kv : actor_list_) { + actor::ActorImpl* actor = kv.second; + + if (actor->waiting_synchro_) { + const char* synchro_description = "unknown"; + + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "execution"; + + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "communication"; + + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "sleeping"; + + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "synchronization"; + + if (boost::dynamic_pointer_cast(actor->waiting_synchro_) != nullptr) + synchro_description = "I/O"; + + XBT_INFO("Actor %ld (%s@%s): waiting for %s activity %#zx (%s) in state %d to finish", actor->get_pid(), + actor->get_cname(), actor->get_host()->get_cname(), synchro_description, + (xbt_log_no_loc ? (size_t)0xDEADBEEF : (size_t)actor->waiting_synchro_.get()), + actor->waiting_synchro_->get_cname(), (int)actor->waiting_synchro_->state_); + } else { + XBT_INFO("Actor %ld (%s@%s) simcall %s", actor->get_pid(), actor->get_cname(), actor->get_host()->get_cname(), + SIMIX_simcall_name(actor->simcall_)); + } + } +} + void EngineImpl::run() { if (MC_record_replay_is_active()) { @@ -136,7 +241,7 @@ void EngineImpl::run() double time = 0; do { - XBT_DEBUG("New Schedule Round; size(queue)=%zu", simix_global->actors_to_run.size()); + XBT_DEBUG("New Schedule Round; size(queue)=%zu", actors_to_run_.size()); if (cfg_breakpoint >= 0.0 && surf_get_clock() >= cfg_breakpoint) { XBT_DEBUG("Breakpoint reached (%g)", cfg_breakpoint.get()); @@ -150,11 +255,11 @@ void EngineImpl::run() execute_tasks(); - while (not simix_global->actors_to_run.empty()) { - XBT_DEBUG("New Sub-Schedule Round; size(queue)=%zu", simix_global->actors_to_run.size()); + while (not actors_to_run_.empty()) { + XBT_DEBUG("New Sub-Schedule Round; size(queue)=%zu", actors_to_run_.size()); - /* Run all processes that are ready to run, possibly in parallel */ - simix_global->run_all_actors(); + /* Run all actors that are ready to run, possibly in parallel */ + run_all_actors(); /* answer sequentially and in a fixed arbitrary order all the simcalls that were issued during that sub-round */ @@ -218,7 +323,7 @@ void EngineImpl::run() * That would thus be a pure waste of time. */ - for (auto const& actor : simix_global->actors_that_ran) { + for (auto const& actor : actors_that_ran_) { if (actor->simcall_.call_ != simix::Simcall::NONE) { actor->simcall_handle(0); } @@ -229,8 +334,8 @@ void EngineImpl::run() wake_all_waiting_actors(); } while (execute_tasks()); - /* If only daemon processes remain, cancel their actions, mark them to die and reschedule them */ - if (simix_global->process_list.size() == daemons_.size()) + /* If only daemon actors remain, cancel their actions, mark them to die and reschedule them */ + if (actor_list_.size() == daemons_.size()) for (auto const& dmon : daemons_) { XBT_DEBUG("Kill %s", dmon->get_cname()); simix_global->maestro_->kill(dmon); @@ -238,7 +343,7 @@ void EngineImpl::run() } time = timer::Timer::next(); - if (time > -1.0 || not simix_global->process_list.empty()) { + if (time > -1.0 || not actor_list_.empty()) { XBT_DEBUG("Calling surf_solve"); time = surf_solve(time); XBT_DEBUG("Moving time ahead : %g", time); @@ -246,7 +351,7 @@ void EngineImpl::run() /* Notify all the hosts that have failed */ /* FIXME: iterate through the list of failed host and mark each of them */ - /* as failed. On each host, signal all the running processes with host_fail */ + /* as failed. On each host, signal all the running actors with host_fail */ // Execute timers and tasks until there isn't anything to be done: bool again = false; @@ -258,28 +363,27 @@ void EngineImpl::run() } while (again); /* Clean actors to destroy */ - simix_global->empty_trash(); + empty_trash(); - XBT_DEBUG("### time %f, #processes %zu, #to_run %zu", time, simix_global->process_list.size(), - simix_global->actors_to_run.size()); + XBT_DEBUG("### time %f, #actors %zu, #to_run %zu", time, actor_list_.size(), actors_to_run_.size()); - if (time < 0. && simix_global->actors_to_run.empty() && not simix_global->process_list.empty()) { - if (simix_global->process_list.size() <= daemons_.size()) { + if (time < 0. && actors_to_run_.empty() && not actor_list_.empty()) { + if (actor_list_.size() <= daemons_.size()) { XBT_CRITICAL("Oops! Daemon actors cannot do any blocking activity (communications, synchronization, etc) " "once the simulation is over. Please fix your on_exit() functions."); } else { XBT_CRITICAL("Oops! Deadlock or code not perfectly clean."); } - simix_global->display_all_actor_status(); + display_all_actor_status(); simgrid::s4u::Engine::on_deadlock(); - for (auto const& kv : simix_global->process_list) { + for (auto const& kv : actor_list_) { XBT_DEBUG("Kill %s", kv.second->get_cname()); simix_global->maestro_->kill(kv.second); } } - } while (time > -1.0 || not simix_global->actors_to_run.empty()); + } while (time > -1.0 || has_actors_to_run()); - if (not simix_global->process_list.empty()) + if (not actor_list_.empty()) THROW_IMPOSSIBLE; simgrid::s4u::Engine::on_simulation_end();