//===-- MergeHandler.h --------------------------------------------*- C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /** * @file MergeHandler.h * @brief Implementation of the region based merging * * ## Basic usage: * * @code{.cpp} * klee_open_merge(); * * code containing branches etc. * * klee_close_merge(); * @endcode * * Will lead to all states that forked from the state that executed the * klee_open_merge() being merged in the klee_close_merge(). This allows for * fine-grained regions to be specified for merging. * * # Implementation Structure * * The main part of the new functionality is implemented in the class * klee::MergeHandler. The Special Function Handler generates an instance of * this class every time a state runs into a klee_open_merge() call. * * This instance is appended to a `std::vector>` * in the ExecutionState that passed the merge open point. This stack is also * copied during forks. We use a stack instead of a single instance to support * nested merge regions. * * Once a state runs into a `klee_close_merge()`, the Special Function Handler * notifies the top klee::MergeHandler in the state's stack, pauses the state * from scheduling, and tries to merge it with all other states that already * arrived at the same close merge point. This top instance is then popped from * the stack, resulting in a decrease of the ref count of the * klee::MergeHandler. * * Since the only references to this MergeHandler are in the stacks of * the ExecutionStates currently in the merging region, once the ref count * reaches zero, every state which ran into the same `klee_open_merge()` is now * paused and waiting to be merged. The destructor of the MergeHandler * then continues the scheduling of the corresponding paused states. * * # Non-blocking State Merging * * This feature adds functionality to the BoundedMergingSearcher that will * prioritize (e.g., immediately schedule) states running inside a bounded-merge * region once a state has reached a corresponding klee_close_merge() call. The * goal is to quickly gather all states inside the merging region in order to * release the waiting states. However, states that are running for more than * twice the mean number of instructions compared to the states that are already * waiting, will not be prioritized anymore. * * Once no more states are available for prioritizing, but there are states * waiting to be released, these states (which have already been merged as good as * possible) will be continued without waiting for the remaining states. When a * remaining state now enters a close-merge point, it will again wait for the * other states, or until the 'timeout' is reached. */ #ifndef KLEE_MERGEHANDLER_H #define KLEE_MERGEHANDLER_H #include "klee/ADT/Ref.h" #include "llvm/Support/CommandLine.h" #include #include #include namespace llvm { class Instruction; } namespace klee { extern llvm::cl::opt UseMerge; extern llvm::cl::opt DebugLogMerge; extern llvm::cl::opt DebugLogIncompleteMerge; class Executor; class ExecutionState; /// @brief Represents one `klee_open_merge()` call. /// Handles merging of states that branched from it class MergeHandler { private: Executor *executor; /// @brief The instruction count when the state ran into the klee_open_merge uint64_t openInstruction; /// @brief The average number of instructions between the open and close merge of each /// state that has finished so far double closedMean; /// @brief Number of states that are tracked by this MergeHandler, that ran /// into a relevant klee_close_merge unsigned closedStateCount; /// @brief Get distance of state from the openInstruction unsigned getInstructionDistance(ExecutionState *es); /// @brief States that ran through the klee_open_merge, but not yet into a /// corresponding klee_close_merge std::vector openStates; /// @brief Mapping the different 'klee_close_merge' calls to the states that ran into /// them std::map > reachedCloseMerge; public: /// @brief Called when a state runs into a 'klee_close_merge()' call void addClosedState(ExecutionState *es, llvm::Instruction *mp); /// @brief Return state that should be prioritized to complete this merge ExecutionState *getPrioritizeState(); /// @brief Add state to the 'openStates' vector void addOpenState(ExecutionState *es); /// @brief Remove state from the 'openStates' vector void removeOpenState(ExecutionState *es); /// @brief True, if any states have run into 'klee_close_merge()' and have /// not been released yet bool hasMergedStates(); /// @brief Immediately release the merged states that have run into a /// 'klee_merge_close()' void releaseStates(); // Return the mean time it takes for a state to get from klee_open_merge to // klee_close_merge double getMean(); /// @brief Required by klee::ref-managed objects class ReferenceCounter _refCount; MergeHandler(Executor *_executor, ExecutionState *es); ~MergeHandler(); }; } #endif /* KLEE_MERGEHANDLER_H */