@@ -51,22 +51,28 @@ The IOSimPOR API
51
51
52
52
The common way to use IOSim is to call
53
53
54
- runSimTrace :: forall a. (forall s. IOSim s a) -> Trace a
54
+ ``` hs
55
+ runSimTrace :: forall a . (forall s . IOSim s a ) -> Trace a
56
+ ```
55
57
56
58
which returns a trace, and then express the property to test as a
57
59
predicate on the trace. Since IOSimPOR explores many traces, then the
58
60
property to test is given as a continuation instead, which is called
59
61
for each trace generated. The common way to use IOSimPOR is thus
60
62
61
- exploreSimTrace :: forall a test. (Testable test, Show a) =>
62
- (ExplorationOptions->ExplorationOptions) ->
63
- (forall s. IOSim s a) ->
64
- (Maybe (Trace a) -> Trace a -> test) ->
65
- Property
63
+ ```hs
64
+ exploreSimTrace :: forall a test . (Testable test , Show a ) =>
65
+ (ExplorationOptions -> ExplorationOptions ) ->
66
+ (forall s . IOSim s a ) ->
67
+ (Maybe (Trace a ) -> Trace a -> test ) ->
68
+ Property
69
+ ```
66
70
67
71
The continuation is the last parameter, with type
68
72
69
- Maybe (Trace a) -> Trace a -> test
73
+ ```hs
74
+ Maybe (Trace a) -> Trace a -> test
75
+ ```
70
76
71
77
Here the second parameter of the continuation is the trace that the
72
78
property should check. The first parameter simply provides information
@@ -77,7 +83,7 @@ reversing one race.
77
83
IOSimPOR Options
78
84
----------------
79
85
80
- exploreSimTrace can be controlled by a number of options, which are
86
+ ` exploreSimTrace ` can be controlled by a number of options, which are
81
87
obtained by passing the function passed as the first parameter to a
82
88
default set of options. Passing the identity function id as the first
83
89
parameter uses the defaults.
@@ -121,7 +127,7 @@ The options are:
121
127
intended pure computations always finish well within that
122
128
time. Note that garbage collection pauses are not included in the
123
129
time limit (which would otherwise need to be considerably longer
124
- than 100ms to accomodate them), provided the -T flag is supplied to
130
+ than 100ms to accommodate them), provided the -T flag is supplied to
125
131
the run-time system.
126
132
127
133
- the schedule control to replay, default Nothing, set by
@@ -139,6 +145,7 @@ IOSimPOR Statistics
139
145
When a tested property passes, IOSimPOR displays some statistics about
140
146
the schedules that were actually run. An example of this output is:
141
147
148
+ ```
142
149
Branching factor (5865 in total):
143
150
45.51% 1
144
151
43.00% 0
@@ -177,6 +184,7 @@ Race reversals per schedule (5865 in total):
177
184
3.10% 3
178
185
1.71% 0
179
186
0.10% 4
187
+ ```
180
188
181
189
The first table shows us the branching factor at each point where
182
190
IOSimPOR explored alternative schedules: in this case, in 43% of cases
@@ -215,7 +223,9 @@ threads drastically reduces the set of races that IOSimPOR needs to consider.
215
223
216
224
To start a system thread, a non-racy thread may call
217
225
218
- exploreRaces :: MonadTest m => m ()
226
+ ``` hs
227
+ exploreRaces :: MonadTest m => m ()
228
+ ```
219
229
220
230
All threads forked (using forkIO) after such a call will be system
221
231
threads. If there is no call to exploreRaces in a test, then all the
@@ -224,13 +234,13 @@ races---so it is necessary to include a call to exploreRaces somewhere
224
234
in a test.
225
235
226
236
IOSimPOR ThreadIds contain a list of small integers; the main thread
227
- contains the list [] , its children are numbered [1], [2], [3] and so
228
- on, then threads forked by [2] are numbered [2,1], [2,2], [2,3] and so
229
- on. The id of a forked thread always extends its parent's id, and
230
- successively forked children of the same thread are numbered 1, 2, 3
231
- and so on. Thread Ids give us useful information for debugging; it is
232
- easy to see which thread forked which other, and relatively easy to
233
- map thread ids in debugging output to threads in the source code.
237
+ contains the list ` [] ` , its children are numbered ` [1 ]`, ` [2 ]`, ` [3 ]` and so
238
+ on, then threads forked by ` [2 ]` are numbered ` [2 ,1 ]`, ` [2 ,2 ]`, ` [2 ,3 ]` and so
239
+ on. The id of a forked thread always extends its parent's id , and successively
240
+ forked children of the same thread are numbered 1 , 2 , 3 and so on . Thread Ids
241
+ give us useful information for debugging; it is easy to see which thread forked
242
+ which other, and relatively easy to map thread ids in debugging output to
243
+ threads in the source code.
234
244
235
245
Except when reversing races, IOSimPOR schedules threads using
236
246
priorities. Non - racy threads take priority over system threads, but
@@ -245,6 +255,7 @@ When IOSimPOR reverses races, this is done by using a 'schedule
245
255
control'. The schedule control is displayed in the test output when a
246
256
test fails. Here is an example:
247
257
258
+ ```
248
259
Schedule control:
249
260
ControlAwait [ ScheduleMod (ThreadId [ 4] ,0)
250
261
ControlDefault
@@ -258,13 +269,14 @@ ThreadId [4] delayed at time Time 0s
258
269
until after:
259
270
ThreadId [ 2]
260
271
ThreadId [ 3]
272
+ ```
261
273
262
274
The schedule control consists of one or more schedule modifications,
263
275
each of which specifies that an event should be delayed until after a
264
276
sequence of other events. The events consist of a thread id and a
265
277
per-thread event number. The interpretation of the schedule
266
278
modification above is that when the default scheduler would have
267
- performed the first event in thread [4] (that is, (ThreadId [4],0)),
279
+ performed the first event in thread ` [4]` (that is, (` ThreadId [4],0` )),
268
280
then it should be delayed, and the list of events in the third field
269
281
of the schedule modification should be performed first. In this case
270
282
there is only one schedule modification, and so only one event is
@@ -274,35 +286,37 @@ the schedule control as an option to exploreSimTrace.
274
286
275
287
The final part of the output tells us how the schedule in the failing
276
288
test differed from the schedule in the most similar passing test:
277
- namely, thread [4] was delayed (at simulated time 0) until after the
278
- events in threads [2] and [3]. Since the schedule control delays
279
- thread [4] until after steps in threads [1], [2] and [3], then we can
280
- conclude that the last passing test already delayed thread [4] until
281
- after the events in thread [1].
289
+ namely, thread ` [4]` was delayed (at simulated time 0) until after the
290
+ events in threads ` [2]` and ` [3]` . Since the schedule control delays
291
+ thread ` [4]` until after steps in threads ` [1]`, ` [2]` and ` [3]` , then we can
292
+ conclude that the last passing test already delayed thread ` [4]` until
293
+ after the events in thread ` [1]` .
282
294
283
295
Potential IOSimPOR Errors
284
296
-------------------------
285
297
286
298
Most reported errors are a result of faults in the code under test,
287
299
but if you see an error of the following form:
288
300
301
+ ```
289
302
Exception:
290
303
Can't follow ControlFollow [ (ThreadId [ 5] ,0)] [ ]
291
304
tid: ThreadId [ 5]
292
305
tstep: 0
293
306
runqueue: [ ThreadId [ 3] ,ThreadId [ 2] ,ThreadId [ 1]]
307
+ ```
294
308
295
309
then the probable cause is a bug in IOSimPOR itself. The message
296
310
indicates that IOSimPOR scheduler is trying to follow a schedule
297
- modification that specifies that thread [5] should run next, but this
298
- is impossible because thread [5] is not in the runqueue (the list of
311
+ modification that specifies that thread ` [5]` should run next, but this
312
+ is impossible because thread ` [5]` is not in the runqueue (the list of
299
313
runnable threads). If you supplied a schedule control explicitly,
300
314
using withReplay, then you may perhaps have supplied a schedule
301
315
control that does not match the version of the code you are running:
302
316
in this case the exception is your fault. But if this message appears
303
317
while you are exploring races, then it indicates a problem in
304
318
IOSimPOR's dependency analysis: IOSimPOR has constructed a schedule as
305
- a result of race reversal that tries to run thread [5] at this point,
306
- because the dependency analysis indicates that thread [5] ought to be
319
+ a result of race reversal that tries to run thread ` [5]` at this point,
320
+ because the dependency analysis indicates that thread ` [5]` ought to be
307
321
runnable---but it is not. Best to consult Quviq at this point.
308
322
0 commit comments