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 const 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));
37 void UdporChecker::explore(Configuration C, EventSet D, EventSet A, std::list<EventSet> max_evt_history,
38 UnfoldingEvent* cur_evt, EventSet prev_exC)
40 // Perform the incremental computation of exC
41 auto [exC, enC] = compute_extension(C, max_evt_history, *cur_evt, prev_exC);
43 // If enC is a subset of D, intuitively
44 // there aren't any enabled transitions
45 // which are "worth" exploring since their
46 // exploration would lead to a so-called
47 // "sleep-set blocked" trace.
48 if (enC.is_subset_of(D)) {
50 if (C.get_events().size() > 0) {
52 // g_var::nb_traces++;
54 // TODO: Log here correctly
55 // XBT_DEBUG("\n Exploring executions: %d : \n", g_var::nb_traces);
60 // When `en(C)` is empty, intuitively this means that there
61 // are no enabled transitions that can be executed from the
62 // state reached by `C` (denoted `state(C)`), i.e. by some
63 // execution of the transitions in C obeying the causality
64 // relation. Here, then, we would be in a deadlock.
66 get_remote_app().check_deadlock();
72 // TODO: Add verbose logging about which event is being explored
74 observe_unfolding_event(*cur_evt);
75 const auto next_state_id = record_newly_visited_state();
77 UnfoldingEvent* e = select_next_unfolding_event(A, enC);
78 xbt_assert(e != nullptr, "UDPOR guarantees that an event will be chosen at each point in"
79 "the search, yet no events were actually chosen");
80 e->set_state_id(next_state_id);
82 // TODO: Clean up configuration code before moving into the actual
83 // implementations of everything
85 // Configuration is the same + event e
90 max_evt_history.push_back(Ce.get_maxmimal_events());
94 // Explore(C + {e}, D, A \ {e})
95 explore(Ce, D, std::move(A), max_evt_history, e, std::move(exC));
100 // TODO: Determine a value of K to use or don't use it at all
101 constexpr unsigned K = 10;
102 auto J = compute_partial_alternative(D, C, K);
104 J.subtract(C.get_events());
105 max_evt_history.pop_back();
107 // Explore(C, D + {e}, J \ C)
108 explore(C, D, std::move(J), std::move(max_evt_history), cur_evt, std::move(prev_exC));
115 clean_up_explore(e, C, D);
118 std::tuple<EventSet, EventSet> UdporChecker::compute_extension(const Configuration& C,
119 const std::list<EventSet>& max_evt_history,
120 const UnfoldingEvent& cur_event,
121 const EventSet& prev_exC) const
123 // exC.remove(cur_event);
125 // TODO: Compute extend() as it exists in tiny_simgrid
128 return std::tuple<EventSet, EventSet>();
131 State& UdporChecker::get_state_referenced_by(const UnfoldingEvent& event)
133 const auto state_id = event.get_state_id();
134 const auto wrapped_state = this->state_manager_.get_state(state_id);
135 xbt_assert(wrapped_state != std::nullopt,
136 "\n\n****** FATAL ERROR ******\n"
137 "To each UDPOR event corresponds a state,"
138 "but state %lu does not exist\n"
139 "******************\n\n",
141 return wrapped_state.value().get();
144 void UdporChecker::observe_unfolding_event(const UnfoldingEvent& event)
146 auto& state = this->get_state_referenced_by(event);
147 const aid_t next_actor = state.next_transition();
148 xbt_assert(next_actor >= 0, "\n\n****** FATAL ERROR ******\n"
149 "In reaching this execution path, UDPOR ensures that at least one\n"
150 "one transition of the state of an visited event is enabled, yet no\n"
151 "state was actually enabled");
152 state.execute_next(next_actor);
155 StateHandle UdporChecker::record_newly_visited_state()
157 const auto next_state = this->get_current_state();
158 const auto next_state_id = this->state_manager_.record_state(std::move(next_state));
160 // In UDPOR, we care about all enabled transitions in a given state
161 next_state->mark_all_enabled_todo();
162 return next_state_id;
165 UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
167 // TODO: Actually select an event here
171 EventSet UdporChecker::compute_partial_alternative(const EventSet& D, const Configuration& C, const unsigned k) const
173 // TODO: Compute k-partial alternatives using [2]
177 void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D)
179 // TODO: Perform clean up here
182 RecordTrace UdporChecker::get_record_trace()
188 std::vector<std::string> UdporChecker::get_textual_trace()
190 std::vector<std::string> trace;
194 } // namespace simgrid::mc::udpor
196 namespace simgrid::mc {
198 Exploration* create_udpor_checker(const std::vector<char*>& args)
200 return new simgrid::mc::udpor::UdporChecker(args);
203 } // namespace simgrid::mc