<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Runtime on Roberto Selbach</title><link>https://rselbach.com/tags/runtime/</link><description>Recent content in Runtime on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 16 Dec 2014 17:40:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/runtime/index.xml" rel="self" type="application/rss+xml"/><item><title>Go 1.4 moves the runtime toward Go</title><link>https://rselbach.com/go-1-4-moves-the-runtime-toward-go/</link><pubDate>Tue, 16 Dec 2014 17:40:00 +0000</pubDate><guid>https://rselbach.com/go-1-4-moves-the-runtime-toward-go/</guid><description>&lt;p&gt;I installed Go 1.4 to test a service and found the most interesting changes below my source code. Parts of the runtime and tools are being translated from C into Go. That work is not a promise that applications suddenly run faster; it is groundwork for making the implementation easier to evolve with one type system and toolchain.&lt;/p&gt;
&lt;p&gt;The collector is now fully precise. It identifies pointers in stacks and the heap rather than retaining objects because non-pointer data happens to resemble an address. Precision also requires cooperation from writes: write barriers record pointer updates that the collector must not miss while maintaining its view of the object graph. This is infrastructure for collector work, not the concurrent collector people keep casually attributing to this release. Go 1.4 still has stop-the-world collection behavior worth measuring.&lt;/p&gt;
&lt;p&gt;Goroutine stacks now start at 2 KiB, down from the larger starting size in previous releases, and grow by copying when needed. This materially reduces initial memory for programs with many mostly shallow goroutines. It does not make deep stacks free; growth allocates a larger contiguous stack and copies live contents using precise pointer information.&lt;/p&gt;
&lt;p&gt;Two source-level tools are immediately practical. &lt;code&gt;go generate&lt;/code&gt; lets a package record commands that generate source or other build inputs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//go:generate stringer -type=State&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running &lt;code&gt;go generate&lt;/code&gt; is explicit; &lt;code&gt;go build&lt;/code&gt; does not run generators automatically. I like that separation because builds should not unexpectedly require every generator or rewrite the tree. Generated files still need a clear policy in the repository, and the directive is a command for developers, not a dependency manager.&lt;/p&gt;
&lt;p&gt;The new &lt;code&gt;internal&lt;/code&gt; directory convention has an important 1.4-sized footnote. In this release, the restriction is enforced for packages in the main Go source repository, keeping implementation packages inside the standard library and toolchain. The intended rule is that code under &lt;code&gt;a/b/internal/x&lt;/code&gt; may be imported only by packages rooted within &lt;code&gt;a/b&lt;/code&gt;, but the &lt;code&gt;go&lt;/code&gt; command does not yet enforce that boundary for general repositories. Broader enforcement is future work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;example.com/project/internal/wire
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;example.com/project/server
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I can use the same layout in my own repository to advertise intent, but in Go 1.4 that part is still convention rather than a boundary enforced by the tool. It is worth adopting without pretending the lock is already on the door.&lt;/p&gt;
&lt;p&gt;After the upgrade I reran tests, allocation benchmarks, and latency measurements rather than assuming runtime changes were universally beneficial. The service used less memory with thousands of idle goroutines, while its GC tail latency remained visible. That is a believable improvement: smaller starting stacks and more precise tracing reduce waste, but write barriers and collection still have costs.&lt;/p&gt;
&lt;p&gt;Go 1.4 mostly removes future constraints. More runtime code in Go, complete pointer precision, and barriers prepare the implementation for deeper collector changes. Meanwhile, &lt;code&gt;go generate&lt;/code&gt; is useful now, and &lt;code&gt;internal&lt;/code&gt; shows where package boundaries are headed.&lt;/p&gt;</description></item><item><title>Growing stacks without segments</title><link>https://rselbach.com/growing-stacks-without-segments/</link><pubDate>Tue, 24 Jun 2014 15:45:00 +0000</pubDate><guid>https://rselbach.com/growing-stacks-without-segments/</guid><description>&lt;p&gt;After installing Go 1.3 I reran a recursive parser benchmark that had always behaved oddly at certain depths. The new runtime changed how goroutine stacks grow, and the result finally matched the shape I expected.&lt;/p&gt;
&lt;p&gt;Before 1.3, a goroutine stack could grow by adding another segment. Function entry checked available space and called runtime machinery when a split was needed. Repeatedly crossing a boundary in a call pattern could produce the notorious &amp;ldquo;hot stack split&amp;rdquo;: allocate a segment, return and release it, then need it again on the next iteration.&lt;/p&gt;
&lt;p&gt;Go 1.3 replaces segmented growth with a contiguous stack that is copied to a larger allocation. Pointers into the old stack must be adjusted to point into the copy. Stack addresses therefore are not permanent, which is one reason converting a Go pointer to an integer and treating it as a stable address is a rotten idea.&lt;/p&gt;
&lt;p&gt;My synthetic test recursively visited a nested expression:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;depth&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;node&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;nil&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;depth&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;child&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The benchmark result on my machine was illustrative rather than universal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Go 1.2: 18400 ns/op
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Go 1.3: 12100 ns/op
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Normal request depths showed little difference. The improvement appeared near stack-growth behavior, exactly where a microbenchmark can exaggerate it. I am not claiming every recursive function became one third faster.&lt;/p&gt;
&lt;p&gt;The copying design depends on knowing which stack words are pointers. Go 1.3 has precise stack scanning, allowing the runtime to update real pointers rather than conservatively treating any pointer-looking word as one. This also helps garbage collection avoid retaining objects merely because an integer happens to resemble an address.&lt;/p&gt;
&lt;p&gt;Contiguous does not mean fixed. A goroutine begins with a modest stack and grows when a function&amp;rsquo;s stack check says more room is required. Growth now entails allocation and copying, so unexpectedly enormous stacks still cost memory and time. Deep recursion can still fail; it merely has a better growth mechanism on the way there.&lt;/p&gt;
&lt;p&gt;Stack copying happens at safe points where the runtime understands frame layout. Code that passes Go pointers through unsafe integer storage defeats assumptions needed to relocate them. &lt;code&gt;unsafe&lt;/code&gt; was never a promise that undocumented runtime addresses would survive stack growth; Go 1.3 merely makes that bad bargain fail more creatively.&lt;/p&gt;
&lt;p&gt;I removed a manual recursion limit that existed solely to dodge segmented-stack performance, but kept the limit that rejects maliciously deep input. A runtime improvement is not an input-validation policy. It is, however, a welcome deletion of one workaround.&lt;/p&gt;</description></item><item><title>The two words inside an interface</title><link>https://rselbach.com/the-two-words-inside-an-interface/</link><pubDate>Thu, 29 May 2014 14:15:00 +0000</pubDate><guid>https://rselbach.com/the-two-words-inside-an-interface/</guid><description>&lt;p&gt;I changed a formatter from a concrete parameter to an interface and expected the call to behave like a generic wrapper around the value. The program worked, but looking at method dispatch made the cost and behavior less mysterious.&lt;/p&gt;
&lt;p&gt;Conceptually, an interface value is two machine words: information describing the dynamic type and a word referring to the dynamic value. For a non-empty interface, the type information also leads to the method table needed to dispatch calls. An empty interface needs no method table, but it still carries dynamic type and value.&lt;/p&gt;
&lt;p&gt;Copying an interface copies those two words, not the object they describe:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Reader&lt;/span&gt; = &lt;span style="color:#a6e22e"&gt;bytes&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;NewBufferString&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;dst&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;src&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both interfaces refer to the same buffer. Reading through &lt;code&gt;dst&lt;/code&gt; advances the state later observed through &lt;code&gt;src&lt;/code&gt;; the assignment did not clone the buffer. This is easy to miss because the interface itself is a small value while the dynamic value may be shared mutable state.&lt;/p&gt;
&lt;p&gt;Calls through an interface use the implementation selected by the dynamic type. Go&amp;rsquo;s implicit satisfaction means the concrete type does not declare which interfaces it implements; the compiler checks the method set at assignment or call sites. Pointer and value method sets still matter, so &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;*T&lt;/code&gt; need not satisfy the same interface.&lt;/p&gt;
&lt;p&gt;The two-word representation does not promise a two-word operation. A call still dispatches to the dynamic type&amp;rsquo;s method, and whether a value escapes depends on how the compiler can follow it through that call. Interface size alone says little about allocation.&lt;/p&gt;
&lt;p&gt;An interface-to-interface assignment can change the static contract while preserving the same dynamic value. A type assertion asks whether that dynamic type satisfies another interface; it does not convert the object into a new representation. I use the two-result form when failure is ordinary:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;c&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;ok&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;w&lt;/span&gt;.(&lt;span style="color:#a6e22e"&gt;io&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Closer&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The one-result form panics on failure, which belongs only where the invariant is truly guaranteed.&lt;/p&gt;
&lt;p&gt;I kept the interface where it represented a real behavioral boundary and restored the concrete parameter in the private formatter. Interfaces are contracts, not performance annotations or automatic copies of the values inside them.&lt;/p&gt;</description></item><item><title>What Go 1.2 changed under my goroutines</title><link>https://rselbach.com/what-go-1-2-changed-under-my-goroutines/</link><pubDate>Thu, 19 Dec 2013 18:10:00 +0000</pubDate><guid>https://rselbach.com/what-go-1-2-changed-under-my-goroutines/</guid><description>&lt;p&gt;One of my test programs had a rude goroutine: it performed a long loop containing function calls while another goroutine waited to print progress. With one processor, older Go releases could let the loop dominate longer than I liked.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;spin&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;n&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#a6e22e"&gt;total&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &amp;lt; &lt;span style="color:#a6e22e"&gt;n&lt;/span&gt;; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;&lt;span style="color:#f92672"&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;		&lt;span style="color:#a6e22e"&gt;total&lt;/span&gt; &lt;span style="color:#f92672"&gt;+=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;step&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	&lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;step&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;int&lt;/span&gt; { &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;i&lt;/span&gt; &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Go 1.2 introduces partial preemption when entering non-inlined functions. The scheduler can arrange for a goroutine to yield when it reaches one of these safe points. I built this experiment with &lt;code&gt;-gcflags=-l&lt;/code&gt; so the tiny &lt;code&gt;step&lt;/code&gt; call would remain a call. It does not make arbitrary Go code preemptible at every instruction. A tight loop with no calls can still be an unpleasant neighbor, and long cgo calls remain a different matter.&lt;/p&gt;
&lt;p&gt;That distinction matters. I first described the change to a colleague as &amp;ldquo;preemptive scheduling,&amp;rdquo; then wrote a no-call loop and disproved my own sentence. Progress became much fairer when the loop called &lt;code&gt;step&lt;/code&gt;, but not because the runtime had acquired a general-purpose interruptible stack map for every program counter.&lt;/p&gt;
&lt;p&gt;The other runtime change I can actually feel is stack size. New goroutine stacks in Go 1.2 start at 8 KiB rather than the smaller segments used before. That spends more virtual and physical memory up front, but avoids repeated stack splitting in modest call chains. In a crude test creating 100,000 blocked goroutines, memory is therefore not simply &amp;ldquo;100,000 times a tiny number.&amp;rdquo; Goroutines are cheap, not free.&lt;/p&gt;
&lt;p&gt;The segmented stacks still grow by linking stack segments. This is why a function prologue checks whether enough stack remains before proceeding. The check and occasional split are part of the cost hidden behind an ordinary call.&lt;/p&gt;
&lt;p&gt;I confirmed the scheduling effect with &lt;code&gt;GOMAXPROCS=1&lt;/code&gt;, because multiple operating-system threads otherwise conceal starvation by running both goroutines simultaneously. That is a useful test setting, not necessarily a production recommendation. With more processors, synchronization and cache traffic enter the result; the single-processor run isolates whether one runnable goroutine gets a chance to yield to another.&lt;/p&gt;
&lt;p&gt;Channel sends, receives, and system calls introduce other scheduling boundaries. My example intentionally removed those ordinary blocking points so the function-call behavior could be seen without a busy server around it.&lt;/p&gt;
&lt;p&gt;My practical rule remains boring: do not add &lt;code&gt;runtime.Gosched&lt;/code&gt; to every loop as seasoning. First determine whether the loop really starves useful work, then put natural blocking or chunking boundaries into the algorithm. Go 1.2 improves the worst behavior around calls, but it does not repeal scheduling.&lt;/p&gt;</description></item></channel></rss>