Go: Under the Hood Under the Hood
中文

Chapter 16 Tooling and Observability

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
-- Brian W. Kernighan and P. J. Plauger, "The Elements of Programming Style", 2nd ed., 1978

The passage comes from Chapter 2, “Expression”, of Kernighan and Plauger’s The Elements of Programming Style. The book first presents a PL/I program that counts the blanks in a string. It uses the built-in functions INDEX and SUBSTR to cut off the first blank and everything before it on each pass; the code is clever, but it takes some thought to see what it does. The authors then give the plain version that examines one character at a time, and write the sentence above. The next discussion concerns another kind of cleverness: programmers who, from their knowledge of a particular compiler, use only the constructs “known” to be more efficient, a judgment the authors show does not always hold. The first concerns understanding and debugging, the second intuition about performance. The tools in this chapter answer exactly these two concerns: finding the cause when a program is wrong, and measuring first when a program seems slow.

16.1, 16.2 and 16.4 concern correctness. 16.1 shows how the runtime decides that the whole program is deadlocked, and how synctest and the goroutine leak profile extend detection to partial deadlocks. 16.2 shows how the race detector uses vector clocks to find memory accesses that lack synchronization, and how work is divided between the compiler and the ThreadSanitizer runtime. 16.4 shows how go test turns test conventions into an executable program, and covers table-driven tests, subtests and fuzzing. 16.3, 16.5 and 16.6 concern observing a running program. The execution trace records scheduling, garbage collection and system call events in time order. Benchmarks, benchstat and profiling answer “how fast”, “did it really change” and “where does the time go”. Runtime metrics report the state of the heap, the collector and the scheduler at very low cost, so that monitoring systems can store them over the long term and alert on them. 16.7 covers the language server protocol and gopls, that is, how the semantic features of editors are built on go/parser and go/types. Most of these tools ship with the toolchain. The mechanisms they rely on are described in the scheduler (Chapter 9), memory statistics (12.8) and the compiler front end (15.1).