Vlad Levin, Robert Palmer, Shaz Qadeer, and Sriram K. Rajamani
Partial-order reduction is widely used to alleviate state space explosion in model checkers for concurrent programs. Traditional approaches to partial order reduction are based on existence of independent actions. Independence between actions is used to select an ample subset of enabled actions from every state. Natural ample sets can be computed for threads that communicate with each other predominantly through message queues. For threads that communicate with shared memory using locks for synchronization, Lipton's theory of reduction provides a promising way to aggregate several fine-grained transitions into larger transactions. This approach can exploit common synchronization disciplines such as protecting shared variables consistently with the same lock, yielding larger transactions, and consequent reductions in the state-space. Further, transaction based reduction allows summarization at transaction boundaries, enabling a new dimension of scalability. In traditional partial-order reduction, actions that are not in the ample set are delayed, thus avoiding the redundant exploration of equivalent interleaving orders. Delaying the execution of actions indefinitely can lead to loss of soundness. This is called the ignoring problem in partial-order reduction. The usual solution to the ignoring problem is by Cycle Detection. Explicit state model checkers usually use Depth First Search, and when a cycle is detected, disallow using a reduced ample set that closes the cycle. The ignoring problem exists in transaction-based reduction as well. Current work on transaction-based reduction solves this problem by constraining the system, for example, by assuming that infinite executions of internal actions do not exist. Such assumptions do not hold in practice. We present a solution to the ignoring problem in the context of transaction-based reduction. Our solution allows infinite executions of internal actions in any thread, and is not based on Cycle Detection. We designate certain states as commit points and track the exploration to discover whether the reduced exploration guarantees a path from each commit point to a state where the transaction is completed. If such a path does not exist, we detect this at the time a commit point is popped from the stack, and schedule all threads at the commit point. This paper presents our algorithm, called Commit Point Completion (CPC), and its soundness proof. We have implemented both CPC and Cycle Detection in the Zing model checker. The CPC algorithm generally produces fewer interleaving orders than Cycle Detection, resulting in faster model checking. In particular we observe that CPC outperforms Cycle Detection in examples that arise from iterative abstraction refinement.