09 — Testing and tools¶
Every other chapter forces its interleavings so that the answer key is deterministic. This one is about what to do when you cannot: a race detector that sees the accesses a test made, a memory error detector that names the variable, a stress test that provokes the race a thousand times, a virtual clock that makes an hour's timeout take a millisecond, a model checker that tries every interleaving of a small program, and the profiles and thread dumps that say where a live program's time went.
Every lesson in this chapter is a stub: the question, the expected answer per language and what the programs will have to show, waiting for the programs. A stub becomes a lesson when its examples run in CI and its table is replaced by what they printed.
| Lesson | The one thing |
|---|---|
| What does a race detector see, and what does it miss? | stub — every data race on the path the test took, none on the path it did not, and no race condition at all |
| What does AddressSanitizer find that the race detector cannot? | stub — a read past the end or into a dead frame, reported at the access with the variable named |
| How do you write a test that provokes the race? | stub — ten thousand runs from a barrier with a yield in the window: evidence, not proof |
| How does a test wait an hour in a millisecond? | stub — synctest and a paused clock make an hour's timeout take a millisecond; elsewhere the clock has to be injected |
| Can every interleaving of a small program be checked? | stub — every interleaving of two three-step threads is twenty, and eight lose an update |
| How do you read a thread dump? | stub — which threads are waiting, for what, and who holds it — in three formats |
| Where does a concurrent program spend its time? | stub — not which function but which thread was doing what, and which were waiting for whom |
| Why did the bug disappear when you added a print? | stub — the print that was added to see the race is what closed the window |