ROSE  0.11.145.0
ModelChecker/Engine.h
1 #ifndef ROSE_BinaryAnalysis_ModelChecker_Engine_H
2 #define ROSE_BinaryAnalysis_ModelChecker_Engine_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_MODEL_CHECKER
5 
6 #include <Rose/BinaryAnalysis/ModelChecker/PathQueue.h>
7 
8 #include <Rose/BinaryAnalysis/InstructionSemantics/BaseSemantics/BasicTypes.h>
9 #include <Rose/BinaryAnalysis/SmtSolver.h>
10 #include <Rose/BinaryAnalysis/Partitioner2/BasicTypes.h>
11 #include <Sawyer/Stopwatch.h>
12 #include <boost/filesystem.hpp>
13 #include <boost/thread/thread.hpp>
14 #include <thread>
15 
16 namespace Rose {
17 namespace BinaryAnalysis {
18 namespace ModelChecker {
19 
40 class Engine final {
42  // Types
44 public:
46  using Ptr = EnginePtr;
47 
49  struct InProgress {
50  InProgress();
51  explicit InProgress(const PathPtr&);
52  ~InProgress();
53 
54  PathPtr path;
55  Sawyer::Stopwatch elapsed;
56  boost::thread::id threadId;
57  int tid = 0;
58  };
59 
61  // Data members
63 private:
64  // Unsynchronized data members
65  PathQueue frontier_; // paths with work remaining
66  PathQueue interesting_; // paths that are interesting, placed here by workers
67  SemanticCallbacksPtr semantics_; // various configurable semantic operations
68 
69 private:
70  // Synchronized data members
71  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects all following data members
72  Sawyer::Container::Map<boost::thread::id, InProgress> inProgress_;// work that is in progress
73  SAWYER_THREAD_TRAITS::ConditionVariable newWork_; // signaled when work arrives or thread finishes
74  SAWYER_THREAD_TRAITS::ConditionVariable newInteresting_; // signaled when interesting paths arrive or threads finish
75  PathPredicatePtr frontierPredicate_; // predicate for inserting paths into the "frontier" queue
76  PathPredicatePtr interestingPredicate_; // predicate for inserting paths into the "interesting" queue
77  SettingsPtr settings_; // overall settings
78  std::vector<std::thread> workers_; // managed worker threads
79  size_t workCapacity_ = 0; // managed workers plus user threads
80  size_t nWorking_ = 0; // number of threads currently doing work
81  size_t nPathsExplored_ = 0; // number of path nodes executed, i.e., number of paths explored
82  size_t nStepsExplored_ = 0; // number of steps executed
83  bool stopping_ = false; // when true, workers stop even if there is still work remaining
84  std::vector<std::pair<double, size_t>> fanout_; // total fanout and number of nodes for each level of the forest
85  size_t nFanoutRoots_ = 0; // number of execution trees for calculating total forest size
86  Sawyer::Stopwatch elapsedTime_; // time since model checking started
87  mutable Sawyer::Stopwatch timeSinceStats_; // time since last statistics were reported
88  mutable size_t nPathsStats_ = 0; // number of paths reported in last statistics output
89  size_t nExpressionsTrimmed_ = 0; // number of symbolic expressions trimmed down to a new variable
90  WorkerStatusPtr workerStatus_; // mostly for debugging
91 
92 protected:
93  Engine() = delete;
94  explicit Engine(const SettingsPtr&);
95 
96 public:
100  static Ptr instance();
101 
105  static Ptr instance(const SettingsPtr&);
106 
110  ~Engine();
111 
113  // Configuration functions
115 public:
124  SettingsPtr settings() const;
125  void settings(const SettingsPtr&);
136  SemanticCallbacksPtr semantics() const;
137  void semantics(const SemanticCallbacksPtr&);
154  PathPrioritizerPtr explorationPrioritizer() const;
155  void explorationPrioritizer(const PathPrioritizerPtr&);
169  PathPredicatePtr explorationPredicate() const;
170  void explorationPredicate(const PathPredicatePtr&);
185  PathPredicatePtr interestingPredicate() const;
186  void interestingPredicate(const PathPredicatePtr&);
190  // Initialization functions
193 public:
199  void reset();
200 
213  void insertStartingPoint(const ExecutionUnitPtr&);
214  void insertStartingPoint(const PathPtr&);
218  // Model checker execution
221 public:
238  void startWorkers(size_t n = 0);
239 
251  void run();
252 
259  void stop();
260 
269  bool step();
270 
279  bool workRemains() const;
280 
288  size_t workCapacity() const;
289 
296  size_t nWorking() const;
297 
303  size_t nPathsPending() const;
304 
306  // Model checker status
308 public:
314  Sawyer::Stopwatch elapsedTime() const;
315 
321  size_t nPathsExplored() const;
322 
329  size_t nStepsExplored() const;
330 
339  const PathQueue& pendingPaths() const;
340 
346  std::vector<InProgress> inProgress() const;
347 
353  size_t nExpressionsTrimmed() const;
354 
358  void showStatistics(std::ostream&, const std::string &prefix = "") const;
359 
368  boost::filesystem::path workerStatusFile() const;
369  void workerStatusFile(const boost::filesystem::path&);
372  // Model checker results
375 public:
386  const PathQueue& interesting() const;
387  PathQueue& interesting();
402  PathPtr takeNextInteresting();
403 
411  bool insertInteresting(const PathPtr&);
412 
419  double estimatedForestSize(size_t k) const;
420 
422  // Worker functions. It is useful to call these from user code.
424 public:
432  bool insertWork(const PathPtr&);
433 
435  // Internal stuff.
437 private:
438  // Update the fanout parameters used to estimate execution tree size. The nChildren are the number of new paths created by
439  // extending the current path, totalSteps is the number of steps in the whole path, and lastSteps is the number of steps in
440  // the last node of the path.
441  void updateFanout(size_t nChildren, size_t totalSteps, size_t lastSteps);
442 
443  // Called by each worker thread when they start. Users should not call this even though it's public. The ID is the index
444  // of the managed worker in the workers_ vector.
445  void worker(size_t id, const Progress::Ptr&);
446 
447  // Change state. The thread should hold its current state in a local variable. The state transition edges affect how
448  // various counters are updated. All threads must start by initializing their current state to STARTING and then calling
449  // changeState to also specify the new state is STARTING. Only certain transitions are allowed--read the source. The
450  // pathHash is optional and should be the hash for the path on which the worker is actively working.
451  void changeState(size_t workerId, WorkerState &currentState, WorkerState newState, uint64_t pathHash);
452 
453  // Non-synchronized version of changeState
454  void changeStateNS(size_t workerId, WorkerState &currentState, WorkerState newState, uint64_t pathHash);
455 
456  // Do things that should be done when work is started.
457  void startWorkingNS();
458 
459  // Called by changeState when a worker has finished.
460  void finishWorkingNS();
461 
462  // Get the next path on which to work. This function blocks until either more work is available, or no more work can
463  // possibly be available. In the former case, it removes the highest priority path from the work queue, changes the work
464  // state to WORKING, and returns the path. In the latter case, it returns a null pointer.
465  //
466  // Thread safety: This method is thread safe.
467  PathPtr takeNextWorkItem(size_t workerId, WorkerState&);
468 
469  // Non-blocking version of takeNextWorkItem.
470  PathPtr takeNextWorkItemNow(WorkerState&);
471 
472  // Execute a path. This goes back as far as necessary to get a known state, and then executes from there to the end
473  // of the path.
474  //
475  // After a path is executed, it is conditionally added to the "interesting" queue according to the @ref
476  // interestingPredicate.
477  //
478  // The solver argument is the solver used by model checker, which might be different than the optional solver already
479  // attached to the RiscOperators object.
480  //
481  // Thread safety: The RISC operators must be thread-local, otherwise thread safe. All paths will have an identical
482  // set of states for this path after this returns.
483  void execute(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
484 
485  // Produce more work, typically by looking at the instruction pointer register for the outgoing state of a previous
486  // path (which is not currently in the work queue) and creating new paths.
487  void extend(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
488 
489  // Perform one step of model checking.
490  void doOneStep(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
491 
492  // Indicates that a path has been finished.
493  //
494  // This should be called by a worker thread whenever its work on a path finishes, regardless of whether the work was
495  // successful or not. It removes the path from the @ref inProgress list.
496  //
497  // Thread safety: This method is thread safe.
499 
500  // Display diagnostics about where variables appear in path constraints.
501  void displaySmtAssertions(const PathPtr&);
502 };
503 
504 
505 } // namespace
506 } // namespace
507 } // namespace
508 
509 #endif
510 #endif
SmtSolverPtr Ptr
Reference counting pointer for SMT solvers.
Definition: SmtSolver.h:45
boost::shared_ptr< RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to a RISC operators object.
Settings settings
Command-line settings for the rosebud tool.
Main namespace for the ROSE library.
Simple elapsed time.
Definition: Stopwatch.h:41
Rose::BinaryAnalysis::DataFlow::Engine< DfCfg, InstructionSemantics::BaseSemantics::StatePtr, TransferFunction, MergeFunction > Engine
Data-Flow engine.
Sawyer::SharedPointer< Engine > EnginePtr
Shared-ownership pointer for Engine.
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
Container associating values with keys.
Definition: Sawyer/Map.h:66
ProgressPtr Ptr
Progress objects are reference counted.
Definition: Progress.h:169