LCT:多线程Java程序的并行分布式测试工具
摘要:
LIME混合执行测试器(LCT)是一个开源自动化测试工具,它允许测试串行和多线程Java程序。该工具使用混合执行测试,结合休眠集来处理输入值和动态偏序归约(DPOR),以避免探索不必要的线程交叉。 LCT工具已被设计为分布使用,使SMT约束求解和测试执行可以分布到多个进程在网络上的工作站。在本论文中,我们描述了工具背后的架构,以及它是如何允许分配DPOR混合执行测试和睡眠集算法。这允许一个给定程序在不同执行路径中进行并行测试。我们在几个Java测试程序中对工具的架构和分布式算法进行了评估。
关键字:混合执行测试,分布式测试,象征执行
译注:LIME(Lisp Implementation with Moderate Effort)是一种使用类似 LISP 语法的动态编程语言
1. 引言
相对于手工编写的测试用例,自动化测试有提高可靠性和降低成本的潜能。一种运用混合执行测试的自动化测试技术,结合了具体和象征执行,来探究对给定串行程序的不同执行路径。混合执行测试能结合动态偏序归约(DPOR )和休眠集算法,该方法也允许用来测试多线程程序。基于这些算法,我们开发了一个开源工具,称为LCT(LIME混合执行测试器),它可以自动测试串行多线程Java程序。该工具已被设计用于分布使用,使计算机网络的测试效果接近于非分布式用例中较大程序的测试效果。
我们事先评估了该工具测试单线程程序的分布式特性[7],并延伸支持使用DPOR算法的多线程程序[8]。本论文主要包括了:(1)该工具在我们系统分布式架构的既定描述和改进中,需要DPOR和休眠集算法,使之可以在这个架构中使用,(2)该工具在多线程程序中的一个新的分布式特性实验评估。特别地,此实验需要研究,因为实验专注的案例中,大多数测试执行是由于不同调度造成的。我们表明,即使在这种案例下,可分布式的测试也与单线程程序高效。本论文其余部分构成如下:第2节简要介绍混合执行测试和动态偏序归约算法;第3节给出了一个概述,讲的是LCT与我们所用算法的改进;第4节涵盖相关的工作第5节提供一个多线程程序的分布式架构实验评估。
2. 混合执行测试与动态偏序归约
混合执行测试[ 6,9,4 ](也被称为动态象征执行)是一种方法,在给定的程序在相同时刻具体和象征性地执行,以研究不同的程序行为。这种方法背后的主要想法是,在运行时收集象征性约束,在每个分支点指定输入值,导致程序采取一个特定的分支。举个例子,程序中x =x + 1 ,if(x> 0),将得到约束 + 1 > 0和+1≤0,在给定的if 语句中,符号值是初始分配给x的。
路径约束是象征约束的结合物,对应于每个分支决定在一个给定的的执行。为了强制测试执行遵循未开发的执行路径,需要选定之前研究的路径约束前缀,且最后的象征约束是无效的。为了取得具体的输入值,路径约束通常与SMT求解器解决。象征约束形成一个象征执行树,每个测试研究是树的一个分支。由于象征执行树的任何两个不同的子树可以独立研究,它是能有效地进行并行化测的试过程。混合执行测试的更多细节,请看参考文献[9]。
对于多线程程序,调度也影响执行路径。由该线程交叉造成的不确定性,可以处理通过调度器控制的混合执行测试,并考虑把调度当做系统的输入值。为了限制需要研究的线程交叉的数量,混合执行测试可以结合动态偏序归约算法[5]。这些算法背后的基本思想是要找到在当前的执行,然后在比赛中转换的回溯点执行树比赛中的过渡,最终将探索不同的交叉。
3.工具详述
LCT架构符合客户端-服务器模型,如图1所示,LCT由三个主要部分组成:插装器,服务器(测试选择器)和客户端(测试执行器)。为了测试给定的Java程序,代码中输入位置首先要标记。例如,int = LCT.getInteger()含义是一个int类型的输入值赋值给变量。在此之后,插装器中给出的程序通过添加新的代码来修改程序,使象征执行成为可能。对于此步骤,LCT使用称为Soot的程序转换框架[10]和对大多数语句增加象征性副本以执行同样的象征性操作。为了使Java程序插装器更容易,给定的程序首先编译成一种称为Jimple的中间语言,该语言提供了一个简化的语法。经过插装器后程序被编译回字节码。由此产生的程序被称为测试执行器,作为客户端工作着。当客户端运行时,它发送生成的信息(例如:约束条件)给在运行时的服务器,服务器反过来构造了一个基于这些信息的象征执行树。当客户端完成测试执行,它要求来自服务器的新的输入值。然后服务器选择象征执行树中需要被研究的路径,并发送相应的线程调度和路径约束给客户端,然后解决它来获取具体的输入值。通过这种方式,约束求解分布到客户端,并防止约束分解成为测试过程并行化的瓶颈。
服务器和客户端之间的通信采用TCP套接字,可以很容易地分配测试任务到多个工作站。测试执行过程中产生的约束条件可用位向量理论表示,而Boolector [2]通常当做约束求解。在测试多线程程序时,为了避免研究不必要的交叉,该工具使用动态偏序归约和休眠集算法。为了在分布式环境中使用这些算法,我们做了一些改进,描述如下。
-----------------------------------------------------------翻译未完待续-------------------------------------------------------------------------------
此为专业英语课所翻译论文,只翻译了一部分;
附原文及翻译情况:
LCT: A Parallel Distributed Testing Tool for Multithreaded Java Programs
LCT:多线程Java程序的并行分布式测试工具
Kari Kahkonen, Olli Saarikivi and Keijo Heljanko
Department of Information and Computer Science School of Science
Aalto University
PO Box 15400, FI-00076 AALTO, Finland
{Kari.Kahkonen,Olli.Saarikivi,Keijo.Heljanko}@aalto.fi
Abstract:
LIME Concolic Tester (LCT) is an open source automated testing tool that allows testing both sequential and multithreaded Java programs. The tool uses concolic testing to handle input values and dynamic partial order reduction (DPOR) combined with sleep sets to avoid exploring unnecessary interleavings of threads. The LCT tool has been designed for distributed use where the SMT constraint solving and test execution can be distributed to multiple processes on a network of workstations. In this paper we describe the architecture behind the tool and how it allows distributing concolic testing with DPOR and sleep set algorithms. This allows different execution paths of a given program to be tested in parallel. We evaluate the architecture and distributed algorithms of the tool on several Java benchmark programs.
LIME(译注:Lisp Implementation with Moderate Effort类LISP语法动态编程语言)混合执行测试器(LCT)是一个开源自动化测试工具,它允许测试串行和多线程Java程序。该工具使用混合执行测试,结合休眠集来处理输入值和动态偏序归约(DPOR),以避免探索不必要的线程交叉。 LCT工具已被设计为分布使用,使SMT约束求解和测试执行可以分布到多个进程在网络上的工作站。在本论文中,我们描述了工具背后的架构,以及它是如何允许分配DPOR混合执行测试和休眠集算法。这允许一个给定程序在不同执行路径中进行并行测试。我们在几个Java测试程序中对工具的架构和分布式算法进行了评估。
Keywords: Concolic testing(混合执行测试), distributed testing(分布式测试), symbolic execution(象征执行)
1 Introduction(引言)
Automated testing has the potential) to improve reliability and reduce costs when compared to manually written test cases. One technique to automate testing is to use concolic testingwhich combines concrete and symbolic execution to explore different execution paths of a given sequential program. Concolic testing can be combined with dynamic partial order reduction (DPOR) and sleep set algorithms that allow the approach to be used to test multithreaded programs as well. Based on these algorithms, we have developed an open source tool called LCT (LIME Concolic Tester) that can automatically test both sequential and multithreaded Java programs. The tool has been designed for distributed usewhere a network of computers can be utilized to make the testing approach scale for larger programs than in the non-distributed case.
相对于手工编写的测试用例,自动化测试有提高可靠性和降低成本的潜能。一种运用混合执行测试的自动化测试技术,结合了具体和象征执行,来探究对给定串行程序的不同执行路径。混合执行测试能结合动态偏序归约(DPOR )和休眠集算法,该方法也允许用来测试多线程程序。基于这些算法,我们开发了一个开源工具,称为LCT(LIME混合执行测试仪),它可以自动测试串行多线程Java程序。该工具已被设计用于分布使用,使计算机网络的测试效果接近于非分布式用例中较大程序的测试效果。
We have previously evaluated the distributed nature of our tool by testing single threaded programs in [7] and since then we have extended our tool to support multithreaded programs using the DPOR algorithm as described in [8]. The main contributions of this paper are: (i) a tool oriented description of the distributed architecture of our system and the modifications(n.改进) needed to the DPOR and sleep set algorithms to make them usable in this architecture(架构), and (ii) a new experimental evaluation(实验评估) of the distributed nature of our tool on multithreaded programs. In particular, the new experiments concentrate oncases where most of the test executions(执行) are generated due to different schedules that need to be explored. We show that even in this case the testing can be distributed as efficiently as with single threaded programs. The rest of the paper is structured as follows. Section 2 briefly describes concolic testing and dynamic partial order reduction algorithms, Section 3 gives an overview of LCT together with our modificationsto the used algorithms, Section 4 covers the related work and Section 5 provides an experimental evaluation of the distributed architecture in the context of multithreaded programs.
我们事先评估了该工具测试单线程程序的分布式特性[7] ,并延伸支持使用DPOR算法的多线程程序[8] 。本论文主要包括了:(1)该工具在我们系统分布式架构的既定描述和改进中,需要DPOR和休眠集算法,使之可以在这个架构中使用,(2)该工具在多线程程序中的一个新的分布式特性实验评估。特别地,此实验需要研究,因为实验专注的案例中,大多数测试执行是由于不同调度造成的。我们表明,即使在这种案例下,可分布式的测试也与单线程程序高效。本论文其余部分构成如下:第2节简要介绍混合执行测试和动态偏序归约算法;第3节给出了一个概述,讲的是LCT与我们所用算法的改进;第4节涵盖相关的工作第5节提供一个多线程程序的分布式架构实验评估。
2 Concolic Testing and Dynamic Partial Order Reduction
2.混合执行测试与动态偏序归约
Concolic testing [6,9,4] (also known as dynamic symbolic execution) is a method where a given program is executed both concretely and symbolically at the same time in order to explore the different behaviors of the program. The main idea behind this approach is to, at runtime, collect symbolic constraints at each branch point that specify the input values causing the program to take a specific branch. As an example, a program x=x+1;if(x>0);would generate constraints+1>0 and+1≤0 at the if-statement given that the symbolic value is assigned initially to x.
混合执行测试[ 6,9,4 ](也被称为动态象征执行)是一种方法,在给定的程序在相同时刻具体和象征性地执行,以研究不同的程序行为。这种方法背后的主要想法是,在运行时收集象征性约束,在每个分支点指定输入值,导致程序采取一个特定的分支。举个例子,程序中x =x + 1 ,if(x> 0),将得到约束 + 1 > 0和+1≤0,在给定的if 语句中,符号值是初始分配给x的。
A path constraint is a conjunction of symbolic constraints that correspond to each branch decision made in a given execution. To force a test execution to follow an unexplored execution path, a prefix of a previously explored path constraint is chosen and the last symbolic constraint in it is negated. To obtain concrete input values,path constraints are typically solved with SMT-solvers. The symbolic constraints form a symbolic execution tree and each test explores one path in this tree. As any two distinct subtrees of the symbolic execution tree can be explored independently, it is possible to parallelize the testing process efficiently. For more details on concolic testing, see e.g., [9].
路径约束是象征约束的结合物,对应于每个分支决定在一个给定的的执行。为了强制测试执行遵循未开发的执行路径,需要选定之前研究的路径约束前缀,且最后的象征约束是无效的。为了取得具体的输入值,路径约束通常与SMT求解器解决。象征约束形成一个象征执行树,每个测试研究是树的一个分支。由于象征执行树的任何两个不同的子树可以独立研究,它是能有效地进行并行化测的试过程。混合执行测试的更多细节,请看参考文献[9]。
For multithreaded programs the schedule affects the execution path as well. The
nondeterminism caused by the thread interleavings(交) can be handled in concolic testing by taking control of the scheduler and considering the schedule as an input to the system. To limit the number of thread interleavings that need to be explored, concolic testing can be combined with dynamic partial order reduction algorithms [5].The basic idea behind these algorithms is to find transitions that are in race in the current execution and then introduce backtracking points to the execution tree such that the different interleavings(交叉) of the transitions in race will eventually(最终) be explored(研究).
对于多线程程序,调度也影响执行路径。由该线程交叉造成的不确定性,可以处理通过调度器控制的混合执行测试,并考虑把调度当做系统的输入值。为了限制需要研究的线程交叉的数量,混合执行测试可以结合动态偏序归约算法[5]。这些算法背后的基本思想是要找到在当前的执行,然后在比赛中转换的回溯点执行树比赛中的过渡,最终将探索不同的交叉。
Fig. 1. The architecture of LCT
3 Tool Details
3.工具详述
The architecture of LCT follows the client-server model and is shown in Figure1.LCT consists of three main parts: the instrumenter, the server (test selector) and the clients (test executors). To test a given Java program, the input locations are first marked in the code. For example,int x = LCT.getInteger() indicates that an int type input will be generated for the variable x. After this the program is given to the instrumenter that modifies the program by adding new code to it that enables symbolic execution. For this step LCT uses a program transformation framework called Soot [10] and adds for most statements symbolic counterparts that perform the same operations symbolically.
LCT架构符合客户端-服务器模型,如图1所示,LCT由三个主要部分组成:插装器,服务器(测试选择器)和客户端(测试执行器)。为了测试给定的Java程序,代码中输入位置首先要标记。例如,int x = LCT.getInteger()含义是一个int类型的输入值赋值给变量。在此之后,插装器中给出的程序通过添加新的代码来修改程序,使象征执行成为可能。对于此步骤,LCT使用称为Soot的程序转换框架[10]和对大多数语句增加象征性副本以执行同样的象征性操作。
To make the instrumentation of Java programs easier, a given program is first translated into an intermediate language called Jimple that offers a simplified syntax. After the instrumentation the program is translated back to bytecode. The resulting program is called a test executor that works as a client. When the client is run, it sends information (e.g., constraints) generated during runtime to the server which in turn(反过来) constructs a symbolic execution tree based on this information. When a client finishes a test execution, it requests new input values from the server. The server then chooses which path in the symbolic execution tree is explored next and sends the corresponding(相应的) thread schedule and path constraint(约束) to the client which then solves it to obtain the concrete input values. This way the constraint solving is distributed to the clients and prevents the constraint solving from becoming a bottleneck(瓶颈) for the parallelization of the testing process.
为了使Java程序插装器更容易,给定的程序首先编译成一种称为Jimple的中间语言,该语言提供了一个简化的语法。经过插装器后程序被编译回字节码。由此产生的程序被称为测试执行器,作为客户端工作着。当客户端运行时,它发送生成的信息(例如:约束条件)给在运行时的服务器,服务器反过来构造了一个基于这些信息的象征执行树。当客户端完成测试执行,它要求来自服务器的新的输入值。然后服务器选择象征执行树中需要被研究的路径,并发送相应的线程调度和路径约束给客户端,然后解决它来获取具体的输入值。通过这种方式,约束求解分布到客户端,并防止约束分解成为测试过程并行化的瓶颈。
The communication between the server and clients is implemented using TCP sockets that makes it easy to distribute the testing to multiple workstations. The constraints generated during test executions are expressed in bitvector theory and Boolector [2] is used as the constraint solver. To avoid exploring unnecessary interleavings when testing multithreaded programs, the tool uses dynamic partial-order reduction and sleep set algorithms. In order to use these algorithms in our distributed setting, we have made some modifications to them that are described next.
服务器和客户端之间的通信采用TCP套接字,可以很容易地分配测试任务到多个工作站。测试执行过程中产生的约束条件可用位向量理论表示,而Boolector [2]通常当做约束求解。在测试多线程程序时,为了避免研究不必要的交叉,该工具使用动态偏序归约和休眠集算法。为了在分布式环境中使用这些算法,我们做了一些改进,描述如下。
3.1 Dynamic Partial Order Reduction and Sleep Sets in a Distributed Setting
3.1在分布式环境中的动态偏序归约和休眠集
DPOR is stateless in the sense that previously visited states are not needed for identifying races. However, for backtracking there does need to be a way to reach previous states. There are several ways to achieve this [5]. LCT uses re-execution of the program, as it is a natural fit for combining with concolic testing. This is because the path constraints in concolic testing encode sets of concrete states and even though a new path constraint shares a prefix with an old one, the inputs solved from the new constraint may not drive the program to any previously visited concrete state. Re-execution is a convenient way reach a concrete state that satisfies the new path constraint.
At the beginning of each test execution the client retrieves from the server a sequence of scheduling decisions to be re-executed. Backtracking points need not be added during the re-execution, as any backtracking points identified will already have been added by a previous test execution. Otherwise DPOR is run as normal during re-execution, meaning that the vector clocks and other bookkeeping data for identifying backtracking points are maintained.
To enable re-execution, the client sends each scheduling decision made to the server, which adds them to the execution tree and remembers the client’s current position in it. The backtracking points DPOR identifies are then sent to the server as indices into the execution tree along the client’s path together with a set of alternate operations that are to be explored from that state. On subsequent test executions these alternate operations are explored by supplying a client with the collected scheduling decisions up to the backtracking state with the alternate oper-ation appended to the sequence.
In model checking the reduced state space explored by a partial order reduction algorithm must often satisfy acycle proviso, which prevents operations from being ignored in all states of a cycle in the state graph. Implementing the cycle proviso in a parallel setting is challenging, although some solutions have been proposed [1]. However, because DPOR is a stateless method with an acyclic state space we can avoid the cycle proviso, allowing for easier parallelization. Using multiple concurrent clients together with the backtracking search performed by DPOR is straightforward: when one client discovers a backtracking point another one may start a test execution to explore it before the first one has finished. While no client side modifications are required to enable this, the server has to be properly synchronized.
Sleep sets can be combined with DPOR to provide additional reduction when DPOR fails to identify accurate sets of operations to explore from backtracking states. The sleep set algorithm is based on the observation that after an operationt has been explored from some states, then after other operations independent with tare explored fromsit is not necessary to explore tagain. To this end we associate with each reached state asleep set, which is a set of operations that are not executed from that state.
To compute sleep sets, when a state s is explored from s,the candidate sleep set for s is the union of the sleep set of sand the set of operations already explored from s. This candidate sleep set is then filtered to only include operations that are independent with the operation that was executed to reach s. The sleep set of the initial state is empty.
Our setting presents two complications to implementing sleep sets: (i) only the server knows which operations have been explored from a given state and (ii) only the client knows the dependencies between operations. Therefore we split the implementation between the server and client as follows.
In the beginning of the execution the server sends the candidate sleep set for the state the client will reach once it has re-executed the sequence of operations sent by the server. When the client reaches the state at the end of the sequence and on each state after that, the sleep set it has received is filtered of dependent operations. Each new sleep set obtained this way is sent to the server. Both the client and server respect the sleep set when executing operations and selecting backtracking points to explore, respectively. The detailed descriptions of the modifications to DPOR and sleep set algorithms that allow them to be used in a client-server setting can be found in [8].
4 Related Work
An alternative way to distribute concolic testing is to partition the symbolic exe-cution tree in such a way that individual workers explore independent partitions of the tree. The partitioning can be done either statically or dynamically. As the shape of the symbolic execution tree is not known beforehand, static partitioning rarely results in optimal load balancing between the workers. Dynamic partition-ing addresses this problem and provides excellent scalability to a large number of workers. Dynamic partitioning, however, requires a more complex implementation when compared to the synchronizing server approach used in LCT. See [3] for one approach based on dynamic partitioning. In [11] an approach to distribute DPOR using partitioning is presented. This approach provides excellent scalability to the number of workers but in some cases results in exploring a same schedule multiple times. The synchronizing server approach does not have this problem.
5 Experiments
To evaluate the distributed architecture of LCT (version 2.2.1), we have used it to test several multithreaded Java programs with varying number of test executor clients that were run concurrently. We have previously shown that the distributed architecture works well for single threaded programs. However, it is not directly evident that the use of DPOR generates enough open branches fast enough to keep a large number of clients busy. Therefore these experiments concentrate on cases where most of the test runs are generated due to backtracking requests of the DPOR algorithm.
Table 1 Results of the experimental evaluation of the distributed architecture of LCT.
The Indexer and File System programs are from [5] where they are used to evaluate the DPOR algorithm. The Parallel Pi program implements a parallel algorithm for calculating the value ofπ. The synthetic programs are simple examples where a number of threads perform randomly generated sequences of shared variable accesses as well as local branching on input values. In the experiments, the server was run on 2.93GHz quadcore Linux workstation with 4GB of RAM. The clients were run mainly on 3.30GHz dualcore Linux workstations 1 with two clients per workstation. The results of the experiments are shown in Table 1. As the order in which dif-ferent thread interleavings are explored affects the performance of DPOR, different runs of our tool can result in different number of test runs for the same benchmark. To take this property of DPOR into account, each benchmark was run five times with a random initial thread schedule. The table shows the average number of execution paths explored and the number of seconds needed to test them in the case where only one client was used. For the cases where multiple clients were run concurrently, the table shows the average speedup obtained when compared to the single client case.
The results show that the architecture scales well at least up to 20 clients. This is because the time to run a single test execution, which consists of restarting JVM to initialize global state, solving paths constraints and running the program both concretely and symbolically takes significantly more time than the operations the server needs to do in a synchronized way. Furthermore, most of the time the number of open paths in the symbolic execution tree is large enough so that each client has work to do.
6 Conclusions
This paper introduces the LCT tool that is available together with source code from: http://www.tcs.hut.fi/Software/lime/ as part of the LIME Interface Test Bench. We have described the distributed architecture of the tool and our modifications to DPOR and sleep set algorithms required by the architecture. We have evaluated the distributed nature of the tool on several Java programs and shown that it improves the scalability of concolic testing of multithreaded programs. Especially, we have shown that the use of DPOR does not limit the search of new execution paths to be tested in such a way that a large number of parallel workers could not be utilized effectively.
Acknowledgement
This work has been financially supported by Tekes - Finnish Agency for Technology and Innovation, Conformiq Software, Elektrobit, Nokia, Space Systems Finland, and Academy of Finland (projects 126860, 128050 and 139402), and Artemis-JU funded project RECOMP (Reduced Certification Costs Using Trusted Multi-core Platforms).
References
[1] Barnat, J.,L.Brim and P. Rockai, Parallel partial order reduction with topological sort proviso, in:J.L.Fiadeiro,S. Gnesi and A. Maggiolo-Schettini, editors,SEFM(2010), pp. 222–231.
[2] Brummayer, R. and A. Biere, Boolector: An efficient SMT solver for bit-vectors and arrays,in:Proceedings of the 15th International Conference on Tools and Algorithms for the Construction and Analysis of Systems (TACAS 2009), Lecture Notes in Computer Science 5505(2009), pp. 174–177.
[3] Bucur, S., V. Ureche, C. Zamfir and G. Candea, Parallel symbolic execution for automated real-world software testing, in: C. M. Kirsch and G. Heiser, editors, EuroSys(2011), pp. 183–198.
[4] Cadar, C., V. Ganesh, P. M. Pawlowski, D. L. Dill and D. R. Engler, EXE: automatically generating inputs of death,in:Proceedings of the 13th ACM conference on Computer and communications security (CCS 2006)(2006), pp. 322–335.
[5] Flanagan, C. and P. Godefroid, Dynamic partial-order reduction for model checking software,in: J. Palsberg and M. Abadi, editors,POPL(2005), pp. 110–121.
[6] Godefroid, P., N. Klarlund and K. Sen, DART: Directed automated random testing,in:Proceedings of the ACM SIGPLAN 2005 Conference on Programming Language Design and Implementation (PLDI2005)(2005), pp. 213–223.
[7] K¨ ahk¨onen, K., T. Launiainen, O. Saarikivi, J. Kauttio, K. Heljanko and I. Niemel,LCT: An open source concolic testing tool for Java programs,in:Proceedings of the 6th Workshop on Bytecode Semantics,Verification, Analysis and Transformation (BYTECODE’2011), 2011, pp. 75–80.
[8] Saarikivi, O., K. K¨ahk¨onen and K. Heljanko, Improving dynamic partial order reductions for concolic testing,in:Proceedings of the 12th International Conference on Application of Concurrency to System Design (ACSD’2012)(2012).
URLhttp://users.ics.aalto.fi/osaariki/lct-improving-dpor.pdf
[9] Sen, K., “Scalable automated methods for dynamic program analysis,” Doctoral thesis, University of Illinois (2006).
[10] Vall´ ee-Rai, R., P. Co, E. Gagnon, L. J. Hendren, P. Lam and V. Sundaresan,Soot - a Java bytecode optimization framework,in:Proceedings of the 1999 conference of the Centre for Advanced Studies on Collaborative Research (CASCON 1999)(1999), p. 13.
[11] Yang,Y., X.Chen, G. Gopalakrishnan and R.M.Kirby, Distributed dynamic partial order reduction based verification of threaded software, in: D.Bosnacki and S. Edelkamp, editors, SPIN, Lecture Notes in Computer Science 4595(2007), pp. 58–75