#endif
}
-xbt_dynar_t get_dead_actors_addr()
-{
-#if SIMGRID_HAVE_MC
- return EngineImpl::get_instance()->get_dead_actors_vector();
-#else
- xbt_die("This function is intended to be used when compiling with MC");
-#endif
-}
-
constexpr std::initializer_list<std::pair<const char*, context::ContextFactoryInitializer>> context_factories = {
#if HAVE_RAW_CONTEXTS
{"raw", &context::raw_factory},
/* Free the remaining data structures */
#if SIMGRID_HAVE_MC
xbt_dynar_free(&actors_vector_);
- xbt_dynar_free(&dead_actors_vector_);
#endif
/* clear models before freeing handle, network models can use external callback defined in the handle */
models_prio_.clear();
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
/* List the actors and their state */
XBT_INFO("Legend of the following listing: \"Actor <pid> (<name>@<host>): <status>\"");
for (auto const& kv : actor_list_) {
- actor::ActorImpl* actor = kv.second;
+ const actor::ActorImpl* actor = kv.second;
if (actor->waiting_synchro_) {
const char* synchro_description = "unknown";
if (boost::dynamic_pointer_cast<kernel::activity::SleepImpl>(actor->waiting_synchro_) != nullptr)
synchro_description = "sleeping";
- if (boost::dynamic_pointer_cast<kernel::activity::RawImpl>(actor->waiting_synchro_) != nullptr)
+ if (boost::dynamic_pointer_cast<kernel::activity::SynchroImpl>(actor->waiting_synchro_) != nullptr)
synchro_description = "synchronization";
if (boost::dynamic_pointer_cast<kernel::activity::IoImpl>(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(),
+ XBT_INFO("Actor %ld (%s@%s): waiting for %s activity %#zx (%s) in state %s 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_);
+ actor->waiting_synchro_->get_cname(), actor->waiting_synchro_->get_state_str());
} 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_));
seal_platform();
if (MC_record_replay_is_active()) {
- mc::replay(MC_record_path());
+ mc::RecordTrace::replay(MC_record_path());
empty_trash();
return;
}
/* Here, the order is ok because:
*
- * Short proof: only maestro adds stuff to the actors_to_run array, so the execution order of user contexts do
- * not impact its order.
+ * Only maestro adds stuff to the actors_to_run array, so the execution order of user contexts do not impact its order.
+ *
+ * In addition, actors remain sorted through an arbitrary but fixed order in all cases:
*
- * Long proof: actors remain sorted through an arbitrary (implicit, complex but fixed) order in all cases.
+ * - If there is no killing during the simulation, actors remain sorted according by their PID.
+ * - Killer actors are moved to the end of the scheduling round (to let victims finish their simcall before dying), but
+ * (1) this decision of killing is reproducible because the simulation was reproducible until then
+ * (2) this reordering introduces no reproducibility hazard in the subsequent simulation.
+ * Even the order change induced by the actor killing is perfectly reproducible.
+ *
+ * So the array order is implicit and somewhat complex, but fixed and reproducible (science works, http://xkcd.com/54/).
*
- * - if there is no kill during the simulation, actors remain sorted according by their PID.
- * Rationale: This can be proved inductively.
- * Assume that actors_to_run is sorted at a beginning of one round (it is at round 0: the deployment file
- * is parsed linearly).
- * Let's show that it is still so at the end of this round.
- * - if an actor is added when being created, that's from maestro. It can be either at startup
- * time (and then in PID order), or in response to a process_create simcall. Since simcalls are handled
- * in arbitrary order (inductive hypothesis), we are fine.
- * - If an actor is added because it's getting killed, its subsequent actions shouldn't matter
- * - If an actor gets added to actors_to_run because one of their blocking action constituting the meat
- * of a simcall terminates, we're still good. Proof:
- * - You are added from ActorImpl::simcall_answer() only. When this function is called depends on the
- * resource kind (network, cpu, disk, whatever), but the same arguments hold. Let's take communications
- * as an example.
- * - For communications, this function is called from CommImpl::finish().
- * This function itself don't mess with the order since simcalls are handled in FIFO order.
- * The function is called:
- * - before the comm starts (invalid parameters, or resource already dead or whatever).
- * The order then trivial holds since maestro didn't interrupt its handling of the simcall yet
- * - because the communication failed or were canceled after startup. In this case, it's called from
- * the function we are in, by the chunk:
- * set = model->states.failed_action_set;
- * while ((synchro = extract(set)))
- * SIMIX_simcall_post((smx_synchro_t) synchro->data);
- * This order is also fixed because it depends of the order in which the surf actions were
- * added to the system, and only maestro can add stuff this way, through simcalls.
- * We thus use the inductive hypothesis once again to conclude that the order in which synchros are
- * popped out of the set does not depend on the user code's execution order.
- * - because the communication terminated. In this case, synchros are served in the order given by
- * set = model->states.done_action_set;
- * while ((synchro = extract(set)))
- * SIMIX_simcall_post((smx_synchro_t) synchro->data);
- * and the argument is very similar to the previous one.
- * So, in any case, the orders of calls to CommImpl::finish() do not depend on the order in which user
- * actors are executed.
- * So, in any cases, the orders of actors within actors_to_run do not depend on the order in which
- * user actors were executed previously.
- * So, if there is no killing in the simulation, the simulation reproducibility is not jeopardized.
- * - If there is some actor killings, the order is changed by this decision that comes from user-land
- * But this decision may not have been motivated by a situation that were different because the simulation is
- * not reproducible.
- * So, even the order change induced by the actor killing is perfectly reproducible.
- *
- * So science works, bitches [http://xkcd.com/54/].
- *
- * We could sort the actors_that_ran array completely so that we can describe the order in which simcalls are
- * handled (like "according to the PID of issuer"), but it's not mandatory (order is fixed already even if
- * unfriendly).
- * That would thus be a pure waste of time.
+ * We could manually sort the actors_that_ran array so that simcalls are handled in an easy to predict order
+ * (e.g. "according to the PID of issuer"), but it's not mandatory for the simulation soundness and reproducibility,
+ * and would thus be a pure waste of time.
*/
for (auto const& actor : actors_that_ran_) {
maestro_->kill(kv.second);
}
}
-
} while ((vetoed_activities == nullptr || vetoed_activities->empty()) &&
((elapsed_time > -1.0 && not double_equals(max_date, NOW, 0.00001)) || has_actors_to_run()));