1 /* Copyright (c) 2016-2023. The SimGrid Team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "src/mc/explo/UdporChecker.hpp"
9 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to MC safety verification ");
11 namespace simgrid::mc::udpor {
13 UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args)
15 /* Create initial data structures, if any ...*/
16 XBT_INFO("Starting a UDPOR exploration");
18 // TODO: Initialize state structures for the search
21 void UdporChecker::run()
23 // NOTE: `A`, `D`, and `C` are derived from the
24 // original UDPOR paper [1], while
25 // `prev_exC` arises from the incremental computation
26 // of ex(C) from the former paper described in [3]
31 auto initial_state = get_current_state();
32 const auto initial_state_id = state_manager_.record_state(std::move(initial_state));
33 const auto root_event = std::make_unique<UnfoldingEvent>(-1, "", EventSet(), initial_state_id);
34 explore(std::move(C), std::move(A), std::move(D), {EventSet()}, root_event.get(), std::move(prev_exC));
36 XBT_INFO("UDPOR exploration terminated -- model checking completed");
39 void UdporChecker::explore(Configuration C, EventSet D, EventSet A, std::list<EventSet> max_evt_history,
40 UnfoldingEvent* cur_evt, EventSet prev_exC)
42 // Perform the incremental computation of exC
43 auto [exC, enC] = compute_extension(C, max_evt_history, *cur_evt, prev_exC);
45 // If enC is a subset of D, intuitively
46 // there aren't any enabled transitions
47 // which are "worth" exploring since their
48 // exploration would lead to a so-called
49 // "sleep-set blocked" trace.
50 if (enC.is_subset_of(D)) {
52 if (C.get_events().size() > 0) {
54 // g_var::nb_traces++;
56 // TODO: Log here correctly
57 // XBT_DEBUG("\n Exploring executions: %d : \n", g_var::nb_traces);
62 // When `en(C)` is empty, intuitively this means that there
63 // are no enabled transitions that can be executed from the
64 // state reached by `C` (denoted `state(C)`), i.e. by some
65 // execution of the transitions in C obeying the causality
66 // relation. Here, then, we would be in a deadlock.
68 get_remote_app().check_deadlock();
74 // TODO: Add verbose logging about which event is being explored
76 observe_unfolding_event(*cur_evt);
77 const auto next_state_id = record_newly_visited_state();
79 UnfoldingEvent* e = select_next_unfolding_event(A, enC);
80 xbt_assert(e != nullptr, "UDPOR guarantees that an event will be chosen at each point in"
81 "the search, yet no events were actually chosen");
82 e->set_state_id(next_state_id);
84 // TODO: Clean up configuration code before moving into the actual
85 // implementations of everything
87 // Configuration is the same + event e
92 max_evt_history.push_back(Ce.get_maxmimal_events());
96 // Explore(C + {e}, D, A \ {e})
97 explore(Ce, D, std::move(A), max_evt_history, e, std::move(exC));
102 // TODO: Determine a value of K to use or don't use it at all
103 constexpr unsigned K = 10;
104 auto J = compute_partial_alternative(D, C, K);
106 J.subtract(C.get_events());
107 max_evt_history.pop_back();
109 // Explore(C, D + {e}, J \ C)
110 explore(C, D, std::move(J), std::move(max_evt_history), cur_evt, std::move(prev_exC));
117 clean_up_explore(e, C, D);
120 std::tuple<EventSet, EventSet> UdporChecker::compute_extension(const Configuration& C,
121 const std::list<EventSet>& max_evt_history,
122 const UnfoldingEvent& cur_event,
123 const EventSet& prev_exC) const
125 // exC.remove(cur_event);
127 // TODO: Compute extend() as it exists in tiny_simgrid
130 return std::tuple<EventSet, EventSet>();
133 State& UdporChecker::get_state_referenced_by(const UnfoldingEvent& event)
135 const auto state_id = event.get_state_id();
136 const auto wrapped_state = this->state_manager_.get_state(state_id);
137 xbt_assert(wrapped_state != std::nullopt,
138 "\n\n****** FATAL ERROR ******\n"
139 "To each UDPOR event corresponds a state,"
140 "but state %lu does not exist\n"
141 "******************\n\n",
143 return wrapped_state.value().get();
146 void UdporChecker::observe_unfolding_event(const UnfoldingEvent& event)
148 auto& state = this->get_state_referenced_by(event);
149 const aid_t next_actor = state.next_transition();
150 xbt_assert(next_actor >= 0, "\n\n****** FATAL ERROR ******\n"
151 "In reaching this execution path, UDPOR ensures that at least one\n"
152 "one transition of the state of an visited event is enabled, yet no\n"
153 "state was actually enabled");
154 state.execute_next(next_actor);
157 StateHandle UdporChecker::record_newly_visited_state()
159 auto next_state = this->get_current_state();
160 const auto next_state_id = this->state_manager_.record_state(std::move(next_state));
162 // In UDPOR, we care about all enabled transitions in a given state
163 next_state->mark_all_enabled_todo();
164 return next_state_id;
167 UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
170 return *(enC.begin());
173 for (const auto& event : A) {
174 if (enC.contains(event)) {
181 EventSet UdporChecker::compute_partial_alternative(const EventSet& D, const Configuration& C, const unsigned k) const
183 // TODO: Compute k-partial alternatives using [2]
187 void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D)
189 // TODO: Perform clean up here
192 RecordTrace UdporChecker::get_record_trace()
198 std::vector<std::string> UdporChecker::get_textual_trace()
200 std::vector<std::string> trace;
204 } // namespace simgrid::mc::udpor
206 namespace simgrid::mc {
208 Exploration* create_udpor_checker(const std::vector<char*>& args)
210 return new simgrid::mc::udpor::UdporChecker(args);
213 } // namespace simgrid::mc