source: CIVL/doc/manual/part-introduction.tex@ bfebb46

1.23 2.0 main test-branch
Last change on this file since bfebb46 was 9cc2d02, checked in by Stephen Siegel <siegel@…>, 12 years ago

Updated manual, updated mpi-pthreads to destroy comms.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@764 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 14.7 KB
Line 
1\part{Introduction}
2\label{part:intro}
3
4\chapter{Acknowledgement}
5
6The CIVL project is funded by the U.S.\ National Science Foundation
7under awards CCF-1346769 and CCF-1346756.
8
9\chapter{What is CIVL?}
10
11\textbf{CIVL} stands for \emph{Concurrency Intermediate Verification
12 Language}. The \emph{CIVL platform} encompasses:
13\begin{enumerate}
14\item the programming language \textbf{CIVL-C}, a dialect of C with
15 additional primitives supporting concurrency, specification, and modeling;
16\item verification and
17 analysis tools, including a symbolic execution-based model checker for
18 checking various properties of, or finding defects in, CIVL-C
19 programs; and
20\item tools that translate from many commonly used
21 languages/APIs to CIVL-C.
22\end{enumerate}
23
24The CIVL-C language is primarily intended to be an intermediate
25representation for verification. A C program using
26MPI~\cite{mpi-forum:2012:mpi30}, CUDA~\cite{cuda-programming-guide},
27OpenMP~\cite{openmp-standard}, OpenCL~\cite{opencl-standard}, or
28another API (or even some combination of APIs), will be automatically
29translated into CIVL-C and then verified. The advantages of such a
30framework are clear: the developer of a new verification technique
31could implement it for CIVL-C and then immediately see its impact
32across a broad range of concurrent programs. Likewise, when a new
33concurrency API is introduced, one only needs to implement a
34translator from it to CIVL-C in order to reap the benefits of all the
35verification tools in the platform. Programmers would have a valuable
36verification and debugging tool, while API designers could use CIVL as
37a ``sandbox'' to investigate possible API modifications, additions,
38and interactions.
39
40This manual covers all aspects of the CIVL framework, and is organized in parts
41as follows:
42\begin{enumerate}
43\item this introduction, including ``quick start'' instructions for
44 downloading and installing CIVL and several examples;
45\item a complete description of the CIVL-C language;
46\item a formal semantics for the language; and
47\item a description of the tools in the framework.
48\end{enumerate}
49
50\chapter{Installation and Quick Start}
51
52This chapter gives instructions for downloading and installing CIVL,
53and running the verification tool on an example.
54
55\textbf{Note.} The following instructions explain how to install CIVL
56under the directory \texttt{/opt}, which is the standard installation
57point. If you do not wish to install CIVL there (e.g., because you
58don't want to use \texttt{sudo}, or you want to install it in your
59home directory), you can just modify the instructions by replacing
60\texttt{/opt} with another directory. You will just need to edit the
61script file \texttt{civl} appropriately, replacing the default paths
62with your chosen paths.
63
64\begin{enumerate}
65\item Download and unpack the appropriate pre-compiled library of CIVL
66 dependencies from
67 \url{http://vsl.cis.udel.edu/tools/vsl_depend/}.
68 There are versions for Darwin (OS X), 32-bit Linux, and 64-bit Linux.
69 After unpacking, you should have a directory named \texttt{vsl}.
70\item If you do not already have a directory \texttt{/opt},
71 create it; use \texttt{sudo} as needed (\verb!sudo mkdir /opt!).
72\item Move the directory \texttt{vsl} into \texttt{/opt}
73 (\verb!mv vsl /opt!).
74\item Download and unpack the latest stable release of CIVL from
75 \url{http://vsl.cis.udel.edu/civl}. Again there are versions
76 for Darwin, 32-bit Linux, and 64-bit Linux.
77\item The resulting directory should be named
78 \texttt{CIVL-\textit{tag}} for some string \textit{tag} which
79 identifies the version of CIVL you downloaded. Move this directory
80 into \texttt{/opt} (\texttt{mv\ CIVL-\textit{tag}\ /opt}).
81\item There should now be an executable script at
82 \texttt{/opt/CIVL-\textit{tag}/bin/civl}. Move this script into
83 your path, or create a symlink from somewhere in your path to it, or
84 add the directory \texttt{/opt/CIVL-\textit{tag}/bin} to your path.
85\end{enumerate}
86
87From the command line, you should now be able to type ``\texttt{civl
88 help}'' and see a help message describing the command line syntax.
89
90Copy the file
91\texttt{/opt/CIVL-\textit{tag}/examples/concurrency/locksBad.cvl} to
92your working directory. Look at the program: it is a simple 2-process
93program with two shared variables used as locks. The two processes
94try to obtain the locks in opposite order, which can lead to a
95deadlock if both processes obtain their first lock before either
96obtains the second. Type ``\verb!civl verify locksBad.cvl!''. You
97should see some output culminating in a message
98\begin{verbatim}
99The program MAY NOT be correct. See CIVLREP/locksBad_log.txt
100\end{verbatim}
101
102Type ``\verb!civl replay locksBad.cvl!''. You should see a
103step-by-step account of how the program arrived at the deadlock.
104
105
106\chapter{Examples}
107
108In this section we show a few simple CIVL-C programs which illustrate
109some of the pertinent features of the language. We also show the results
110of running some of the tools on them.
111
112\section{Dining Philosophers}
113
114Dijkstra's well-known Dining Philosophers system can be encoded in
115CIVL-C as shown in Figure \ref{fig:dining}.
116
117\begin{figure}[t]
118 \begin{small}
119\begin{verbatim}
120#include <civlc.h>
121
122$input int B; // upper bound on number of philosophers
123$input int n; // number of philosophers
124$assume 2<=n && n<=B;
125_Bool forks[n]; // Each fork will be on the table (0) or in a hand (1).
126
127void dine(int id) {
128 int left = id;
129 int right = (id + 1) % n;
130
131 while (1) {
132 $when (forks[left] == 0) forks[left] = 1;
133 $when (forks[right] == 0) forks[right] = 1;
134 forks[right] = 0;
135 forks[left] = 0;
136 }
137}
138
139void main() {
140 for (int i = 0; i < n; i++) forks[i] = 0;
141 for (int i = 0; i < n; i++) $spawn dine(i);
142}
143\end{verbatim}
144 \end{small}
145 \caption{\texttt{diningBad.cvl}: CIVL-C encoding of Dijkstra's Dining Philosophers}
146 \label{fig:dining}
147\end{figure}
148
149In this encoding, an upper bound \ct{B} is placed on the number of
150philosophers \ct{n}. When verifying this program, a concrete value
151will be specified for \ct{B}. Hence the result of verification will
152apply to all \ct{n} between $2$ and \ct{B}, inclusive.
153
154Both \ct{B} and \ct{n} are delcared as \emph{input} variables using
155the type qualifier \cinput. An input variable may be
156initialized with any valid value of its type. In contrast, non-input
157variables declared in file scope will be initialized with a
158special \emph{undefined} value; if such a variable is read before it
159is defined, an error will be reported. In addition, any input variable
160may have a concrete initial value specified on the command line. In
161this case, we will specify a concrete value for \ct{B} on the command
162line but leave \ct{n} unconstrained.
163
164An $\cassume$ statement restricts the set of executions of the program
165to include only those traces in which the assumptions hold. In
166contrast with an $\cassert$ statement, CIVL does not check that the
167assumed expression holds, and will not generate an error message if it
168fails to hold. Thus an $\cassume$ statement allows the programmer to
169say to CIVL ``assume that this is true,'' while an $\cassert$
170statement allows the programmer to say to CIVL ``check that this is
171true.''
172
173A $\cwhen$ statement encodes a \emph{guarded command}. The $\cwhen$
174statement includes a boolean expression called the \emph{guard} and a
175statement body. The $\cwhen$ statement is enabled if and only if the
176\emph{guard} evaluates to \emph{true}, in which case the body may be
177executed. The first atomic statement in the body executes atomically
178with the evaluation of the guard, so it is guaranteed that the guard
179will hold when this initial sub-statement executes. Since assignment
180statements are atomic in CIVL, in this example the bodiy of each
181$\cwhen$ statement executes atomically with the guard evaluation.
182
183The $\cspawn$ statement is very similar to a function call. The main
184difference is that the function called is invoked in a new process
185which runs concurrently with the existing processes. The $\cspawn$
186statement itself returns immediately.
187
188The program may be verified for an upper bound of $5$ by typing the
189following at the command line:
190\begin{verbatim}
191 civl verify -inputB=5 diningBad.cvl
192\end{verbatim}
193
194The output indicates that a deadlock has been found and a
195counterexample has been produced and saved. We can examine the
196counterexample, but it is more helpful to work with a \emph{minimal}
197counterexample, i.e., a deadlocking trace of minimal length. To find a
198minimal counterexample, we issue the command
199
200\begin{verbatim}
201 civl verify -inputB=5 -min diningBad.cvl
202\end{verbatim}
203
204\begin{figure}[t]
205 \begin{small}
206\begin{verbatim}
207CIVL v0.9 of 2014-03-14 -- http://vsl.cis.udel.edu/civl
208Error 0 encountered at depth 129:
209...
210Error 25 encountered at depth 16:
211CIVL execution error (kind: DEADLOCK, certainty: PROVEABLE)
212A deadlock is possible:
213 Path condition: true
214 Enabling predicate: false
215ProcessState 0: terminated
216ProcessState 1: at location 26, f0:21.30-42 "forks[right]"
217 Enabling predicate: false
218ProcessState 2: at location 26, f0:21.30-42 "forks[right]"
219 Enabling predicate: false
220at f0:21.30-42 "forks[right]".
221State 664
222| Path condition
223| | true
224| Dynamic scopes
225| | dyscope 0 (parent=-1, static=0)
226| | | reachers = {1,2}
227| | | variables
228| | | | __atomic_lock_var = process<-1>
229| | | | B = 5
230| | | | n = 2
231| | | | forks = X_s0v4[0:=1, 1:=1]
232...
233| Process states
234...
235| | process 2
236| | | atomicCount = 0
237| | | call stack
238| | | | Frame[function=dine, location=25, f0:21.30-42 "forks[right]", scope=3]
239...
240=================== Stats ===================
241 validCalls : 15327
242 proverCalls : 17
243 memory (bytes) : 18554880
244 time (s) : 2.17
245 maxProcs : 6
246 statesInstantiated : 9264
247 statesSaved : 665
248 statesSeen : 1758
249 statesMatched : 1177
250 steps : 2993
251 transitions : 2934
252
253The program MAY NOT be correct. See CIVLREP/diningBad_log.txt
254\end{verbatim}
255 \end{small}
256 \caption{Output from \texttt{civl verify -inputB=5 -min diningBad.cvl}}
257 \label{fig:diningOut}
258\end{figure}
259
260The result of this command is shown in Figure \ref{fig:diningOut}. The
261output indicates that a minimal counterexample has length 19, i.e.,
262involves 20 states and 19 transitions (the depth of 20 is one more
263than 19). It was the 26th and shortest trace found. It was deemed
264equivalent to the earlier traces and hence the earlier ones were
265discarded and only this one saved. We can replay the trace with the command
266\begin{verbatim}
267 civl replay diningBad.cvl
268\end{verbatim}
269
270\begin{figure}
271 \begin{small}
272\begin{verbatim}
273...
274Transition 1: State 0, proc 0:
275 0->1: B = 5 at f0:9.0-12 "$input int B";
276 1->2: n = InitialValue(n) at f0:10.0-12 "$input int n";
277 2->3: $assume ((2<=n)&&(n<=B)) at f0:11.0-20 "$assume 2<=n && n ... B";
278 3->5: forks = InitialValue(forks) at f0:13.0-12 "int forks[n]";
279 5->6: i = 0 at f0:28.7-16 "int i = 0";
280--> State 1
281
282Transition 2: State 1, proc 0:
283 6->8: LOOP_TRUE_BRANCH at f0:28.18-23 "i < n";
284--> State 2
285
286...
287
288Transition 12: State 12, proc 2:
289 18->19: left = id at f0:16.2-15 "int left = id";
290 19->20: right = ((id+1)%n) at f0:17.2-26 "int right = (id ... n";
291--> State 13
292
293Transition 13: State 13, proc 2:
294 20->23: LOOP_TRUE_BRANCH at f0:19.9-10 "1";
295--> State 14
296
297Transition 14: State 14, proc 1:
298 23->25: forks[left] = 1 at f0:20.29-44 "forks[left] = 1";
299--> State 15
300
301Transition 15: State 15, proc 2:
302 23->25: forks[left] = 1 at f0:20.29-44 "forks[left] = 1";
303--> State 16
304...
305Violation of Deadlock found in State 16:
306A deadlock is possible:
307 Path condition: true
308 Enabling predicate: false
309ProcessState 0: terminated
310ProcessState 1: at location 25, f0:21.30-42 "forks[right]"
311 Enabling predicate: false
312ProcessState 2: at location 25, f0:21.30-42 "forks[right]"
313 Enabling predicate: false
314
315Trace ends after 15 transitions.
316Violation(s) found.
317...
318\end{verbatim}
319 \end{small}
320 \caption{Output from \texttt{civl replay diningBad.cvl}}
321 \label{fig:diningReplay}
322\end{figure}
323
324The result of this command is shown in Figure \ref{fig:diningReplay}.
325The output indicates that a deadlock has been found involving 2
326philosophers. The trace has 15 transitions; after the initialization
327sequence, each philosopher picks up her left fork.
328
329\section{A Multithreaded MPI Example}
330
331\begin{figure}[t]
332 \begin{small}
333\begin{verbatim}
334#include<civlc.h>
335#define TAG 0
336#define NPROCS 2
337#define NTHREADS 2
338
339$gcomm gcomm = $gcomm_create($here, NPROCS);
340
341void MPI_Process (int rank) {
342 $comm comm = $comm_create($here, gcomm, rank);
343 $proc threads[NTHREADS];
344
345 void Thread(int tid) {
346 int x = rank;
347 $message in, out = $message_pack(rank, 1-rank, TAG, &x, sizeof(int));
348
349 for (int j=0; j<2; j++) {
350 if (rank == 1) {
351 for (int i=0; i<2; i++) $comm_enqueue(comm, out);
352 for (int i=0; i<2; i++) in = $comm_dequeue(comm, 1-rank, TAG);
353 } else {
354 for (int i=0; i<2; i++) in = $comm_dequeue(comm, 1-rank, TAG);
355 for (int i=0; i<2; i++) $comm_enqueue(comm, out);
356 }
357 }
358 }
359
360 for (int i=0; i<NTHREADS; i++) threads[i] = $spawn Thread(i);
361 for (int i=0; i<NTHREADS; i++) $wait(threads[i]);
362 $comm_destroy(comm);
363}
364
365void main() {
366 $proc procs[NPROCS];
367
368 for (int i=0; i<NPROCS; i++) procs[i] = $spawn MPI_Process(i);
369 for (int i=0; i<NPROCS; i++) $wait(procs[i]);
370 $gcomm_destroy(gcomm);
371}
372\end{verbatim}
373 \end{small}
374 \caption{\texttt{mpi-pthreads.cvl}: CIVL-C model of a (defective)
375 multithreaded MPI program.}
376 \label{fig:mpithreads}
377\end{figure}
378
379Figure \ref{fig:mpithreads} is an example of a CIVL-C model of
380multithreaded MPI program. The program consists of two processes,
381each of which spawns two threads. All four threads issue
382message-passing operations.
383
384This example illustrates some of the message-passing primitives
385provided in CIVL-C. A \emph{global communicator} object is allocated
386in the root scope. The constant $\chere$ has type $\cscope$ and
387refers to the scope in which the expression occurs; in this case it is
388the root (i.e., file) scope. This global communicator is declared to
389have \texttt{NPROCS} \emph{places}; these are points from which
390messages can be sent or received. The function \verb!MPI_Process! is
391used to model an MPI process. Each instance will create its own
392\emph{local communicator} object which specifies the global
393communicator and a place; this is the object that will be used to send
394or receive messages at that place.
395
396Each process spawns two instances of function \texttt{Thread}. Each
397thread creates a message object from a buffer, specifying the source
398and destination places, tag, pointer to the beginning of the buffer,
399and the size of the buffer. The message is \emph{enqueued} into the
400communication universe using the local communicator. Similarly,
401messages are dequeued by specifying the local communicator, source
402place, and tag.
403
404The program has a subtle defect, which only manifests on very specific
405interleavings of the threads. This defect can be found using
406\texttt{civl verify}.
407
408
Note: See TracBrowser for help on using the repository browser.