#include "src/mc/mc_private.hpp"
#include "src/mc/mc_request.hpp"
#include "src/mc/mc_smx.hpp"
+#include "src/mc/mc_api.hpp"
#if HAVE_SMPI
#include "smpi_request.hpp"
#include <cstdint>
using simgrid::mc::remote;
+using mcapi = simgrid::mc::mc_api;
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc, "Logging specific to MC communication determinism detection");
/********** Static functions ***********/
- static e_mc_comm_pattern_difference_t compare_comm_pattern(const simgrid::mc::PatternCommunication* comm1,
- const simgrid::mc::PatternCommunication* comm2)
+ static simgrid::mc::CommPatternDifference compare_comm_pattern(const simgrid::mc::PatternCommunication* comm1,
+ const simgrid::mc::PatternCommunication* comm2)
{
+ using simgrid::mc::CommPatternDifference;
if(comm1->type != comm2->type)
- return TYPE_DIFF;
+ return CommPatternDifference::TYPE;
if (comm1->rdv != comm2->rdv)
- return RDV_DIFF;
+ return CommPatternDifference::RDV;
if (comm1->src_proc != comm2->src_proc)
- return SRC_PROC_DIFF;
+ return CommPatternDifference::SRC_PROC;
if (comm1->dst_proc != comm2->dst_proc)
- return DST_PROC_DIFF;
+ return CommPatternDifference::DST_PROC;
if (comm1->tag != comm2->tag)
- return TAG_DIFF;
+ return CommPatternDifference::TAG;
if (comm1->data.size() != comm2->data.size())
- return DATA_SIZE_DIFF;
+ return CommPatternDifference::DATA_SIZE;
if (comm1->data != comm2->data)
- return DATA_DIFF;
- return NONE_DIFF;
+ return CommPatternDifference::DATA;
+ return CommPatternDifference::NONE;
}
- static char* print_determinism_result(e_mc_comm_pattern_difference_t diff, int process,
+ static char* print_determinism_result(simgrid::mc::CommPatternDifference diff, int process,
const simgrid::mc::PatternCommunication* comm, unsigned int cursor)
{
char* type;
else
type = bprintf("The recv communications pattern of the process %d is different!", process - 1);
+ using simgrid::mc::CommPatternDifference;
switch(diff) {
- case TYPE_DIFF:
- res = bprintf("%s Different type for communication #%u", type, cursor);
- break;
- case RDV_DIFF:
- res = bprintf("%s Different rdv for communication #%u", type, cursor);
- break;
- case TAG_DIFF:
- res = bprintf("%s Different tag for communication #%u", type, cursor);
- break;
- case SRC_PROC_DIFF:
- res = bprintf("%s Different source for communication #%u", type, cursor);
- break;
- case DST_PROC_DIFF:
- res = bprintf("%s Different destination for communication #%u", type, cursor);
- break;
- case DATA_SIZE_DIFF:
- res = bprintf("%s Different data size for communication #%u", type, cursor);
- break;
- case DATA_DIFF:
- res = bprintf("%s Different data for communication #%u", type, cursor);
- break;
- default:
- res = nullptr;
- break;
+ case CommPatternDifference::TYPE:
+ res = bprintf("%s Different type for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::RDV:
+ res = bprintf("%s Different rdv for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::TAG:
+ res = bprintf("%s Different tag for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::SRC_PROC:
+ res = bprintf("%s Different source for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::DST_PROC:
+ res = bprintf("%s Different destination for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::DATA_SIZE:
+ res = bprintf("%s Different data size for communication #%u", type, cursor);
+ break;
+ case CommPatternDifference::DATA:
+ res = bprintf("%s Different data for communication #%u", type, cursor);
+ break;
+ default:
+ res = nullptr;
+ break;
}
return res;
{
if (not backtracking) {
PatternCommunicationList& list = initial_communications_pattern[process];
- e_mc_comm_pattern_difference_t diff = compare_comm_pattern(list.list[list.index_comm].get(), comm);
+ CommPatternDifference diff = compare_comm_pattern(list.list[list.index_comm].get(), comm);
- if (diff != NONE_DIFF) {
+ if (diff != CommPatternDifference::NONE) {
if (comm->type == PatternCommunicationType::send) {
this->send_deterministic = false;
if (this->send_diff != nullptr)
/********** Non Static functions ***********/
- void CommunicationDeterminismChecker::get_comm_pattern(smx_simcall_t request, e_mc_call_type_t call_type,
- int backtracking)
+ void CommunicationDeterminismChecker::get_comm_pattern(smx_simcall_t request, CallType call_type, int backtracking)
{
- const smx_actor_t issuer = MC_smx_simcall_get_issuer(request);
+ const smx_actor_t issuer = mcapi::get().mc_smx_simcall_get_issuer(request);
const mc::PatternCommunicationList& initial_pattern = initial_communications_pattern[issuer->get_pid()];
const std::vector<PatternCommunication*>& incomplete_pattern = incomplete_communications_pattern[issuer->get_pid()];
auto pattern = std::make_unique<PatternCommunication>();
pattern->index = initial_pattern.index_comm + incomplete_pattern.size();
- if (call_type == MC_CALL_TYPE_SEND) {
+ if (call_type == CallType::SEND) {
/* Create comm pattern */
pattern->type = PatternCommunicationType::send;
- pattern->comm_addr = static_cast<kernel::activity::CommImpl*>(simcall_comm_isend__getraw__result(request));
+ pattern->comm_addr = mcapi::get().get_pattern_comm_addr(request);
Remote<kernel::activity::CommImpl> temp_synchro;
mc_model_checker->get_remote_simulation().read(temp_synchro, remote(pattern->comm_addr));
char* remote_name = mc_model_checker->get_remote_simulation().read<char*>(RemotePtr<char*>(
(uint64_t)(synchro->get_mailbox() ? &synchro->get_mailbox()->name_ : &synchro->mbox_cpy->name_)));
- pattern->rdv = mc_model_checker->get_remote_simulation().read_string(RemotePtr<char>(remote_name));
- pattern->src_proc =
- mc_model_checker->get_remote_simulation().resolve_actor(mc::remote(synchro->src_actor_.get()))->get_pid();
- pattern->src_host = MC_smx_actor_get_host_name(issuer);
+ pattern->rdv = mcapi::get().get_pattern_comm_rdv(pattern->comm_addr);
+ pattern->src_proc = mcapi::get().get_pattern_comm_src_proc(pattern->comm_addr);
+ pattern->src_host = mc_api::get().get_actor_host_name(issuer);
#if HAVE_SMPI
simgrid::smpi::Request mpi_request;
pattern->tag = mpi_request.tag();
#endif
- if (synchro->src_buff_ != nullptr) {
- pattern->data.resize(synchro->src_buff_size_);
- mc_model_checker->get_remote_simulation().read_bytes(pattern->data.data(), pattern->data.size(),
- remote(synchro->src_buff_));
+ // if (synchro->src_buff_ != nullptr) {
+ // pattern->data.resize(synchro->src_buff_size_);
+ // mc_model_checker->get_remote_simulation().read_bytes(pattern->data.data(), pattern->data.size(),
+ // remote(synchro->src_buff_));
+ // }
+
+ auto pattern_data = mcapi::get().get_pattern_comm_data(pattern->comm_addr);
+ if(pattern_data.data() != nullptr) {
+ auto data_size = pattern_data.size();
+ pattern->data.resize(data_size);
+ memcpy(pattern->data.data(), pattern_data.data(), data_size);
}
#if HAVE_SMPI
if(mpi_request.detached()){
return;
}
#endif
- } else if (call_type == MC_CALL_TYPE_RECV) {
+ } else if (call_type == CallType::RECV) {
pattern->type = PatternCommunicationType::receive;
pattern->comm_addr = static_cast<kernel::activity::CommImpl*>(simcall_comm_irecv__getraw__result(request));
std::vector<std::string> trace;
for (auto const& state : stack_) {
smx_simcall_t req = &state->executed_req_;
- if (req)
- trace.push_back(mcapi::get().request_to_string(req, state->transition_.argument_, RequestType::executed));
+ trace.push_back(request_to_string(req, state->transition_.argument_, RequestType::executed));
}
return trace;
}
}
}
XBT_INFO("Expanded states = %lu", expanded_states_count_);
- XBT_INFO("Visited states = %lu", mc_model_checker->visited_states);
- XBT_INFO("Executed transitions = %lu", mc_model_checker->executed_transitions);
+ XBT_INFO("Visited states = %lu", mcapi::get().mc_get_visited_states());
+ XBT_INFO("Executed transitions = %lu", mcapi::get().mc_get_executed_trans());
XBT_INFO("Send-deterministic : %s", this->send_deterministic ? "Yes" : "No");
if (_sg_mc_comms_determinism)
XBT_INFO("Recv-deterministic : %s", this->recv_deterministic ? "Yes" : "No");
void CommunicationDeterminismChecker::prepare()
{
- const int maxpid = MC_smx_get_maxpid();
+ const int maxpid = mcapi::get().get_maxpid();
initial_communications_pattern.resize(maxpid);
incomplete_communications_pattern.resize(maxpid);
XBT_DEBUG("********* Start communication determinism verification *********");
/* Get an enabled actor and insert it in the interleave set of the initial state */
- for (auto& actor : mc_model_checker->get_remote_simulation().actors())
- if (mc::actor_is_enabled(actor.copy.get_buffer()))
+ auto actors = mcapi::get().get_actors();
+ for (auto& actor : actors)
+ if (mcapi::get().actor_is_enabled(actor.copy.get_buffer()->get_pid()))
initial_state->add_interleaving_set(actor.copy.get_buffer());
stack_.push_back(std::move(initial_state));
static inline bool all_communications_are_finished()
{
- for (size_t current_actor = 1; current_actor < MC_smx_get_maxpid(); current_actor++) {
+ auto maxpid = mcapi::get().get_maxpid();
+ for (size_t current_actor = 1; current_actor < maxpid; current_actor++) {
if (not incomplete_communications_pattern[current_actor].empty()) {
XBT_DEBUG("Some communications are not finished, cannot stop the exploration! State not visited.");
return false;
/* Intermediate backtracking */
State* last_state = stack_.back().get();
if (last_state->system_state_) {
- last_state->system_state_->restore(&mc_model_checker->get_remote_simulation());
+ last_state->system_state_->restore(&mcapi::get().mc_get_remote_simulation());
MC_restore_communications_pattern(last_state);
return;
}
/* Restore the initial state */
- mc::session->restore_initial_state();
+ mcapi::get().s_restore_initial_state();
- unsigned n = MC_smx_get_maxpid();
+ unsigned n = mcapi::get().get_maxpid();
assert(n == incomplete_communications_pattern.size());
assert(n == initial_communications_pattern.size());
for (unsigned j=0; j < n ; j++) {
/* because we got a copy of the executed request, we have to fetch the
real one, pointed by the request field of the issuer process */
- const smx_actor_t issuer = MC_smx_simcall_get_issuer(saved_req);
+ const smx_actor_t issuer = mcapi::get().mc_smx_simcall_get_issuer(saved_req);
smx_simcall_t req = &issuer->simcall_;
/* TODO : handle test and testany simcalls */
- e_mc_call_type_t call = MC_get_call_type(req);
- mcapi::get().handle_simcall(state->transition_);
+ CallType call = MC_get_call_type(req);
+ mc_model_checker->handle_simcall(state->transition_);
MC_handle_comm_pattern(call, req, req_num, 1);
- mc_model_checker->wait_for_requests();
+ mcapi::get().mc_wait_for_requests();
/* Update statistics */
- mc_model_checker->visited_states++;
- mc_model_checker->executed_transitions++;
+ mcapi::get().mc_inc_visited_states();
+ mcapi::get().mc_inc_executed_trans();
}
}
cur_state->interleave_size());
/* Update statistics */
- mc_model_checker->visited_states++;
+ mcapi::get().mc_inc_visited_states();
if (stack_.size() <= (std::size_t)_sg_mc_max_depth)
- req = MC_state_choose_request(cur_state);
+ req = mcapi::get().mc_state_choose_request(cur_state);
else
req = nullptr;
if (req != nullptr && visited_state == nullptr) {
int req_num = cur_state->transition_.argument_;
- XBT_DEBUG("Execute: %s", request_to_string(req, req_num, RequestType::simix).c_str());
+ XBT_DEBUG("Execute: %s", mcapi::get().request_to_string(req, req_num, RequestType::simix).c_str());
std::string req_str;
if (dot_output != nullptr)
- req_str = request_get_dot_output(req, req_num);
+ req_str = mcapi::get().request_get_dot_output(req, req_num);
- mc_model_checker->executed_transitions++;
+ mcapi::get().mc_inc_executed_trans();
/* TODO : handle test and testany simcalls */
- e_mc_call_type_t call = MC_CALL_TYPE_NONE;
+ CallType call = CallType::NONE;
if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
call = MC_get_call_type(req);
/* Answer the request */
- mc_model_checker->handle_simcall(cur_state->transition_);
+ mcapi::get().handle_simcall(cur_state->transition_);
/* After this call req is no longer useful */
MC_handle_comm_pattern(call, req, req_num, 0);
+
/* Wait for requests (schedules processes) */
- mc_model_checker->wait_for_requests();
+ mcapi::get().mc_wait_for_requests();
/* Create the new expanded state */
++expanded_states_count_;
if (visited_state == nullptr) {
/* Get enabled actors and insert them in the interleave set of the next state */
- for (auto& actor : mc_model_checker->get_remote_simulation().actors())
- if (simgrid::mc::actor_is_enabled(actor.copy.get_buffer()))
+ auto actors = mcapi::get().mc_get_remote_simulation().actors();
+ for (auto& actor : actors)
+ if (mcapi::get().actor_is_enabled(actor.copy.get_buffer()->get_pid()))
next_state->add_interleaving_set(actor.copy.get_buffer());
if (dot_output != nullptr)
visited_state = nullptr;
/* Check for deadlocks */
- if (mc_model_checker->checkDeadlock()) {
- MC_show_deadlock();
+ if (mcapi::get().mc_check_deadlock()) {
+ mcapi::get().mc_show_deadlock();
throw simgrid::mc::DeadlockError();
}
}
}
- mc::session->log_state();
+ mcapi::get().s_log_state();
}
void CommunicationDeterminismChecker::run()
{
XBT_INFO("Check communication determinism");
- mc::session->initialize();
+ mcapi::get().s_initialize();
this->prepare();
this->real_run();
#include "src/mc/mc_private.hpp"
#include "src/mc/mc_request.hpp"
#include "src/mc/mc_smx.hpp"
+#include "src/mc/mc_api.hpp"
#include <boost/range/algorithm.hpp>
#include <cstring>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc, "Logging specific to algorithms for liveness properties verification");
+using mcapi = simgrid::mc::mc_api;
+
/********* Static functions *********/
namespace simgrid {
smx_simcall_t req = nullptr;
- if (saved_req != nullptr) {
- /* because we got a copy of the executed request, we have to fetch the
- real one, pointed by the request field of the issuer process */
- const smx_actor_t issuer = MC_smx_simcall_get_issuer(saved_req);
- req = &issuer->simcall_;
-
- /* Debug information */
- XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth,
- request_to_string(req, req_num, simgrid::mc::RequestType::simix).c_str(), state.get());
- }
+ /* because we got a copy of the executed request, we have to fetch the
+ real one, pointed by the request field of the issuer process */
+ const smx_actor_t issuer = MC_smx_simcall_get_issuer(saved_req);
+ req = &issuer->simcall_;
+
+ /* Debug information */
+ XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth,
+ request_to_string(req, req_num, simgrid::mc::RequestType::simix).c_str(), state.get());
this->get_session().execute(state->transition_);
}
for (std::shared_ptr<Pair> const& pair : exploration_stack_) {
int req_num = pair->graph_state->transition_.argument_;
smx_simcall_t req = &pair->graph_state->executed_req_;
- if (req && req->call_ != SIMCALL_NONE)
+ if (req->call_ != simix::Simcall::NONE)
trace.push_back(request_to_string(req, req_num, RequestType::executed));
}
return trace;
}
}
- smx_simcall_t req = MC_state_choose_request(current_pair->graph_state.get());
+ smx_simcall_t req = mcapi::get().mc_state_choose_request(current_pair->graph_state.get());
int req_num = current_pair->graph_state->transition_.argument_;
if (dot_output != nullptr) {
#include "src/mc/mc_record.hpp"
#include "src/mc/mc_request.hpp"
#include "src/mc/mc_smx.hpp"
+#include "src/mc/mc_api.hpp"
#include "src/xbt/mmalloc/mmprivate.h"
+using mcapi = simgrid::mc::mc_api;
+
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_safety, mc, "Logging specific to MC safety verification ");
namespace simgrid {
void SafetyChecker::check_non_termination(const State* current_state)
{
for (auto state = stack_.rbegin(); state != stack_.rend(); ++state)
- if (snapshot_equal((*state)->system_state_.get(), current_state->system_state_.get())) {
+ if (mcapi::get().snapshot_equal((*state)->system_state_.get(), current_state->system_state_.get())) {
XBT_INFO("Non-progressive cycle: state %d -> state %d", (*state)->num_, current_state->num_);
XBT_INFO("******************************************");
XBT_INFO("*** NON-PROGRESSIVE CYCLE DETECTED ***");
XBT_INFO("******************************************");
XBT_INFO("Counter-example execution trace:");
- for (auto const& s : mc_model_checker->getChecker()->get_textual_trace())
+ auto checker = mcapi::get().mc_get_checker();
+ for (auto const& s : checker->get_textual_trace())
XBT_INFO(" %s", s.c_str());
- dumpRecordPath();
- session->log_state();
+ mcapi::get().mc_dump_record_path();
+ mcapi::get().s_log_state();
throw TerminationError();
}
for (auto const& state : stack_) {
int value = state->transition_.argument_;
smx_simcall_t req = &state->executed_req_;
- if (req)
- trace.push_back(mcapi::get().request_to_string(req, value, RequestType::executed));
+ trace.push_back(request_to_string(req, value, RequestType::executed));
}
return trace;
}
void SafetyChecker::log_state() // override
{
XBT_INFO("Expanded states = %lu", expanded_states_count_);
- XBT_INFO("Visited states = %lu", mc_model_checker->visited_states);
- XBT_INFO("Executed transitions = %lu", mc_model_checker->executed_transitions);
+ XBT_INFO("Visited states = %lu", mcapi::get().mc_get_visited_states());
+ XBT_INFO("Executed transitions = %lu", mcapi::get().mc_get_executed_trans());
}
void SafetyChecker::run()
XBT_VERB("Exploration depth=%zu (state=%p, num %d)(%zu interleave)", stack_.size(), state, state->num_,
state->interleave_size());
- mc_model_checker->visited_states++;
+ mcapi::get().mc_inc_visited_states();
// Backtrack if we reached the maximum depth
if (stack_.size() > (std::size_t)_sg_mc_max_depth) {
// Search an enabled transition in the current state; backtrack if the interleave set is empty
// get_request also sets state.transition to be the one corresponding to the returned req
- smx_simcall_t req = MC_state_choose_request(state);
+ smx_simcall_t req = mcapi::get().mc_state_choose_request(state);
// req is now the transition of the process that was selected to be executed
if (req == nullptr) {
// If there are processes to interleave and the maximum depth has not been
// reached then perform one step of the exploration algorithm.
- XBT_DEBUG("Execute: %s", request_to_string(req, state->transition_.argument_, RequestType::simix).c_str());
+ XBT_DEBUG("Execute: %s", mcapi::get().request_to_string(req, state->transition_.argument_, RequestType::simix).c_str());
std::string req_str;
if (dot_output != nullptr)
- req_str = request_get_dot_output(req, state->transition_.argument_);
+ req_str = mcapi::get().request_get_dot_output(req, state->transition_.argument_);
- mc_model_checker->executed_transitions++;
+ mcapi::get().mc_inc_executed_trans();
/* Actually answer the request: let execute the selected request (MCed does one step) */
- this->get_session().execute(state->transition_);
+ mcapi::get().execute(state->transition_);
/* Create the new expanded state (copy the state of MCed into our MCer data) */
++expanded_states_count_;
/* If this is a new state (or if we don't care about state-equality reduction) */
if (visited_state_ == nullptr) {
/* Get an enabled process and insert it in the interleave set of the next state */
- for (auto& remoteActor : mc_model_checker->get_remote_simulation().actors()) {
+ auto actors = mcapi::get().mc_get_remote_simulation().actors();
+ for (auto& remoteActor : actors) {
auto actor = remoteActor.copy.get_buffer();
- if (actor_is_enabled(actor)) {
+ if (mcapi::get().actor_is_enabled(actor->get_pid())) {
next_state->add_interleaving_set(actor);
if (reductionMode_ == ReductionMode::dpor)
break; // With DPOR, we take the first enabled transition
}
XBT_INFO("No property violation found.");
- session->log_state();
+ mcapi::get().s_log_state();
}
void SafetyChecker::backtrack()
stack_.pop_back();
/* Check for deadlocks */
- if (mc_model_checker->checkDeadlock()) {
- MC_show_deadlock();
+ if (mcapi::get().mc_check_deadlock()) {
+ mcapi::get().mc_show_deadlock();
throw DeadlockError();
}
stack_.pop_back();
if (reductionMode_ == ReductionMode::dpor) {
smx_simcall_t req = &state->internal_req_;
- if (req->call_ == SIMCALL_MUTEX_LOCK || req->call_ == SIMCALL_MUTEX_TRYLOCK)
+ if (req->call_ == simix::Simcall::MUTEX_LOCK || req->call_ == simix::Simcall::MUTEX_TRYLOCK)
xbt_die("Mutex is currently not supported with DPOR, use --cfg=model-check/reduction:none");
- const kernel::actor::ActorImpl* issuer = MC_smx_simcall_get_issuer(req);
+ const kernel::actor::ActorImpl* issuer = mcapi::get().mc_smx_simcall_get_issuer(req);
for (auto i = stack_.rbegin(); i != stack_.rend(); ++i) {
State* prev_state = i->get();
- if (request_depend(req, &prev_state->internal_req_)) {
+ if (mcapi::get().request_depend(req, &prev_state->internal_req_)) {
if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
XBT_DEBUG("Dependent Transitions:");
int value = prev_state->transition_.argument_;
smx_simcall_t prev_req = &prev_state->executed_req_;
- XBT_DEBUG("%s (state=%d)", simgrid::mc::request_to_string(prev_req, value, RequestType::internal).c_str(),
+ XBT_DEBUG("%s (state=%d)", mcapi::get().request_to_string(prev_req, value, RequestType::internal).c_str(),
prev_state->num_);
value = state->transition_.argument_;
prev_req = &state->executed_req_;
- XBT_DEBUG("%s (state=%d)", simgrid::mc::request_to_string(prev_req, value, RequestType::executed).c_str(),
+ XBT_DEBUG("%s (state=%d)", mcapi::get().request_to_string(prev_req, value, RequestType::executed).c_str(),
state->num_);
}
XBT_DEBUG("Process %p is in done set", req->issuer_);
break;
} else if (req->issuer_ == prev_state->internal_req_.issuer_) {
- XBT_DEBUG("Simcall %s and %s with same issuer", SIMIX_simcall_name(req->call_),
- SIMIX_simcall_name(prev_state->internal_req_.call_));
+ XBT_DEBUG("Simcall %s and %s with same issuer", mcapi::get().simix_simcall_name(req->call_),
+ mcapi::get().simix_simcall_name(prev_state->internal_req_.call_));
break;
} else {
- const kernel::actor::ActorImpl* previous_issuer = MC_smx_simcall_get_issuer(&prev_state->internal_req_);
+ const kernel::actor::ActorImpl* previous_issuer = mcapi::get().mc_smx_simcall_get_issuer(&prev_state->internal_req_);
XBT_DEBUG("Simcall %s, process %ld (state %d) and simcall %s, process %ld (state %d) are independent",
- SIMIX_simcall_name(req->call_), issuer->get_pid(), state->num_,
- SIMIX_simcall_name(prev_state->internal_req_.call_), previous_issuer->get_pid(), prev_state->num_);
+ mcapi::get().simix_simcall_name(req->call_), issuer->get_pid(), state->num_,
+ mcapi::get().simix_simcall_name(prev_state->internal_req_.call_), previous_issuer->get_pid(), prev_state->num_);
}
}
}
/* Intermediate backtracking */
const State* last_state = stack_.back().get();
if (last_state->system_state_) {
- last_state->system_state_->restore(&mc_model_checker->get_remote_simulation());
+ last_state->system_state_->restore(&mcapi::get().mc_get_remote_simulation());
return;
}
/* Restore the initial state */
- session->restore_initial_state();
+ mcapi::get().s_restore_initial_state();
/* Traverse the stack from the state at position start and re-execute the transitions */
for (std::unique_ptr<State> const& state : stack_) {
if (state == stack_.back())
break;
- session->execute(state->transition_);
+ mcapi::get().execute(state->transition_);
/* Update statistics */
- mc_model_checker->visited_states++;
- mc_model_checker->executed_transitions++;
+ mcapi::get().mc_inc_visited_states();
+ mcapi::get().mc_inc_executed_trans();
}
}
XBT_INFO("Check a safety property. Reduction is: %s.",
(reductionMode_ == ReductionMode::none ? "none"
: (reductionMode_ == ReductionMode::dpor ? "dpor" : "unknown")));
- session->initialize();
+
+ mcapi::get().s_initialize();
XBT_DEBUG("Starting the safety algorithm");
XBT_DEBUG("Initial state");
/* Get an enabled actor and insert it in the interleave set of the initial state */
- for (auto& actor : mc_model_checker->get_remote_simulation().actors())
- if (actor_is_enabled(actor.copy.get_buffer())) {
+ auto actors = mcapi::get().get_actors();
+ for (auto& actor : actors)
+ if (mcapi::get().actor_is_enabled(actor.copy.get_buffer()->get_pid())) {
initial_state->add_interleaving_set(actor.copy.get_buffer());
if (reductionMode_ != ReductionMode::none)
break;
simix_global->run_all_actors();
for (smx_actor_t const& process : simix_global->actors_that_ran) {
const s_smx_simcall* req = &process->simcall_;
- if (req->call_ != SIMCALL_NONE && not simgrid::mc::request_is_visible(req))
+ if (req->call_ != simix::Simcall::NONE && not simgrid::mc::request_is_visible(req))
process->simcall_handle(0);
}
}
// Called from both MCer and MCed:
bool actor_is_enabled(smx_actor_t actor)
{
+// #del
#if SIMGRID_HAVE_MC
// If in the MCer, ask the client app since it has all the data
if (mc_model_checker != nullptr) {
return simgrid::mc::session->actor_is_enabled(actor->get_pid());
}
#endif
+// #
// Now, we are in the client app, no need for remote memory reading.
smx_simcall_t req = &actor->simcall_;
if (req->inspector_ != nullptr)
return req->inspector_->is_enabled();
+ using simix::Simcall;
switch (req->call_) {
- case SIMCALL_NONE:
+ case Simcall::NONE:
return false;
- case SIMCALL_COMM_WAIT: {
+ case Simcall::COMM_WAIT: {
/* FIXME: check also that src and dst processes are not suspended */
const kernel::activity::CommImpl* act = simcall_comm_wait__getraw__comm(req);
return (act->src_actor_ && act->dst_actor_);
}
- case SIMCALL_COMM_WAITANY: {
+ case Simcall::COMM_WAITANY: {
simgrid::kernel::activity::CommImpl** comms = simcall_comm_waitany__get__comms(req);
size_t count = simcall_comm_waitany__get__count(req);
for (unsigned int index = 0; index < count; ++index) {
return false;
}
- case SIMCALL_MUTEX_LOCK: {
+ case Simcall::MUTEX_LOCK: {
const kernel::activity::MutexImpl* mutex = simcall_mutex_lock__get__mutex(req);
if (mutex->get_owner() == nullptr)
return mutex->get_owner()->get_pid() == req->issuer_->get_pid();
}
- case SIMCALL_SEM_ACQUIRE: {
+ case Simcall::SEM_ACQUIRE: {
static int warned = 0;
if (not warned)
XBT_INFO("Using semaphore in model-checked code is still experimental. Use at your own risk");
return true;
}
- case SIMCALL_COND_WAIT: {
+ case Simcall::COND_WAIT: {
static int warned = 0;
if (not warned)
XBT_INFO("Using condition variables in model-checked code is still experimental. Use at your own risk");
xbt_assert(mc_model_checker == nullptr, "This should be called from the client side");
#endif
- return (req->inspector_ != nullptr && req->inspector_->is_visible()) || req->call_ == SIMCALL_COMM_ISEND ||
- req->call_ == SIMCALL_COMM_IRECV || req->call_ == SIMCALL_COMM_WAIT || req->call_ == SIMCALL_COMM_WAITANY ||
- req->call_ == SIMCALL_COMM_TEST || req->call_ == SIMCALL_COMM_TESTANY || req->call_ == SIMCALL_MC_RANDOM ||
- req->call_ == SIMCALL_MUTEX_LOCK || req->call_ == SIMCALL_MUTEX_TRYLOCK || req->call_ == SIMCALL_MUTEX_UNLOCK;
+ using simix::Simcall;
+ return (req->inspector_ != nullptr && req->inspector_->is_visible()) || req->call_ == Simcall::COMM_ISEND ||
+ req->call_ == Simcall::COMM_IRECV || req->call_ == Simcall::COMM_WAIT || req->call_ == Simcall::COMM_WAITANY ||
+ req->call_ == Simcall::COMM_TEST || req->call_ == Simcall::COMM_TESTANY || req->call_ == Simcall::MC_RANDOM ||
+ req->call_ == Simcall::MUTEX_LOCK || req->call_ == Simcall::MUTEX_TRYLOCK ||
+ req->call_ == Simcall::MUTEX_UNLOCK;
}
}
* under the terms of the license (GNU LGPL) which comes with this package. */
#include "src/mc/mc_state.hpp"
-#include "src/mc/mc_comm_pattern.hpp"
#include "src/mc/mc_config.hpp"
-#include "src/mc/mc_request.hpp"
-#include "src/mc/mc_smx.hpp"
+#include "src/mc/mc_api.hpp"
#include <boost/range/algorithm.hpp>
using simgrid::mc::remote;
+using mcapi = simgrid::mc::mc_api;
namespace simgrid {
namespace mc {
State::State(unsigned long state_number) : num_(state_number)
{
this->internal_comm_.clear();
-
- actor_states_.resize(MC_smx_get_maxpid());
+ auto maxpid = mcapi::get().get_maxpid();
+ actor_states_.resize(maxpid);
/* Stateful model checking */
if ((_sg_mc_checkpoint > 0 && (state_number % _sg_mc_checkpoint == 0)) || _sg_mc_termination) {
- system_state_ = std::make_shared<simgrid::mc::Snapshot>(num_);
+ auto snapshot_ptr = mcapi::get().take_snapshot(num_);
+ system_state_ = std::shared_ptr<simgrid::mc::Snapshot>(snapshot_ptr);
if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
- MC_state_copy_incomplete_communications_pattern(this);
- MC_state_copy_index_communications_pattern(this);
+ mcapi::get().copy_incomplete_comm_pattern(this);
+ mcapi::get().copy_index_comm_pattern(this);
}
}
}
}
}
+
+ /* Search an enabled transition for the given process.
+ *
+ * This can be seen as an iterator returning the next transition of the process.
+ *
+ * We only consider the processes that are both
+ * - marked "to be interleaved" in their ActorState (controlled by the checker algorithm).
+ * - which simcall can currently be executed (like a comm where the other partner is already known)
+ * Once we returned the last enabled transition of a process, it is marked done.
+ *
+ * Things can get muddled with the WAITANY and TESTANY simcalls, that are rewritten on the fly to a bunch of WAIT
+ * (resp TEST) transitions using the transition.argument field to remember what was the last returned sub-transition.
+ */
+ static inline smx_simcall_t MC_state_choose_request_for_process(simgrid::mc::State* state, smx_actor_t actor)
+ {
+ using simgrid::simix::Simcall;
+
+ /* reset the outgoing transition */
+ simgrid::mc::ActorState* procstate = &state->actor_states_[actor->get_pid()];
+ state->transition_.pid_ = -1;
+ state->transition_.argument_ = -1;
+ state->executed_req_.call_ = Simcall::NONE;
+
+ if (not simgrid::mc::actor_is_enabled(actor))
+ return nullptr; // Not executable in the application
+
+ smx_simcall_t req = nullptr;
+ switch (actor->simcall_.call_) {
+ case Simcall::COMM_WAITANY:
+ state->transition_.argument_ = -1;
+ while (procstate->times_considered < simcall_comm_waitany__get__count(&actor->simcall_)) {
+ if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
+ state->transition_.argument_ = procstate->times_considered;
+ ++procstate->times_considered;
+ break;
+ }
+ ++procstate->times_considered;
+ }
+
+ if (procstate->times_considered >= simcall_comm_waitany__get__count(&actor->simcall_))
+ procstate->set_done();
+ if (state->transition_.argument_ != -1)
+ req = &actor->simcall_;
+ break;
+
+ case Simcall::COMM_TESTANY: {
+ unsigned start_count = procstate->times_considered;
+ state->transition_.argument_ = -1;
+ while (procstate->times_considered < simcall_comm_testany__get__count(&actor->simcall_)) {
+ if (simgrid::mc::request_is_enabled_by_idx(&actor->simcall_, procstate->times_considered)) {
+ state->transition_.argument_ = procstate->times_considered;
+ ++procstate->times_considered;
+ break;
+ }
+ ++procstate->times_considered;
+ }
+
+ if (procstate->times_considered >= simcall_comm_testany__get__count(&actor->simcall_))
+ procstate->set_done();
+
+ if (state->transition_.argument_ != -1 || start_count == 0)
+ req = &actor->simcall_;
+
+ break;
+ }
+
+ case Simcall::COMM_WAIT: {
+ simgrid::mc::RemotePtr<simgrid::kernel::activity::CommImpl> remote_act =
+ remote(simcall_comm_wait__getraw__comm(&actor->simcall_));
+ simgrid::mc::Remote<simgrid::kernel::activity::CommImpl> temp_act;
+ mc_model_checker->get_remote_simulation().read(temp_act, remote_act);
+ const simgrid::kernel::activity::CommImpl* act = temp_act.get_buffer();
+ if (act->src_actor_.get() && act->dst_actor_.get())
+ state->transition_.argument_ = 0; // OK
+ else if (act->src_actor_.get() == nullptr && act->type_ == simgrid::kernel::activity::CommImpl::Type::READY &&
+ act->detached())
+ state->transition_.argument_ = 0; // OK
+ else
+ state->transition_.argument_ = -1; // timeout
+ procstate->set_done();
+ req = &actor->simcall_;
+ break;
+ }
+
+ case Simcall::MC_RANDOM: {
+ int min_value = simcall_mc_random__get__min(&actor->simcall_);
+ state->transition_.argument_ = procstate->times_considered + min_value;
+ procstate->times_considered++;
+ if (state->transition_.argument_ == simcall_mc_random__get__max(&actor->simcall_))
+ procstate->set_done();
+ req = &actor->simcall_;
+ break;
+ }
+
+ default:
+ procstate->set_done();
+ state->transition_.argument_ = 0;
+ req = &actor->simcall_;
+ break;
+ }
+ if (not req)
+ return nullptr;
+
+ state->transition_.pid_ = actor->get_pid();
+ state->executed_req_ = *req;
+ // Fetch the data of the request and translate it:
+ state->internal_req_ = *req;
+
+ /* The waitany and testany request are transformed into a wait or test request over the corresponding communication
+ * action so it can be treated later by the dependence function. */
+ switch (req->call_) {
+ case Simcall::COMM_WAITANY: {
+ state->internal_req_.call_ = Simcall::COMM_WAIT;
+ simgrid::kernel::activity::CommImpl* remote_comm;
+ remote_comm = mc_model_checker->get_remote_simulation().read(
+ remote(simcall_comm_waitany__get__comms(req) + state->transition_.argument_));
+ mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
+ simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
+ simcall_comm_wait__set__timeout(&state->internal_req_, 0);
+ break;
+ }
+
+ case Simcall::COMM_TESTANY:
+ state->internal_req_.call_ = Simcall::COMM_TEST;
+
+ if (state->transition_.argument_ > 0) {
+ simgrid::kernel::activity::CommImpl* remote_comm = mc_model_checker->get_remote_simulation().read(
+ remote(simcall_comm_testany__get__comms(req) + state->transition_.argument_));
+ mc_model_checker->get_remote_simulation().read(state->internal_comm_, remote(remote_comm));
+ }
+
+ simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
+ simcall_comm_test__set__result(&state->internal_req_, state->transition_.argument_);
+ break;
+
+ case Simcall::COMM_WAIT:
+ mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
+ remote(simcall_comm_wait__getraw__comm(req)));
+ simcall_comm_wait__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
+ simcall_comm_wait__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
+ break;
+
+ case Simcall::COMM_TEST:
+ mc_model_checker->get_remote_simulation().read_bytes(&state->internal_comm_, sizeof(state->internal_comm_),
+ remote(simcall_comm_test__getraw__comm(req)));
+ simcall_comm_test__set__comm(&state->executed_req_, state->internal_comm_.get_buffer());
+ simcall_comm_test__set__comm(&state->internal_req_, state->internal_comm_.get_buffer());
+ break;
+
+ default:
+ /* No translation needed */
+ break;
+ }
+
+ return req;
+ }
+
+ smx_simcall_t MC_state_choose_request(simgrid::mc::State* state)
+ {
+ for (auto& actor : mc_model_checker->get_remote_simulation().actors()) {
+ /* Only consider the actors that were marked as interleaving by the checker algorithm */
+ if (not state->actor_states_[actor.copy.get_buffer()->get_pid()].is_todo())
+ continue;
+
+ smx_simcall_t res = MC_state_choose_request_for_process(state, actor.copy.get_buffer());
+ if (res)
+ return res;
+ }
+ return nullptr;
+ }
#ifndef SIMGRID_MC_STATE_HPP
#define SIMGRID_MC_STATE_HPP
-#include "src/kernel/activity/CommImpl.hpp"
#include "src/mc/Transition.hpp"
#include "src/mc/sosp/Snapshot.hpp"
+#include "src/mc/mc_pattern.hpp"
namespace simgrid {
namespace mc {
-enum class PatternCommunicationType {
- none = 0,
- send = 1,
- receive = 2,
-};
-
-class PatternCommunication {
-public:
- int num = 0;
- simgrid::kernel::activity::CommImpl* comm_addr;
- PatternCommunicationType type = PatternCommunicationType::send;
- unsigned long src_proc = 0;
- unsigned long dst_proc = 0;
- const char* src_host = nullptr;
- const char* dst_host = nullptr;
- std::string rdv;
- std::vector<char> data;
- int tag = 0;
- int index = 0;
-
- PatternCommunication() { std::memset(&comm_addr, 0, sizeof(comm_addr)); }
-
- PatternCommunication dup() const
- {
- simgrid::mc::PatternCommunication res;
- // num?
- res.comm_addr = this->comm_addr;
- res.type = this->type;
- // src_proc?
- // dst_proc?
- res.dst_proc = this->dst_proc;
- res.dst_host = this->dst_host;
- res.rdv = this->rdv;
- res.data = this->data;
- // tag?
- res.index = this->index;
- return res;
- }
-};
-
-/* On every state, each actor has an entry of the following type.
- * This represents both the actor and its transition because
- * an actor cannot have more than one enabled transition at a given time.
- */
-class ActorState {
- /* Possible exploration status of an actor transition in a state.
- * Either the checker did not consider the transition, or it was considered and still to do, or considered and done.
- */
- enum class InterleavingType {
- /** This actor transition is not considered by the checker (yet?) */
- disabled = 0,
- /** The checker algorithm decided that this actor transitions should be done at some point */
- todo,
- /** The checker algorithm decided that this should be done, but it was done in the meanwhile */
- done,
- };
-
- /** Exploration control information */
- InterleavingType state = InterleavingType::disabled;
-
-public:
- /** Number of times that the process was considered to be executed */
- // TODO, make this private
- unsigned int times_considered = 0;
-
- bool is_disabled() const { return this->state == InterleavingType::disabled; }
- bool is_done() const { return this->state == InterleavingType::done; }
- bool is_todo() const { return this->state == InterleavingType::todo; }
- /** Mark that we should try executing this process at some point in the future of the checker algorithm */
- void consider()
- {
- this->state = InterleavingType::todo;
- this->times_considered = 0;
- }
- void set_done() { this->state = InterleavingType::done; }
-};
-
/* A node in the exploration graph (kind-of) */
class XBT_PRIVATE State {
public:
/* Internal translation of the executed_req simcall
*
- * SIMCALL_COMM_TESTANY is translated to a SIMCALL_COMM_TEST
- * and SIMCALL_COMM_WAITANY to a SIMCALL_COMM_WAIT.
+ * Simcall::COMM_TESTANY is translated to a Simcall::COMM_TEST
+ * and Simcall::COMM_WAITANY to a Simcall::COMM_WAIT.
*/
s_smx_simcall internal_req_;