source: CIVL/docs/introduction.md

2.0
Last change on this file was 3b44025, checked in by Stephen Siegel <siegel@…>, 12 days ago

Improved comments in Makefile and updated installation instructions.

  • Property mode set to 100644
File size: 21.4 KB
Line 
1
2# Introduction and Quick Start
3
4## Installation and Quick Start
5
61. Install one or more of the following automated theorem provers.
7 In each case, you must ensure that the executable
8 (z3, cvc4, cvc5, alt-ergo) is in your PATH.
9 - [Z3](https://github.com/Z3Prover/z3)
10 - [CVC4](https://cvc4.github.io)
11 - [cvc5](https://github.com/cvc5/cvc5)
12 - [Alt-Ergo](https://alt-ergo.ocamlpro.com)
131. Install a Java SDK if you have not already done so. A package
14 manager is the easiest way to do this. We recommend the latest
15 long term support release, but CIVL should work fine with Java 17
16 or later.
171. The CIVL releases are published on [the GitHub releases
18 page](<https://github.com/verified-software-lab/civl/releases/>).
19 Choose your desired version; for most users, the latest stable
20 version is the best choice. In any case, this will be a tar
21 gzipped archive with a name of the form `civl-x.y.tgz`. Unpack
22 this and you should have a directory named `civl-x.y`. The
23 directory contains jar files, source code, examples, and other
24 resources. You can move it wherever you like.
251. Use one of the following methods to create the `civl` executable:
26 - Method 1 (jlink): Change into the `civl-x.y` directory and type
27 `make`. This should result in a directory named `civl-runtime`
28 which contains a custom JVM optimized for CIVL. You can move
29 `civl-runtime` wherever you like (or keep it where it is). Add
30 the `/path/to/civl-runtime/bin` to your PATH, e.g., by adding a
31 line such as `export PATH=/path/to/civl-runtime/bin:$PATH` to
32 your shell startup file (`.zprofile`, `.bash_profile`, etc.).
33 See the comments in the `Makefile` for more details and options.
34 - Method 2 (jar): Move the file in `civl-x.y/lib` named
35 `civl-complete.jar` to wherever you like (or keep it where it
36 is). Create an executable shell script like the following:
37 ```
38 #!/bin/sh
39 java -Xmx16g -jar /path/to/civl-complete.jar $@
40 ```
41 Adjust the JVM arguments however you like; in the example above,
42 the maximum heap size is set to 16GB. Move this script into a
43 directory in your PATH.
441. From the command line, type `civl help`. You should see a help
45 message describing the command line syntax.
461. From the command line, type `civl config`. This should find the
47 provers in your PATH and create a file named `.sarl` in your home
48 directory.
49
50To test your installation, copy the file
51`examples/concurrency/locksBad.cvl` to your working directory. Look at
52the program: it is a simple 2-process program with two shared
53variables used as locks. The two processes try to obtain the locks in
54opposite order, which can lead to a deadlock if both processes obtain
55their first lock before either obtains the second. Type `civl verify
56locksBad.cvl`. You should see some output culminating in a message
57
58`The program MAY NOT be correct. See CIVLREP/locksBad_log.txt.`
59
60Type `civl replay locksBad.cvl`. You should see a step-by-step account
61of how the program arrived at the deadlock.
62
63
64## Verifying CIVL-C Programs
65
66Dijkstra’s well-known Dining Philosophers system can be encoded in
67CIVL-C as follows:
68
69```civl
70$input int B = 4; // upper bound on number of philosophers
71$input int n; // number of philosophers
72$assume(2<=n && n<=B);
73
74_Bool forks[n]; // Each fork will be on the table ($true) or in a hand ($false).
75
76void dine(int id) {
77 int left = id;
78 int right = (id + 1) % n;
79 while (1) {
80 $when (forks[left]) forks[left] = $false;
81 $when (forks[right]) forks[right] = $false;
82 forks[right] = $true;
83 forks[left] = $true;
84 }
85}
86
87void main() {
88 $for(int i: 0..n-1) forks[i] = $true;
89 $parfor(int i: 0..n-1) dine(i);
90}
91```
92
93In this encoding, an upper bound `B` is placed on the number of
94philosophers `n`. When verifying this program, a concrete value will
95be specified for `B`. Hence the result of verification will apply to
96all `n` between 2 and `B`, inclusive.
97
98Both `B` and `n` are declared as input variables using the type
99qualifier `$input`. An input variable may be initialized with any
100valid value of its type. In contrast, non-input variables declared in
101file scope will be initialized with a special undefined value; if such
102a variable is read before it is defined, an error will be reported. In
103addition, any input variable may have a concrete initial value
104specified on the command line. In this case, we will specify a
105concrete value for `B` on the command line.
106
107An `$assume` statement restricts the set of executions of the program
108to include only those traces in which the assumptions hold. In
109contrast with an `$assert` statement, CIVL does not check that the
110assumed expression holds, and will not generate an error message if it
111fails to hold. Thus an `$assume` statement allows the programmer to
112say to CIVL “assume that this is true,” while an `$assert` statement
113allows the programmer to say to CIVL “check that this is true.”
114
115A `$when` statement encodes a guarded command. The `$when` statement
116includes a boolean expression called the **guard** and a statement
117body. The `$when` statement is enabled if and only if the guard
118evaluates to **true**, in which case the body may be executed. The
119first atomic statement in the body executes atomically with the
120evaluation of the guard, so it is guaranteed that the guard will hold
121when this initial sub-statement executes. Since assignment statements
122are atomic in CIVL, in this example the body of each `$when` statement
123executes atomically with the guard evaluation.
124
125The `$for` statement is very similar to a **for** loop. The main
126difference is that it takes a **domain** and loops over it.
127
128The `$parfor` statement is a combination of `$for` and `$spawn`. The
129latter is very similar to a function call. The main difference is that
130the function called is invoked in a new process which runs
131concurrently with the existing processes.
132
133The program may be verified for an upper bound of 5 by typing
134
135```sh
136civl verify -inputB=5 diningBad.cvl
137```
138
139which results in the following output:
140
141```
142CIVL v1.18+ of 2018-12-28 -- http://vsl.cis.udel.edu/civl
143
144Violation 0 encountered at depth 21:
145CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
146at diningBad.cvl:20.32-32
147 $parfor(int i: 0..n-1) dine(i);
148 ^
149
150A deadlock is possible:
151 Path condition: true
152 Enabling predicate: false
153process p0 (id=0): false
154process p1 (id=1): false
155process p2 (id=2): false
156
157Call stacks:
158process 0:
159 main at diningBad.cvl:20.32 ";"
160process 1:
161 dine at diningBad.cvl:12.4-8 "$when" called from
162 _par_proc0 at diningBad.cvl:20.25-28 "dine"
163process 2:
164 dine at diningBad.cvl:12.4-8 "$when" called from
165 _par_proc0 at diningBad.cvl:20.25-28 "dine"
166
167Logging new entry 0, writing trace to CIVLREP/diningBad_0.trace
168Terminating search after finding 1 violation.
169
170=== Source files ===
171diningBad.cvl (diningBad.cvl)
172
173
174=== Command ===
175civl verify -inputB=5 diningBad.cvl
176
177=== Stats ===
178 time (s) : 1.43
179 memory (bytes) : 163053568
180 max process count : 3
181 states : 32
182 states saved : 26
183 state matches : 1
184 transitions : 30
185 trace steps : 21
186 valid calls : 106
187 provers : cvc4, z3
188 prover calls : 4
189
190=== Result ===
191The program MAY NOT be correct. See CIVLREP/diningBad_log.txt
192```
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 minimal
197counterexample, i.e., a deadlocking trace of minimal length. To find a
198minimal counterexample, we issue the command
199
200```sh
201civl verify -inputB=5 -min diningBad.cvl
202```
203
204which results in the output
205
206```
207CIVL v1.18+ of 2018-12-28 -- http://vsl.cis.udel.edu/civl
208
209Violation 0 encountered at depth 21:
210CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
211at diningBad.cvl:20.32-32
212 $parfor(int i: 0..n-1) dine(i);
213 ^
214
215A deadlock is possible:
216 Path condition: true
217 Enabling predicate: false
218process p0 (id=0): false
219process p1 (id=1): false
220process p2 (id=2): false
221
222Call stacks:
223process 0:
224 main at diningBad.cvl:20.32 ";"
225process 1:
226 dine at diningBad.cvl:12.4-8 "$when" called from
227 _par_proc0 at diningBad.cvl:20.25-28 "dine"
228process 2:
229 dine at diningBad.cvl:12.4-8 "$when" called from
230 _par_proc0 at diningBad.cvl:20.25-28 "dine"
231
232Logging new entry 0, writing trace to CIVLREP/diningBad_0.trace
233Restricting search depth to 20
234
235Violation 1 encountered at depth 16:
236CIVL execution violation (kind: DEADLOCK, certainty: PROVEABLE)
237at diningBad.cvl:20.32-32
238 $parfor(int i: 0..n-1) dine(i);
239 ^
240
241A deadlock is possible:
242 Path condition: true
243 Enabling predicate: false
244process p0 (id=0): false
245process p1 (id=1): false
246process p2 (id=2): false
247
248Call stacks:
249process 0:
250 main at diningBad.cvl:20.32 ";"
251process 1:
252 dine at diningBad.cvl:12.4-8 "$when" called from
253 _par_proc0 at diningBad.cvl:20.25-28 "dine"
254process 2:
255 dine at diningBad.cvl:12.4-8 "$when" called from
256 _par_proc0 at diningBad.cvl:20.25-28 "dine"
257
258New log entry is equivalent to previously encountered entry 0
259Length of new trace (16) is less than length of old (21): replacing old with new...
260Restricting search depth to 15
261
262=== Source files ===
263diningBad.cvl (diningBad.cvl)
264
265
266=== Command ===
267civl verify -inputB=5 -min diningBad.cvl
268
269=== Stats ===
270 time (s) : 1.46
271 memory (bytes) : 163053568
272 max process count : 6
273 states : 96
274 states saved : 77
275 state matches : 2
276 transitions : 91
277 trace steps : 64
278 valid calls : 334
279 provers : cvc4, z3
280 prover calls : 4
281
282=== Result ===
283The program MAY NOT be correct. See CIVLREP/diningBad_log.txt
284```
285
286The output indicates that a minimal counterexample consists of 16
287execution steps. It was the second and shortest trace found. It was
288deemed equivalent to the earlier traces and hence the earlier ones
289were discarded and only this one saved. We can replay the trace with
290the command
291
292```sh
293civl replay -showTransitions diningBad.cvl
294```
295
296which results in the output
297
298```
299CIVL v1.18+ of 2018-12-28 -- http://vsl.cis.udel.edu/civl
300
301Initial state:
302
303State (id=9)
304| Path condition
305| | true
306| Dynamic scopes
307| | dyscope d0 (parent=NULL, static=1)
308| | | variables
309| | | | B = NULL
310| | | | n = NULL
311| | | | forks = NULL
312| Process states
313| | process 0
314| | | call stack
315| | | | Frame[function=main, location=0, diningBad.cvl:1.15 "4", dyscope=d0]
316
317Executed by p0 from State (id=9)
318 0->1: B=5 at diningBad.cvl:1.0-15 "$input int B = 4"
319 1->2: n=InitialValue(n) [n:=X_n] at diningBad.cvl:2.0-11 "$input int n"
320 2->3: $assume((2<=X_n)&&(X_n<=5)) at diningBad.cvl:3.0-20 "$assume(2<=n && n ... )"
321 3->4: forks=InitialValue(forks) [forks:=(boolean[X_n]) ($lambda i: int. false)] at diningBad.cvl:5.0-13 "_Bool forks[n]"
322--> State (id=18)
323
324Step 1: Executed by p0 from State (id=18)
325 4->5: $elaborate_domain(($domain(1))(0..X_n-1#1)) [$assume(0==(X_n - 2))] at diningBad.cvl:19.14-19 "0..n-1"
326--> State (id=22)
327
328Step 2: Executed by p0 from State (id=22)
329 5->6: LOOP_BODY_ENTER (guard: ($domain(1))(0..1#1) has next for (NULL)) at diningBad.cvl:19.14-19 "0..n-1"
330 6->7: NEXT of (NULL) in ($domain(1))(0..1#1) [i:=0] at diningBad.cvl:19.2-5 "$for"
331--> State (id=26)
332
333Step 3: Executed by p0 from State (id=26)
334 7->5: forks[0]=true at diningBad.cvl:19.22-civlc.cvh:10.14 "forks[i] = 1"
335--> State (id=29)
336
337Step 4: Executed by p0 from State (id=29)
338 5->6: LOOP_BODY_ENTER (guard: ($domain(1))(0..1#1) has next for (0)) at diningBad.cvl:19.14-19 "0..n-1"
339 6->7: NEXT of (0) in ($domain(1))(0..1#1) [i:=1] at diningBad.cvl:19.2-5 "$for"
340--> State (id=33)
341
342Step 5: Executed by p0 from State (id=33)
343 7->5: forks[1]=true at diningBad.cvl:19.22-civlc.cvh:10.14 "forks[i] = 1"
344--> State (id=36)
345
346Step 6: Executed by p0 from State (id=36)
347 5->8: LOOP_BODY_EXIT (guard: !($domain(1))(0..1#1) has next for (1)) at diningBad.cvl:19.14-19 "0..n-1"
348--> State (id=38)
349
350Step 7: Executed by p0 from State (id=38)
351 8->9: $elaborate_domain(($domain(1))(0..1#1)) [$assume(true)] at diningBad.cvl:20.17-22 "0..n-1"
352 9->10: $parfor(i0: ($domain(1))(0..1#1)) $spawn _par_proc0(i0) at diningBad.cvl:20.2-8 "$parfor"
353 10->11: _civl_ir1=0 at diningBad.cvl:20.32 ";"
354--> State (id=52)
355
356Step 8: Executed by p0 from State (id=52)
357 11->12: LOOP_BODY_ENTER (guard: 0<2) at diningBad.cvl:20.32 ";"
358--> State (id=54)
359
360Step 9: Executed by p1 from State (id=54)
361 23->15: dine(0) at diningBad.cvl:20.25-31 "dine(i)"
362 15->16: left=0 at diningBad.cvl:8.2-14 "int left = id"
363 16->17: right=(0+1)%2 [right:=1] at diningBad.cvl:9.2-25 "int right = (id ... n"
364--> State (id=61)
365
366Step 10: Executed by p1 from State (id=61)
367 17->18: LOOP_BODY_ENTER (guard: 1!=0) at diningBad.cvl:10.9 "1"
368--> State (id=63)
369
370Step 11: Executed by p2 from State (id=63)
371 23->15: dine(1) at diningBad.cvl:20.25-31 "dine(i)"
372 15->16: left=1 at diningBad.cvl:8.2-14 "int left = id"
373 16->17: right=(1+1)%2 [right:=0] at diningBad.cvl:9.2-25 "int right = (id ... n"
374--> State (id=70)
375
376Step 12: Executed by p2 from State (id=70)
377 17->18: LOOP_BODY_ENTER (guard: 1!=0) at diningBad.cvl:10.9 "1"
378--> State (id=72)
379
380Step 13: Executed by p1 from State (id=72)
381 18->19: forks[0]=false at diningBad.cvl:11.24-civlc.cvh:12.15 "forks[left] = 0"
382--> State (id=75)
383
384Step 14: Executed by p2 from State (id=75)
385 18->19: forks[1]=false at diningBad.cvl:11.24-civlc.cvh:12.15 "forks[left] = 0"
386--> State (id=78)
387
388Step 15:
389State (id=78)
390| Path condition
391| | true
392| Dynamic scopes
393| | dyscope d0 (parent=NULL, static=1)
394| | | variables
395| | | | B = 5
396| | | | n = 2
397| | | | forks = {[0]=false, [1]=false}
398| | dyscope d1 (parent=d0, static=4)
399| | | variables
400| | | | i = 1
401| | | | __LiteralDomain_counter0__ = NULL
402| | dyscope d2 (parent=d0, static=7)
403| | | variables
404| | | | _dom_size0 = 2
405| | | | _par_procs0 = {[0]=p1, [1]=p2}
406| | dyscope d3 (parent=d0, static=8)
407| | | variables
408| | | | i = 0
409| | dyscope d4 (parent=d0, static=8)
410| | | variables
411| | | | i = 1
412| | dyscope d5 (parent=d2, static=9)
413| | | variables
414| | | | _civl_ir1 = 0
415| | dyscope d6 (parent=d5, static=10)
416| | | variables
417| | dyscope d7 (parent=d0, static=3)
418| | | variables
419| | | | id = 0
420| | dyscope d8 (parent=d7, static=12)
421| | | variables
422| | | | left = 0
423| | | | right = 1
424| | dyscope d9 (parent=d0, static=3)
425| | | variables
426| | | | id = 1
427| | dyscope d10 (parent=d9, static=12)
428| | | variables
429| | | | left = 1
430| | | | right = 0
431| Process states
432| | process 0
433| | | call stack
434| | | | Frame[function=main, location=12, diningBad.cvl:20.32 ";", dyscope=d6]
435| | process 1
436| | | call stack
437| | | | Frame[function=dine, location=19, diningBad.cvl:12.4-8 "$when", dyscope=d8]
438| | | | Frame[function=_par_proc0, location=23, diningBad.cvl:20.25-28 "dine", dyscope=d3]
439| | process 2
440| | | call stack
441| | | | Frame[function=dine, location=19, diningBad.cvl:12.4-8 "$when", dyscope=d10]
442| | | | Frame[function=_par_proc0, location=23, diningBad.cvl:20.25-28 "dine", dyscope=d4]
443
444Violation of Deadlock found in (id=78):
445A deadlock is possible:
446 Path condition: true
447 Enabling predicate: false
448process p0 (id=0): false
449process p1 (id=1): false
450process p2 (id=2): false
451
452Trace ends after 15 trace steps.
453Violation(s) found.
454
455=== Source files ===
456diningBad.cvl (diningBad.cvl)
457
458
459=== Command ===
460civl replay -showTransitions diningBad.cvl
461
462=== Stats ===
463 time (s) : 1.44
464 memory (bytes) : 163053568
465 max process count : 3
466 states : 27
467 valid calls : 100
468 provers : cvc4, z3
469 prover calls : 4
470```
471
472The output indicates that a deadlock has been found involving 2
473philosophers. After the initialization sequence, each philosopher
474picks up her left fork.
475
476
477## Verifying Sequential C Programs
478
479Since almost anything you can do in sequential C is also legal CIVL-C,
480there is not much you have to do to apply the verifier to C programs.
481
482The verifier requires a complete program --- i.e., there must be a
483main function --- and there is usually some set-up that you want to do
484for CIVL that is different than what you want the program to do in
485normal use. For this reason, there is a preprocessor object-like
486macro `_CIVL` which is defined when using the CIVL verifier. This
487allows you to insert some CIVL-C code that will be used for
488verification, without interfering with the normal compilation and use
489of the program. Consider the following example, `sum.c`:
490
491```c
492#include <assert.h>
493#include <stdio.h>
494#ifdef _CIVL
495#include <civlc.cvh>
496$input int B=5, N;
497$assume(1<=N && N<=B);
498#else
499#define N 100
500#endif
501int sum=0;
502int main() {
503 for (int i = 1; i <= N; i++) sum += i;
504 printf("N=%d, sum = %d\n", N, sum);
505 assert(sum == (N+1)*N/2);
506}
507```
508
509The program can be compiled and executed as usual...
510
511```sh
512$ cc -o sum sum.c
513$ ./sum
514N=100, sum = 5050
515$
516```
517
518...and it can be verified using CIVL:
519
520```sh
521$ civl verify sum.c
522CIVL v1.18+ of 2018-12-28 -- http://vsl.cis.udel.edu/civl
523N=5, sum = 15
524N=4, sum = 10
525N=3, sum = 6
526N=2, sum = 3
527N=1, sum = 1
528
529=== Source files ===
530sum.c (sum.c)
531
532
533=== Command ===
534civl verify sum.c
535
536=== Stats ===
537 time (s) : 2.26
538 memory (bytes) : 163053568
539 max process count : 1
540 states : 51
541 states saved : 31
542 state matches : 0
543 transitions : 50
544 trace steps : 16
545 valid calls : 54
546 provers : cvc4, z3
547 prover calls : 13
548
549=== Result ===
550The standard properties hold for all executions.
551$
552```
553
554Another approach for separating the CIVL driver code from the "real"
555program is to place these in separate translation units. In the
556following example, a toy library "sumlib" has been implemented using a
557header file `sumlib.h` and an implementation `sumlib.c`:
558
559```c title="sumlib.h"
560int sum(int n);
561```
562
563```c title="sumlib.c"
564#include "sumlib.h"
565int sum(int n) {
566 int result = 0;
567 for (int i=1; i<=n; i++) result += i;
568 return result;
569}
570```
571
572A simple test has been implemented in a separate translation unit
573named `sumlib_test.c`. The translation units can be compiled, linked,
574and executed, in the usual way.
575
576```c title="sumlib_test.c"
577#include <stdio.h>
578#include <assert.h>
579#include "sumlib.h"
580#define N 100
581int main() {
582 int result = sum(N);
583 printf("N=%d, sum = %d\n", N, result);
584 assert(result == (N+1)*N/2);
585}
586```
587
588```sh
589$ cc sumlib_test.c sumlib.c
590$ ./a.out
591N=100, sum = 5050
592```
593
594Finally, a CIVL verification driver is provided in another translation
595unit, `sumlib_driver.cvl`. The CIVL verifier can be applied to the
596whole program composed of the two translation units
597`sumlib_driver.cvl` and `sumlib.c`:
598
599```civl title="sumlib_driver.cvl"
600#include <stdio.h>
601#include "sumlib.h"
602$input int B=5, N;
603$assume(1<=N && N<=B);
604int main() {
605 int result = sum(N);
606 printf("N=%d, sum = %d\n", N, result);
607 $assert(result == (N+1)*N/2);
608}
609```
610
611```sh
612$ civl verify sumlib_driver.cvl sumlib.c
613CIVL v1.18+ of 2018-12-28 -- http://vsl.cis.udel.edu/civl
614N=5, sum = 15
615N=4, sum = 10
616N=3, sum = 6
617N=2, sum = 3
618N=1, sum = 1
619
620=== Source files ===
621sumlib_driver.cvl (sumlib_driver.cvl)
622sumlib.h (sumlib.h)
623sumlib.c (sumlib.c)
624
625
626=== Command ===
627civl verify sumlib_driver.cvl sumlib.c
628
629=== Stats ===
630 time (s) : 2.78
631 memory (bytes) : 163053568
632 max process count : 1
633 states : 47
634 states saved : 32
635 state matches : 0
636 transitions : 46
637 trace steps : 16
638 valid calls : 49
639 provers : cvc4, z3
640 prover calls : 13
641
642=== Result ===
643The standard properties hold for all executions.
644```
645
646There are limitations to the application of CIVL to C programs.
647Support for the standard library is only partial. Small bounds will
648have to be placed on many parameters in order for CIVL verification to
649terminate (or terminate in a reasonable amount of time).
650
651## Verifying C/MPI Programs
652
653<!-- TODO: Link to main [[wiki:MPI Documentation|MPI Documentation.]] -->
654
655CIVL can verify C/MPI programs that use a subset of MPI. The
656instructions for sequential programs apply equally to MPI programs.
657In addition, one must specify either (1) the number of processes for
658the MPI program, or (2) an upper and a lower bound on the number of
659processes for the MPI program.
660
661In the following example, the C/MPI program `ring.c` is verified for exactly 5 processes:
662
663```sh
664civl verify -input_mpi_nprocs=5 ring.c
665```
666
667In the following example, `ring.c` is verified for any number of
668processes between 2 and 5, inclusive:
669
670```sh
671civl verify -input_mpi_nprocs_lo=2 -input_mpi_nprocs_hi=5 ring.c
672```
673
674
675
676## Verifying C/OpenMP Programs
677
678<!-- Link to main [[wiki:OpenMP Documentation|OpenMP Documentation.]] -->
679
680CIVL uses an input variable `omp_thread_max` for verifying OpenMP
681programs. It must be specified on the command line, e.g.,
682
683```sh
684civl verify -input_omp_thread_max=3 sum_omp.c
685```
686
687Upon entering an OpenMP parallel region, CIVL will
688nondeterministically choose an integer between 1 and `omp_thread_max`,
689and create a thread team consisting of that number of threads. If
690`omp_thread_max` is not specified, then the program must explicitly
691specify the number of threads for each parallel region.
692
693By default, CIVL attempts to simplify an OpenMP program by replacing
694parallel code with sequential code when it can determine that the two
695are equivalent. In the best case, this can remove all of the OpenMP,
696resulting in a sequential program. The option `-ompNoSimplify` can be
697used to disable such simplification. Another option,
698`-ompLoopDecomp=X` can be used to specify the loop decomposition
699strategy, where `X` is one `ALL` (the default), `ROUND_ROBIN`, or
700`RANDOM`.
Note: See TracBrowser for help on using the repository browser.