ROSE  0.11.50.0
Engine.h
1 #ifndef ROSE_BinaryAnalysis_ModelChecker_Engine_H
2 #define ROSE_BinaryAnalysis_ModelChecker_Engine_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_BINARY_ANALYSIS
5 
6 #include <Rose/BinaryAnalysis/ModelChecker/PathQueue.h>
7 
8 #include <Rose/BinaryAnalysis/InstructionSemantics2/BaseSemantics/Types.h>
9 #include <Rose/BinaryAnalysis/SmtSolver.h>
10 #include <Rose/BinaryAnalysis/Partitioner2/BasicTypes.h>
11 #include <Sawyer/Stopwatch.h>
12 #include <thread>
13 
14 namespace Rose {
15 namespace BinaryAnalysis {
16 namespace ModelChecker {
17 
38 class Engine final {
40  // Types
42 public:
44  using Ptr = EnginePtr;
45 
47  struct InProgress {
48  InProgress();
49  explicit InProgress(const PathPtr&);
50  ~InProgress();
51 
52  PathPtr path;
54  boost::thread::id threadId;
55  };
56 
58  // Data members
60 private:
61  PathQueue frontier_; // paths with work remaining
62  PathQueue interesting_; // paths that are interesting, placed here by workers
63  SemanticCallbacksPtr semantics_; // various configurable semantic operations
64 
65  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects all following data members
66  Sawyer::Container::Map<boost::thread::id, InProgress> inProgress_;// work that is in progress
67  SAWYER_THREAD_TRAITS::ConditionVariable newWork_; // signaled when work arrives or thread finishes
68  SAWYER_THREAD_TRAITS::ConditionVariable newInteresting_; // signaled when interesting paths arrive or threads finish
69  PathPredicatePtr frontierPredicate_; // predicate for inserting paths into the "frontier" queue
70  PathPredicatePtr interestingPredicate_; // predicate for inserting paths into the "interesting" queue
71  SettingsPtr settings_; // overall settings
72  std::vector<std::thread> workers_; // managed worker threads
73  size_t workCapacity_ = 0; // managed workers plus user threads
74  size_t nWorking_ = 0; // number of threads currently doing work
75  size_t nPathsExplored_ = 0; // number of path nodes executed, i.e., number of paths explored
76  size_t nStepsExplored_ = 0; // number of steps executed
77  bool stopping_ = false; // when true, workers stop even if there is still work remaining
78  std::vector<std::pair<double, size_t>> fanout_; // total fanout and number of nodes for each level of the forest
79  size_t nFanoutRoots_ = 0; // number of execution trees for calculating total forest size
80  Sawyer::Stopwatch elapsedTime_; // time since model checking started
81  mutable Sawyer::Stopwatch timeSinceStats_; // time since last statistics were reported
82  mutable size_t nPathsStats_ = 0; // number of paths reported in last statistics output
83 
84 protected:
85  Engine() = delete;
86  explicit Engine(const SettingsPtr&);
87 
88 public:
92  static Ptr instance();
93 
97  static Ptr instance(const SettingsPtr&);
98 
102  ~Engine();
103 
105  // Configuration functions
107 public:
116  SettingsPtr settings() const;
117  void settings(const SettingsPtr&);
128  SemanticCallbacksPtr semantics() const;
129  void semantics(const SemanticCallbacksPtr&);
146  PathPrioritizerPtr explorationPrioritizer() const;
147  void explorationPrioritizer(const PathPrioritizerPtr&);
161  PathPredicatePtr explorationPredicate() const;
162  void explorationPredicate(const PathPredicatePtr&);
177  PathPredicatePtr interestingPredicate() const;
178  void interestingPredicate(const PathPredicatePtr&);
182  // Initialization functions
185 public:
191  void reset();
192 
205  void insertStartingPoint(const ExecutionUnitPtr&);
206  void insertStartingPoint(const PathPtr&);
210  // Model checker execution
213 public:
230  void startWorkers(size_t n = 0);
231 
243  void run();
244 
251  void stop();
252 
261  bool step();
262 
271  bool workRemains() const;
272 
280  size_t workCapacity() const;
281 
288  size_t nWorking() const;
289 
295  size_t nPathsPending() const;
296 
298  // Model checker results
300 public:
307 
313  size_t nPathsExplored() const;
314 
321  size_t nStepsExplored() const;
322 
331  const PathQueue& pendingPaths() const;
332 
343  const PathQueue& interesting() const;
359  PathPtr takeNextInteresting();
360 
367  void finishPath();
368 
374  std::vector<InProgress> inProgress() const;
375 
383  bool insertInteresting(const PathPtr&);
384 
391  double estimatedForestSize(size_t k) const;
392 
396  void showStatistics(std::ostream&, const std::string &prefix = "") const;
397 
399  // Worker functions. It is useful to call these from user code.
401 public:
409  bool insertWork(const PathPtr&);
410 
412  // Internal stuff.
414 private:
415  // Update the fanout parameters used to estimate execution tree size. The nChildren are the number of new paths created by
416  // extending the current path, totalSteps is the number of steps in the whole path, and lastSteps is the number of steps in
417  // the last node of the path.
418  void updateFanout(size_t nChildren, size_t totalSteps, size_t lastSteps);
419 
420  // Called by each worker thread when they start. Users should not call this even though it's public.
421  void worker();
422 
423  // Worker states.
424  enum class WorkerState {
425  STARTING, // thread is initializing
426  WAITING, // thread is looking for new work
427  WORKING, // thread is actively working on a path
428  FINISHED // thread will never work again and is cleaning up
429  };
430 
431  // Change state. The thread should hold its current state in a local variable. The state transition edges affect how
432  // various counters are updated. All threads must start by initializing their current state to STARTING and then calling
433  // changeState to also specify the new state is STARTING. Only certain transitions are allowed--read the source.
434  void changeState(WorkerState &currentState, WorkerState newState);
435 
436  // Non-synchronized version of changeState
437  void changeStateNS(WorkerState &currentState, WorkerState newState);
438 
439  // Do things that should be done when work is started.
440  void startWorkingNS();
441 
442  // Called by changeState when a worker has finished.
443  void finishWorkingNS();
444 
445  // Get the next path on which to work. This function blocks until either more work is available, or no more work can
446  // possibly be available. In the former case, it removes the highest priority path from the work queue, changes the work
447  // state to WORKING, and returns the path. In the latter case, it returns a null pointer.
448  //
449  // Thread safety: This method is thread safe.
450  PathPtr takeNextWorkItem(WorkerState&);
451 
452  // Non-blocking version of takeNextWorkItem.
453  PathPtr takeNextWorkItemNow(WorkerState&);
454 
455  // Execute a path. This goes back as far as necessary to get a known state, and then executes from there to the end
456  // of the path.
457  //
458  // After a path is executed, it is conditionally added to the "interesting" queue according to the @ref
459  // interestingPredicate.
460  //
461  // The solver argument is the solver used by model checker, which might be different than the optional solver already
462  // attached to the RiscOperators object.
463  //
464  // Thread safety: The RISC operators must be thread-local, otherwise thread safe. All paths will have an identical
465  // set of states for this path after this returns.
466  void execute(const PathPtr&, const InstructionSemantics2::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
467 
468  // Produce more work, typically by looking at the instruction pointer register for the outgoing state of a previous
469  // path (which is not currently in the work queue) and creating new paths.
470  void extend(const PathPtr&, const InstructionSemantics2::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
471 
472  // Perform one step of model checking.
473  void doOneStep(const PathPtr&, const InstructionSemantics2::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
474 };
475 
476 
477 } // namespace
478 } // namespace
479 } // namespace
480 
481 #endif
482 #endif
SmtSolverPtr Ptr
Reference counting pointer for SMT solvers.
Definition: SmtSolver.h:39
void reset()
Reset engine to initial state.
boost::shared_ptr< RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to a RISC operators object.
Sawyer::Stopwatch elapsed
Wall clock time elapsed for this work.
Definition: Engine.h:53
SemanticCallbacksPtr semantics() const
Property: Adjustments to semantic operations.
PathPrioritizerPtr explorationPrioritizer() const
Property: Path exploration prioritizer.
void showStatistics(std::ostream &, const std::string &prefix="") const
Print some statistics.
void finishPath()
Indicates that a path has been finished.
boost::thread::id threadId
Identifier for thread doing the work.
Definition: Engine.h:54
void insertStartingPoint(const ExecutionUnitPtr &)
Insert a path starting point.
size_t nPathsExplored() const
Property: Number of paths explored.
Information about a path that is in progress.
Definition: Engine.h:47
const PathQueue & pendingPaths() const
Property: Paths waiting to be explored.
Main class for model checking.
Definition: Engine.h:38
size_t workCapacity() const
Work capacity.
PathPtr path
The path being worked on.
Definition: Engine.h:52
const PathQueue & interesting() const
Property: The interesting results queue.
Main namespace for the ROSE library.
double estimatedForestSize(size_t k) const
Estimated execution forest size to K levels.
EnginePtr Ptr
Reference counting pointer.
Definition: Engine.h:44
Simple elapsed time.
Definition: Stopwatch.h:41
List of path endpoints in an execution tree.
Definition: PathQueue.h:16
SettingsPtr settings() const
Property: Settings.
PathPredicatePtr interestingPredicate() const
Property: Interesting insertion predicate.
PathPredicatePtr explorationPredicate() const
Property: Work insertion predicate.
size_t nWorking() const
Number of threads that are working.
bool insertWork(const PathPtr &)
Insert a path into the execution tree.
size_t nPathsPending() const
Number of paths to explore.
bool insertInteresting(const PathPtr &)
Potentially insert a path into the interesting queue.
std::vector< InProgress > inProgress() const
Paths that are currently in progress.
void stop()
Complete all current work and then stop.
void startWorkers(size_t n=0)
Start multiple worker threads.
PathPtr takeNextInteresting()
Take next interesting result.
bool workRemains() const
Test whether work remains to be done.
static Ptr instance()
Allocating constructor.
bool step()
Run one step of checking in the calling thread.
size_t nStepsExplored() const
Property: Number of steps explored.
Sawyer::Stopwatch elapsedTime() const
Property: Elapsed time for model checking.
Container associating values with keys.
Definition: Sawyer/Map.h:66