<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chapter 16 Tooling and Observability on Go: Under the Hood</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/</link><description>Recent content in Chapter 16 Tooling and Observability on Go: Under the Hood</description><generator>Hugo</generator><language>en</language><atom:link href="https://golang.design/under-the-hood/en/part5toolchain/ch16tools/index.xml" rel="self" type="application/rss+xml"/><item><title>16.1 Runtime Deadlock Detection</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/deadlock/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/deadlock/</guid><description>&lt;h1 id="161-runtime-deadlock-detection"&gt;16.1 Runtime Deadlock Detection&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;fatal error: all goroutines are asleep - deadlock!&lt;/code&gt;, almost every Go programmer has seen this error. It
comes from the runtime&amp;rsquo;s built-in deadlock detector. This section first makes clear how it decides and when
it fires, then turns to something more important: what it can guarantee in theory, and what it is
&lt;strong&gt;structurally unable to detect&lt;/strong&gt;. The latter is the root of many production &amp;ldquo;hang&amp;rdquo; mysteries; understanding
it is worth more than memorizing that error message.&lt;/p&gt;</description></item><item><title>16.2 Race Detection</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/race/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/race/</guid><description>&lt;h1 id="162-race-detection"&gt;16.2 Race Detection&lt;/h1&gt;
&lt;p&gt;A data race is the most insidious and hardest-to-reproduce class of bug in concurrent programs. Its definition is short: if two goroutines
access the same memory address concurrently, at least one of them is a write, and no synchronization orders the two, then the program&amp;rsquo;s behavior
is undefined (&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/"&gt;11.9&lt;/a&gt;). &amp;ldquo;Undefined&amp;rdquo; is not as gentle as &amp;ldquo;you read a stale value&amp;rdquo;;
it means the compiler and the processor are both allowed to perform surprising reorderings, and the result may be right one time and wrong the next, may appear only under stress
load, only on a certain CPU, only in a certain version, just once in a while. There is no hope of catching this kind of bug by human code review. Go&amp;rsquo;s
&lt;strong&gt;race detector&lt;/strong&gt; (&lt;code&gt;-race&lt;/code&gt;) is exactly the tool that turns this from &amp;ldquo;reproduce it by luck&amp;rdquo; into &amp;ldquo;run it once and it tells you&amp;rdquo;. This section
explains its principle, the algorithmic cost behind it, and the two capability boundaries you must keep in mind.&lt;/p&gt;</description></item><item><title>16.3 Execution Tracing</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/trace/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/trace/</guid><description>&lt;h1 id="163-execution-tracing"&gt;16.3 Execution Tracing&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;pprof&lt;/code&gt; (&lt;a href=".././perf"&gt;16.5&lt;/a&gt;) answers the question &amp;ldquo;which functions is the time being spent in&amp;rdquo;. It aggregates CPU samples taken over a window into a call tree and tells you that &lt;code&gt;json.Marshal&lt;/code&gt; accounts for 30% of the CPU. But it cannot answer another class of question: a request took 50ms, and for 45ms of it the goroutine &lt;strong&gt;was not running at all&lt;/strong&gt;, it was waiting. Waiting for what? A lock? The network? Interrupted by GC? Or it wanted to run but had no P available (&lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch09sched/steal/"&gt;9.2&lt;/a&gt;)? A CPU profile knows nothing about &amp;ldquo;waiting&amp;rdquo;, because it only samples the stack that is currently executing, and a blocked goroutine is on no CPU at all, so it is naturally never sampled.&lt;/p&gt;</description></item><item><title>16.4 Testing Code</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/testing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/testing/</guid><description>&lt;h1 id="164-testing-code"&gt;16.4 Testing Code&lt;/h1&gt;
&lt;p&gt;Testing in Go is not a bolt-on, it is a first-class citizen of the language toolchain. &lt;code&gt;go test&lt;/code&gt; is built in, the &lt;code&gt;testing&lt;/code&gt; package is standard, and convention replaces configuration. This set of design choices has deeply shaped Go&amp;rsquo;s engineering culture: in other languages, &amp;ldquo;whether to write tests at all, and which framework to use&amp;rdquo; is a decision that requires weighing trade-offs; in Go it is the default action. This section explains how this machinery runs, why it was designed this way, and how it grew from unit testing all the way to Go 1.18 fuzzing.&lt;/p&gt;</description></item><item><title>16.5 Benchmarking and Performance Profiling</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/perf/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/perf/</guid><description>&lt;h1 id="165-benchmarking-and-performance-profiling"&gt;16.5 Benchmarking and Performance Profiling&lt;/h1&gt;
&lt;p&gt;The first principle of optimization is to measure before you act. Guessing at bottlenecks by intuition usually guesses wrong; the real hot spots are often not where you think they are. Go builds every tool this discipline requires straight into the toolchain: benchmarks answer &amp;ldquo;how fast,&amp;rdquo; profiling answers &amp;ldquo;where is it slow, where does the memory go,&amp;rdquo; and &lt;code&gt;benchstat&lt;/code&gt; uses statistics to answer &amp;ldquo;did this change actually make things faster, or is it just noise.&amp;rdquo; This section explains all three tools thoroughly and strings them into a measurement-driven loop of &amp;ldquo;profile to find the hot spot, change, benchmark to verify.&amp;rdquo; One level up, this loop joins with PGO (&lt;a href="../../ch15compile/optimize"&gt;15.3&lt;/a&gt;) and execution tracing (&lt;a href=".././trace"&gt;16.3&lt;/a&gt;) to form Go&amp;rsquo;s complete performance-engineering methodology.&lt;/p&gt;</description></item><item><title>16.6 Runtime Metrics</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/metric/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/metric/</guid><description>&lt;h1 id="166-runtime-metrics"&gt;16.6 Runtime Metrics&lt;/h1&gt;
&lt;p&gt;Profiling (&lt;a href=".././perf"&gt;16.5&lt;/a&gt;) and tracing (&lt;a href=".././trace"&gt;16.3&lt;/a&gt;) belong to the family of &amp;ldquo;pull it in to diagnose when something goes wrong&amp;rdquo; tools: they cost a fair amount, produce a lot of output, and suit the case where you already suspect a problem somewhere and want to capture a window of time or a single request to look at closely. But in production the more common question is not &amp;ldquo;profile this for me right now&amp;rdquo;; it is &amp;ldquo;has this service been healthy over the past week, when did it start degrading, and should we page someone at midnight?&amp;rdquo; Answering questions like these does not rely on a one-off deep dive. It relies on &lt;strong&gt;continuous, low-cost, long-retainable numbers&lt;/strong&gt;: how big the heap is, how often GC runs, whether the goroutine count is climbing, whether the tail of scheduling latency is rising. These numbers are &lt;strong&gt;runtime metrics&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>16.7 The Language Server Protocol</title><link>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/gopls/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part5toolchain/ch16tools/gopls/</guid><description>&lt;h1 id="167-the-language-server-protocol"&gt;16.7 The Language Server Protocol&lt;/h1&gt;
&lt;p&gt;Auto-completion, jump-to-definition, live error reporting, refactoring: in modern editors these features, on the Go side, are provided by &lt;strong&gt;&lt;code&gt;gopls&lt;/code&gt;&lt;/strong&gt; (the Go language server, pronounced &amp;ldquo;go please&amp;rdquo;). Behind it stands the &lt;strong&gt;Language Server Protocol&lt;/strong&gt; (LSP). This section makes three things clear: the combinatorial explosion that LSP untangles, how gopls builds on the reusable libraries of the compiler frontend, and why it deserves to be called the culmination of the Go toolchain&amp;rsquo;s design philosophy.&lt;/p&gt;</description></item></channel></rss>