spot 2.16
Loading...
Searching...
No Matches
deadlock.hh
1// -*- coding: utf-8 -*-
2// Copyright (C) by the Spot authors, see the AUTHORS file for details.
3//
4// This file is part of Spot, a model checking library.
5//
6// Spot is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 3 of the License, or
9// (at your option) any later version.
10//
11// Spot is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14// License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19#pragma once
20
21#include <atomic>
22#include <chrono>
23#include <spot/bricks/brick-hashset>
24#include <stdlib.h>
25#include <thread>
26#include <vector>
27#include <spot/misc/common.hh>
28#include <spot/kripke/kripke.hh>
29#include <spot/misc/fixpool.hh>
30#include <spot/misc/timer.hh>
31#include <spot/twacube/twacube.hh>
32#include <spot/twacube/fwd.hh>
33#include <spot/mc/mc.hh>
34
35namespace spot
36{
43 template<typename State, typename SuccIterator,
44 typename StateHash, typename StateEqual,
45 typename Deadlock>
46 class SPOT_API swarmed_deadlock
47 {
49 enum st_status
50 {
51 UNKNOWN = 1, // First time this state is discovered by this thread
52 OPEN = 2, // The state is currently processed by this thread
53 CLOSED = 4, // All the successors of this state have been visited
54 };
55
57 struct deadlock_pair
58 {
59 State st;
60 int* colors;
61 };
62
64 struct pair_hasher
65 {
66 pair_hasher(const deadlock_pair*)
67 { }
68
69 pair_hasher() = default;
70
71 brick::hash::hash128_t
72 hash(const deadlock_pair* lhs) const
73 {
74 StateHash hash;
75 // Not modulo 31 according to brick::hashset specifications.
76 unsigned u = hash(lhs->st) % (1<<30);
77 return {u, u};
78 }
79
80 bool equal(const deadlock_pair* lhs,
81 const deadlock_pair* rhs) const
82 {
83 StateEqual equal;
84 return equal(lhs->st, rhs->st);
85 }
86 };
87
88 static constexpr bool compute_deadlock =
89 std::is_same<std::true_type, Deadlock>::value;
90
91 public:
92
94 using shared_map = brick::hashset::FastConcurrent <deadlock_pair*,
95 pair_hasher>;
98
101 {
102 return nullptr; // Useless
103 }
104
107 twacube_ptr, /* useless here */
108 shared_map& map, shared_struct* /* useless here */,
109 unsigned tid,
110 std::atomic<bool>& stop):
111 sys_(sys), tid_(tid), map_(map),
112 nb_th_(std::thread::hardware_concurrency()),
113 p_(sizeof(int)*std::thread::hardware_concurrency()),
114 p_pair_(sizeof(deadlock_pair)),
115 stop_(stop)
116 {
117 static_assert(spot::is_a_kripkecube_ptr<decltype(&sys),
118 State, SuccIterator>::value,
119 "error: does not match the kripkecube requirements");
120 SPOT_ASSERT(nb_th_ > tid);
121 }
122
123 virtual ~swarmed_deadlock()
124 {
125 while (!todo_.empty())
126 {
127 sys_.recycle(todo_.back().it, tid_);
128 todo_.pop_back();
129 }
130 }
131
133 void run()
134 {
135 setup();
136 State initial = sys_.initial(tid_);
137 if (SPOT_LIKELY(push(initial)))
138 {
139 todo_.push_back({initial, sys_.succ(initial, tid_), transitions_});
140 }
141 while (!todo_.empty() && !stop_.load(std::memory_order_relaxed))
142 {
143 if (todo_.back().it->done())
144 {
145 if (SPOT_LIKELY(pop()))
146 {
147 deadlock_ = todo_.back().current_tr == transitions_;
148 if (compute_deadlock && deadlock_)
149 break;
150 sys_.recycle(todo_.back().it, tid_);
151 todo_.pop_back();
152 }
153 }
154 else
155 {
156 ++transitions_;
157 State dst = todo_.back().it->state();
158
159 if (SPOT_LIKELY(push(dst)))
160 {
161 todo_.back().it->next();
162 todo_.push_back({dst, sys_.succ(dst, tid_), transitions_});
163 }
164 else
165 {
166 todo_.back().it->next();
167 }
168 }
169 }
170 finalize();
171 }
172
174 void setup()
175 {
176 tm_.start("DFS thread " + std::to_string(tid_));
177 }
178
180 bool push(State s)
181 {
182 // Prepare data for a newer allocation
183 int* ref = (int*) p_.allocate();
184 for (unsigned i = 0; i < nb_th_; ++i)
185 ref[i] = UNKNOWN;
186
187 // Try to insert the new state in the shared map.
188 deadlock_pair* v = (deadlock_pair*) p_pair_.allocate();
189 v->st = s;
190 v->colors = ref;
191 auto it = map_.insert(v);
192 bool b = it.isnew();
193
194 // Insertion failed, delete element
195 // FIXME Should we add a local cache to avoid useless allocations?
196 if (!b)
197 p_.deallocate(ref);
198
199 // The state has been marked dead by another thread
200 for (unsigned i = 0; !b && i < nb_th_; ++i)
201 if ((*it)->colors[i] == static_cast<int>(CLOSED))
202 return false;
203
204 // The state has already been visited by the current thread
205 if ((*it)->colors[tid_] == static_cast<int>(OPEN))
206 return false;
207
208 // Keep a ptr over the array of colors
209 refs_.push_back((*it)->colors);
210
211 // Mark state as visited.
212 (*it)->colors[tid_] = OPEN;
213 ++states_;
214 return true;
215 }
216
218 bool pop()
219 {
220 // Track maximum dfs size
221 dfs_ = todo_.size() > dfs_ ? todo_.size() : dfs_;
222
223 // Don't avoid pop but modify the status of the state
224 // during backtrack
225 refs_.back()[tid_] = CLOSED;
226 refs_.pop_back();
227 return true;
228 }
229
231 void finalize()
232 {
233 bool tst_val = false;
234 bool new_val = true;
235 bool exchanged = stop_.compare_exchange_strong(tst_val, new_val);
236 if (exchanged)
237 finisher_ = true;
238 tm_.stop("DFS thread " + std::to_string(tid_));
239 }
240
242 bool finisher()
243 {
244 return finisher_;
245 }
246
248 unsigned states()
249 {
250 return states_;
251 }
252
254 unsigned transitions()
255 {
256 return transitions_;
257 }
258
260 unsigned walltime()
261 {
262 return tm_.timer("DFS thread " + std::to_string(tid_)).walltime();
263 }
264
266 std::string name()
267 {
268 if (compute_deadlock)
269 return "deadlock";
270 return "reachability";
271 }
272
274 int sccs()
275 {
276 return -1;
277 }
278
281 {
282 if (compute_deadlock)
283 return deadlock_ ? mc_rvalue::DEADLOCK : mc_rvalue::NO_DEADLOCK;
284 return mc_rvalue::SUCCESS;
285 }
286
288 std::string trace()
289 {
290 std::string result;
291 for (auto& e: todo_)
292 result += sys_.to_string(e.s, tid_);
293 return result;
294 }
295
296 private:
297 struct todo_element
298 {
299 State s;
300 SuccIterator* it;
301 unsigned current_tr;
302 };
303 kripkecube<State, SuccIterator>& sys_;
304 std::vector<todo_element> todo_;
305 unsigned transitions_ = 0;
306 unsigned tid_;
307 shared_map map_;
308 spot::timer_map tm_;
309 unsigned states_ = 0;
310 unsigned dfs_ = 0;
312 unsigned nb_th_ = 0;
313 fixed_size_pool<pool_type::Unsafe> p_;
314 fixed_size_pool<pool_type::Unsafe> p_pair_;
315 bool deadlock_ = false;
316 std::atomic<bool>& stop_;
319 std::vector<int*> refs_;
320 bool finisher_ = false;
321 };
322}
This class allows to ensure (at compile time) if a given parameter is of type kripkecube....
Definition kripke.hh:71
This class is a template representation of a Kripke structure. It is composed of two template paramet...
Definition kripke.hh:40
This class aims to explore a model to detect whether it contains a deadlock. This deadlock detection ...
Definition deadlock.hh:47
unsigned transitions()
Return number of transitions traversed.
Definition deadlock.hh:254
mc_rvalue result()
Return deadlock detection result.
Definition deadlock.hh:280
bool pop()
Pop state from stack.
Definition deadlock.hh:218
static shared_struct * make_shared_structure(shared_map, unsigned)
Create shared structure for thread tid.
Definition deadlock.hh:100
void finalize()
Finalize thread resources.
Definition deadlock.hh:231
std::string trace()
Return trace.
Definition deadlock.hh:288
swarmed_deadlock(kripkecube< State, SuccIterator > &sys, twacube_ptr, shared_map &map, shared_struct *, unsigned tid, std::atomic< bool > &stop)
Constructor for parallel deadlock detection.
Definition deadlock.hh:106
std::string name()
Return algorithm name.
Definition deadlock.hh:266
int sccs()
Return number of SCCs found (returns -1)
Definition deadlock.hh:274
shared_map shared_struct
Type alias for shared structure.
Definition deadlock.hh:97
bool push(State s)
Push state onto stack.
Definition deadlock.hh:180
void run()
Run the algorithm.
Definition deadlock.hh:133
void setup()
Setup thread resources.
Definition deadlock.hh:174
unsigned states()
Return number of states visited.
Definition deadlock.hh:248
bool finisher()
Check if this thread finished the search.
Definition deadlock.hh:242
unsigned walltime()
Return wall time in milliseconds.
Definition deadlock.hh:260
brick::hashset::FastConcurrent< deadlock_pair *, pair_hasher > shared_map
Concurrent hashset for shared state storage.
Definition deadlock.hh:95
A map of timer, where each timer has a name.
Definition timer.hh:231
std::shared_ptr< twacube > twacube_ptr
Definition fwd.hh:28
Definition automata.hh:26
mc_rvalue
Return value of a parallel model-checking algorithm.
Definition mc.hh:50

Please direct any question, comment, or bug report to the Spot mailing list at spot@lrde.epita.fr.
Generated on Fri Feb 27 2015 10:00:07 for spot by doxygen 1.9.8