spot  2.16
mc_instanciator.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 <spot/misc/common.hh>
22 #include <spot/misc/_config.h>
23 #include <string>
24 #include <thread>
25 #include <vector>
26 #include <utility>
27 #include <atomic>
28 #include <spot/kripke/kripke.hh>
29 #include <spot/mc/mc.hh>
30 #include <spot/mc/lpar13.hh>
31 #include <spot/mc/deadlock.hh>
32 #include <spot/mc/cndfs.hh>
33 #include <spot/mc/bloemen.hh>
34 #include <spot/mc/bloemen_ec.hh>
35 #include <spot/misc/timer.hh>
36 
37 namespace spot
38 {
39 
40 #if defined(__cpp_concepts) && __cpp_concepts >= 201907L
44  template<typename T>
45  concept is_a_mc_algorithm = requires(T u)
46  {
47  u->setup();
48  u->run();
49  u->finalize();
50  { u->finisher() } -> std::same_as<bool>;
51  { u->states() } -> std::same_as<unsigned>;
52  { u->transitions() } -> std::same_as<unsigned>;
53  { u->walltime() } -> std::same_as<unsigned>;
54  { u->name() } -> std::same_as<std::string>;
55  { u->sccs() } -> std::same_as<int>;
56  { u->result() } -> std::same_as<mc_rvalue>;
57  { u->trace() } -> std::same_as<std::string>;
58  };
59 #endif
60 
61 
62  template<typename algo_name, typename kripke_ptr, typename State,
63  typename Iterator, typename Hash, typename Equal>
64  static ec_stats instanciate(kripke_ptr sys,
65  spot::twacube_ptr prop = nullptr,
66  bool trace = false)
67  {
68  spot::timer_map tm;
69  std::atomic<bool> stop(false);
70  unsigned nbth = sys->get_threads();
71 
72  typename algo_name::shared_map map;
73  std::vector<algo_name*> swarmed(nbth);
74 
75  // The shared structure requires sometimes one instance per thread
76  using struct_name = typename algo_name::shared_struct;
77  std::vector<struct_name*> ss(nbth);
78 
79  tm.start("Initialisation");
80  for (unsigned i = 0; i < nbth; ++i)
81  {
82  ss[i] = algo_name::make_shared_structure(map, i);
83  swarmed[i] = new algo_name(*sys, prop, map, ss[i], i, stop);
84 
85 #if defined(__cpp_concepts) && __cpp_concepts >= 201907L
86  static_assert(spot::is_a_mc_algorithm<decltype(&*swarmed[i])>,
87  "error: does not match the mc_algorithm requirements");
88 #endif
89 
90  }
91  tm.stop("Initialisation");
92 
93  // Spawn Threads
94  std::mutex iomutex;
95  std::atomic<bool> barrier(true);
96  std::vector<std::thread> threads(nbth);
97  for (unsigned i = 0; i < nbth; ++i)
98  {
99  threads[i] = std::thread ([&swarmed, &iomutex, i, &barrier]
100  {
101 #ifdef SPOT_HAVE_SCHED_GETCPU
102  {
103  std::lock_guard<std::mutex> iolock(iomutex);
104  std::cout << "Thread #" << i
105  << ": on CPU " << sched_getcpu() << '\n';
106  }
107 #endif
108 
109  // Wait all threads to be instantiated.
110  while (barrier)
111  continue;
112  swarmed[i]->run();
113  });
114 
115 #ifdef SPOT_PTHREAD_SETAFFINITY_NP
116  // Pin threads to a dedicated core.
117  cpu_set_t cpuset;
118  CPU_ZERO(&cpuset);
119  CPU_SET(i, &cpuset);
120  int rc = pthread_setaffinity_np(threads[i].native_handle(),
121  sizeof(cpu_set_t), &cpuset);
122  if (rc != 0)
123  {
124  std::lock_guard<std::mutex> iolock(iomutex);
125  std::cerr << "Error calling pthread_setaffinity_np: " << rc << '\n';
126  }
127 #endif
128  }
129 
130  tm.start("Run");
131  barrier.store(false);
132 
133  for (auto& t: threads)
134  t.join();
135  tm.stop("Run");
136 
137  // Build the result
138  ec_stats result;
139  for (unsigned i = 0; i < nbth; ++i)
140  {
141  result.name.emplace_back(swarmed[i]->name());
142  result.walltime.emplace_back(swarmed[i]->walltime());
143  result.states.emplace_back(swarmed[i]->states());
144  result.transitions.emplace_back(swarmed[i]->transitions());
145  result.sccs.emplace_back(swarmed[i]->sccs());
146  result.value.emplace_back(swarmed[i]->result());
147  result.finisher.emplace_back(swarmed[i]->finisher());
148  }
149 
150  if (trace)
151  {
152  bool go_on = true;
153  for (unsigned i = 0; i < nbth && go_on; ++i)
154  {
155  // Enumerate cases where a trace can be extracted
156  // Here we use a switch so that adding new algorithm
157  // with new return status will trigger an error that
158  // should then be fixed here.
159  switch (result.value[i])
160  {
161  // A (partial?) trace has been computed
162  case mc_rvalue::DEADLOCK:
164  result.trace = swarmed[i]->trace();
165  go_on = false;
166  break;
167 
168  // Nothing to do here.
170  case mc_rvalue::EMPTY:
171  case mc_rvalue::SUCCESS:
172  case mc_rvalue::FAILURE:
173  break;
174  }
175  }
176  }
177 
178  for (unsigned i = 0; i < nbth; ++i)
179  {
180  delete swarmed[i];
181  delete ss[i];
182  }
183 
184  return result;
185  }
186 
187  template<typename kripke_ptr, typename State,
188  typename Iterator, typename Hash, typename Equal>
189  static ec_stats ec_instanciator(const mc_algorithm algo, kripke_ptr sys,
190  spot::twacube_ptr prop = nullptr,
191  bool trace = false)
192  {
193  if (algo == mc_algorithm::BLOEMEN_EC || algo == mc_algorithm::CNDFS ||
194  algo == mc_algorithm::SWARMING)
195  {
196  SPOT_ASSERT(prop != nullptr);
197  SPOT_ASSERT(sys->ap().size() == prop->ap().size());
198  for (unsigned int i = 0; i < sys->ap().size(); ++i)
199  SPOT_ASSERT(sys->ap()[i].compare(prop->ap()[i]) == 0);
200  }
201 
202  switch (algo)
203  {
205  return instanciate<spot::swarmed_bloemen<State, Iterator, Hash, Equal>,
206  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
207 
209  return
210  instanciate<spot::swarmed_bloemen_ec<State, Iterator, Hash, Equal>,
211  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
212 
213  case mc_algorithm::CNDFS:
214  return instanciate<spot::swarmed_cndfs<State, Iterator, Hash, Equal>,
215  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
216 
218  return instanciate
220  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
221 
223  return instanciate
225  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
226 
228  return instanciate<spot::lpar13<State, Iterator, Hash, Equal>,
229  kripke_ptr, State, Iterator, Hash, Equal> (sys, prop, trace);
230  }
231  SPOT_UNREACHABLE();
232  }
233 }
This class aims to explore a model to detect whether it contains a deadlock. This deadlock detection ...
Definition: deadlock.hh:47
A map of timer, where each timer has a name.
Definition: timer.hh:231
void stop(const std::string &name)
Stop timer name.
Definition: timer.hh:251
void start(const std::string &name)
Start a timer with name name.
Definition: timer.hh:240
std::shared_ptr< kripke > kripke_ptr
Definition: fwd.hh:33
std::shared_ptr< twacube > twacube_ptr
Definition: fwd.hh:25
Definition: automata.hh:26
mc_algorithm
The list of parallel model-checking algorithms available.
Definition: mc.hh:39
@ CNDFS
Evangelista.12.atva emptiness check.
@ REACHABILITY
Only perform a reachability algorithm.
@ SWARMING
Holzmann.11.ieee applied to renault.13.lpar.
@ DEADLOCK
Check whether there is a deadlock.
@ BLOEMEN_SCC
Bloemen.16.ppopp SCC computation.
@ BLOEMEN_EC
Bloemen.16.hvc emptiness check.
@ NOT_EMPTY
The product is not empty.
@ NO_DEADLOCK
No deadlock has been found.
@ FAILURE
The algorithm finished abnormally.
@ DEADLOCK
A deadlock has been found.
@ EMPTY
The product is empty.
@ SUCCESS
The algorithm finished normally.

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.1