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"
7 #include <xbt/asserts.h>
10 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_udpor, mc, "Logging specific to verification using UDPOR");
12 namespace simgrid::mc::udpor {
14 UdporChecker::UdporChecker(const std::vector<char*>& args) : Exploration(args)
16 /* Create initial data structures, if any ...*/
18 // TODO: Initialize state structures for the search
21 void UdporChecker::run()
23 XBT_INFO("Starting a UDPOR exploration");
24 // NOTE: `A`, `D`, and `C` are derived from the
25 // original UDPOR paper [1], while `prev_exC` arises
26 // from the incremental computation of ex(C) from [3]
29 // TODO: Move computing the root configuration into a method on the Unfolding
30 auto initial_state = get_current_state();
31 auto root_event = std::make_unique<UnfoldingEvent>(std::make_shared<Transition>(), EventSet());
32 auto* root_event_handle = root_event.get();
33 unfolding.insert(std::move(root_event));
34 C_root.add_event(root_event_handle);
36 explore(std::move(C_root), EventSet(), EventSet(), std::move(initial_state), EventSet());
38 XBT_INFO("UDPOR exploration terminated -- model checking completed");
41 void UdporChecker::explore(Configuration C, EventSet D, EventSet A, std::unique_ptr<State> stateC, EventSet prev_exC)
43 // Perform the incremental computation of exC
45 // TODO: This method will have side effects on
46 // the unfolding, but the naming of the method
47 // suggests it is doesn't have side effects. We should
48 // reconcile this in the future
49 auto [exC, enC] = compute_extension(C, prev_exC);
51 // If enC is a subset of D, intuitively
52 // there aren't any enabled transitions
53 // which are "worth" exploring since their
54 // exploration would lead to a so-called
55 // "sleep-set blocked" trace.
56 if (enC.is_subset_of(D)) {
58 if (C.get_events().size() > 0) {
60 // g_var::nb_traces++;
62 // TODO: Log here correctly
63 // XBT_DEBUG("\n Exploring executions: %d : \n", g_var::nb_traces);
68 // When `en(C)` is empty, intuitively this means that there
69 // are no enabled transitions that can be executed from the
70 // state reached by `C` (denoted `state(C)`), i.e. by some
71 // execution of the transitions in C obeying the causality
72 // relation. Here, then, we would be in a deadlock.
74 get_remote_app().check_deadlock();
80 // TODO: Add verbose logging about which event is being explored
82 UnfoldingEvent* e = select_next_unfolding_event(A, enC);
83 xbt_assert(e != nullptr, "\n\n****** INVARIANT VIOLATION ******\n"
84 "UDPOR guarantees that an event will be chosen at each point in\n"
85 "the search, yet no events were actually chosen\n"
86 "*********************************\n\n");
88 // Move the application into stateCe and actually make note of that state
89 move_to_stateCe(*stateC, *e);
90 auto stateCe = record_current_state();
99 // Explore(C + {e}, D, A \ {e})
100 explore(Ce, D, std::move(A), std::move(stateCe), std::move(exC));
105 // TODO: Determine a value of K to use or don't use it at all
106 constexpr unsigned K = 10;
107 auto J = compute_partial_alternative(D, C, K);
109 J.subtract(C.get_events());
111 // Before searching the "right half", we need to make
112 // sure the program actually reflects the fact
113 // that we are searching again from `stateC` (the recursive
114 // search moved the program into `stateCe`)
115 restore_program_state_to(*stateC);
117 // Explore(C, D + {e}, J \ C)
118 explore(C, D, std::move(J), std::move(stateC), std::move(prev_exC));
125 clean_up_explore(e, C, D);
128 std::tuple<EventSet, EventSet> UdporChecker::compute_extension(const Configuration& C, const EventSet& prev_exC) const
130 // See eqs. 5.7 of section 5.2 of [3]
131 // C = C' + {e_cur}, i.e. C' = C - {e_cur}
135 // ex(C) = ex(C' + {e_cur}) = ex(C') / {e_cur} + U{<a, > : H }
136 UnfoldingEvent* e_cur = C.get_latest_event();
137 EventSet exC = prev_exC;
140 // ... fancy computations
143 return std::tuple<EventSet, EventSet>(exC, enC);
146 void UdporChecker::move_to_stateCe(State& state, const UnfoldingEvent& e)
148 const aid_t next_actor = e.get_transition()->aid_;
150 // TODO: Add the trace if possible for reporting a bug
151 xbt_assert(next_actor >= 0, "\n\n****** INVARIANT VIOLATION ******\n"
152 "In reaching this execution path, UDPOR ensures that at least one\n"
153 "one transition of the state of an visited event is enabled, yet no\n"
154 "state was actually enabled. Please report this as a bug.\n"
155 "*********************************\n\n");
156 state.execute_next(next_actor);
159 void UdporChecker::restore_program_state_to(const State& stateC)
161 // TODO: Perform state regeneration in the same manner as is done
162 // in the DFSChecker.cpp
165 std::unique_ptr<State> UdporChecker::record_current_state()
167 auto next_state = this->get_current_state();
169 // In UDPOR, we care about all enabled transitions in a given state
170 next_state->mark_all_enabled_todo();
175 UnfoldingEvent* UdporChecker::select_next_unfolding_event(const EventSet& A, const EventSet& enC)
178 return *(enC.begin());
181 for (const auto& event : A) {
182 if (enC.contains(event)) {
189 EventSet UdporChecker::compute_partial_alternative(const EventSet& D, const Configuration& C, const unsigned k) const
191 // TODO: Compute k-partial alternatives using [2]
195 void UdporChecker::clean_up_explore(const UnfoldingEvent* e, const Configuration& C, const EventSet& D)
197 // TODO: Perform clean up here
200 RecordTrace UdporChecker::get_record_trace()
206 std::vector<std::string> UdporChecker::get_textual_trace()
208 // TODO: Topologically sort the events of the latest configuration
209 // and iterate through that topological sorting
210 std::vector<std::string> trace;
214 } // namespace simgrid::mc::udpor
216 namespace simgrid::mc {
218 Exploration* create_udpor_checker(const std::vector<char*>& args)
220 return new simgrid::mc::udpor::UdporChecker(args);
223 } // namespace simgrid::mc