ROSE 0.11.145.147
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
16namespace Rose {
17namespace BinaryAnalysis {
18namespace ModelChecker {
19
40class Engine final {
42 // Types
44public:
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
63private:
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
69private:
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
92protected:
93 Engine() = delete;
94 explicit Engine(const SettingsPtr&);
95
96public:
100 static Ptr instance();
101
105 static Ptr instance(const SettingsPtr&);
106
110 ~Engine();
111
113 // Configuration functions
115public:
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&);
191 // Initialization functions
193public:
199 void reset();
200
214 void insertStartingPoint(const ExecutionUnitPtr&, Prune = Prune::NO);
215 void insertStartingPoint(const PathPtr&, Prune = Prune::NO);
220 // Model checker execution
222public:
239 void startWorkers(size_t n = 0);
240
252 void run();
253
260 void stop();
261
270 bool step();
271
280 bool workRemains() const;
281
289 size_t workCapacity() const;
290
297 size_t nWorking() const;
298
304 size_t nPathsPending() const;
305
307 // Model checker status
309public:
315 Sawyer::Stopwatch elapsedTime() const;
316
322 size_t nPathsExplored() const;
323
330 size_t nStepsExplored() const;
331
340 const PathQueue& pendingPaths() const;
341
347 std::vector<InProgress> inProgress() const;
348
354 size_t nExpressionsTrimmed() const;
355
359 void showStatistics(std::ostream&, const std::string &prefix = "") const;
360
369 boost::filesystem::path workerStatusFile() const;
370 void workerStatusFile(const boost::filesystem::path&);
374 // Model checker results
376public:
387 const PathQueue& interesting() const;
388 PathQueue& interesting();
403 PathPtr takeNextInteresting();
404
412 bool insertInteresting(const PathPtr&);
413
420 double estimatedForestSize(size_t k) const;
421
423 // Worker functions. It is useful to call these from user code.
425public:
433 bool insertWork(const PathPtr&);
434
436 // Internal stuff.
438private:
439 // Update the fanout parameters used to estimate execution tree size. The nChildren are the number of new paths created by
440 // extending the current path, totalSteps is the number of steps in the whole path, and lastSteps is the number of steps in
441 // the last node of the path.
442 void updateFanout(size_t nChildren, size_t totalSteps, size_t lastSteps);
443
444 // Called by each worker thread when they start. Users should not call this even though it's public. The ID is the index
445 // of the managed worker in the workers_ vector.
446 void worker(size_t id, const Progress::Ptr&);
447
448 // Change state. The thread should hold its current state in a local variable. The state transition edges affect how
449 // various counters are updated. All threads must start by initializing their current state to STARTING and then calling
450 // changeState to also specify the new state is STARTING. Only certain transitions are allowed--read the source. The
451 // pathHash is optional and should be the hash for the path on which the worker is actively working.
452 void changeState(size_t workerId, WorkerState &currentState, WorkerState newState, uint64_t pathHash);
453
454 // Non-synchronized version of changeState
455 void changeStateNS(size_t workerId, WorkerState &currentState, WorkerState newState, uint64_t pathHash);
456
457 // Do things that should be done when work is started.
458 void startWorkingNS();
459
460 // Called by changeState when a worker has finished.
461 void finishWorkingNS();
462
463 // Get the next path on which to work. This function blocks until either more work is available, or no more work can
464 // possibly be available. In the former case, it removes the highest priority path from the work queue, changes the work
465 // state to WORKING, and returns the path. In the latter case, it returns a null pointer.
466 //
467 // Thread safety: This method is thread safe.
468 PathPtr takeNextWorkItem(size_t workerId, WorkerState&);
469
470 // Non-blocking version of takeNextWorkItem.
471 PathPtr takeNextWorkItemNow(WorkerState&);
472
473 // Execute a path. This goes back as far as necessary to get a known state, and then executes from there to the end
474 // of the path.
475 //
476 // After a path is executed, it is conditionally added to the "interesting" queue according to the @ref
477 // interestingPredicate.
478 //
479 // The solver argument is the solver used by model checker, which might be different than the optional solver already
480 // attached to the RiscOperators object.
481 //
482 // Thread safety: The RISC operators must be thread-local, otherwise thread safe. All paths will have an identical
483 // set of states for this path after this returns.
484 void execute(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
485
486 // Produce more work, typically by looking at the instruction pointer register for the outgoing state of a previous
487 // path (which is not currently in the work queue) and creating new paths.
488 void extend(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
489
490 // Perform one step of model checking.
491 void doOneStep(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&);
492
493 // Indicates that a path has been finished.
494 //
495 // This should be called by a worker thread whenever its work on a path finishes, regardless of whether the work was
496 // successful or not. It removes the path from the @ref inProgress list.
497 //
498 // Thread safety: This method is thread safe.
499 void finishPath(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&);
500
501 // Display diagnostics about where variables appear in path constraints.
502 void displaySmtAssertions(const PathPtr&);
503};
504
505
506} // namespace
507} // namespace
508} // namespace
509
510#endif
511#endif
Container associating values with keys.
Definition Sawyer/Map.h:72
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.
The ROSE library.
Settings settings
Command-line settings for the rosebud tool.