<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Don&#39;t Panic</title>
    <link>https://commaok.xyz/</link>
    <description>Recent content on Don&#39;t Panic</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 22 Feb 2026 07:12:48 -0700</lastBuildDate>
    
        <atom:link href="https://commaok.xyz/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Why I leave my webcam off</title>
      <link>https://commaok.xyz/post/audio-only/</link>
      <pubDate>Mon, 05 Jan 2026 05:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/audio-only/</guid>
      <description>&lt;p&gt;Whenever possible, I leave my webcam off during internet meetings. It is almost always possible.&lt;/p&gt;
&lt;p&gt;There are a few reasons. In decreasing importance:&lt;/p&gt;
&lt;h2 id=&#34;attention&#34;&gt;Attention&lt;/h2&gt;
&lt;p&gt;Screens are attention-destroyers.&lt;/p&gt;
&lt;p&gt;There are so many things to look at and to do. I was probably deep into a task when the meeting started. So tempting to just nudge it along. Or I might stare at myself on camera.&lt;/p&gt;
&lt;p&gt;If I turn the webcam off, I can stand up and move around.&lt;/p&gt;
&lt;p&gt;The impact of this on my attention is &lt;em&gt;dramatic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;People sometimes think that I&amp;rsquo;ve turned off my camera so that I can tune out. This has it exactly backwards. If my camera is on, I&amp;rsquo;m probably not paying much attention.&lt;/p&gt;
&lt;p&gt;As a bonus, I get fresh air, exercise, a tidier house, or fewer weeds in my garden.&lt;/p&gt;
&lt;h2 id=&#34;fatigue&#34;&gt;Fatigue&lt;/h2&gt;
&lt;p&gt;Being on-camera is tiring; it&amp;rsquo;s well-documented. I have yet to see benefits from video that outweigh that cost.&lt;/p&gt;
&lt;h2 id=&#34;connection-quality&#34;&gt;Connection quality&lt;/h2&gt;
&lt;p&gt;Except for the very best of internet connections, audio-only just works better.&lt;/p&gt;
&lt;p&gt;Fluid conversation consists of &lt;a href=&#34;https://chelseatroy.com/2018/03/29/why-do-remote-meetings-suck-so-much/&#34;&gt;continuous negotiation about turn-taking&lt;/a&gt;. Every negotiation is a round trip; high latency destroys easy communication.&lt;/p&gt;
&lt;p&gt;Humans also handle audio hiccups better than video artifacts, perhaps because we&amp;rsquo;re accustomed to acoustic interference in the real world. Wind happens, but a frozen, pixelated face is unnerving.&lt;/p&gt;
&lt;h2 id=&#34;formality&#34;&gt;Formality&lt;/h2&gt;
&lt;p&gt;I don&amp;rsquo;t FaceTime my family or close friends. We talk on the phone. It&amp;rsquo;s relaxing and pleasant. Video calls feel formal and stiff.&lt;/p&gt;
&lt;p&gt;And in fact, the main scenario in which I find it socially difficult to turn off my video camera is in formal calls, usually with people I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;Increasingly, though, I establish from the moment that the call is scheduled that my camera will be off. Any awkwardness from that has faded by the time the call occurs. And I&amp;rsquo;m happier for it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to make NYT Connections better</title>
      <link>https://commaok.xyz/post/connections/</link>
      <pubDate>Mon, 27 Oct 2025 07:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/connections/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve played nearly every &lt;em&gt;NYT Connections&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The core game is rock solid, but category colors sap some of the joy. To maximize your score, you&amp;rsquo;re supposed to submit categories &lt;a href=&#34;https://www.nytimes.com/2024/08/27/upshot/connections-bot-faq.html&#34;&gt;from purple to yellow&lt;/a&gt;. But:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;After spotting an easy category, I waste mental energy filtering it out.&lt;/li&gt;
&lt;li&gt;When I&amp;rsquo;ve solved the whole thing in my head, I must still &lt;em&gt;guess&lt;/em&gt; which category is which color.&lt;/li&gt;
&lt;li&gt;I use &lt;a href=&#34;https://daylightcomputer.com/&#34;&gt;grayscale&lt;/a&gt; &lt;a href=&#34;https://blog.alexbeals.com/posts/make-your-phone-grayscale&#34;&gt;devices&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are some proposals to fix these frustrations.&lt;/p&gt;
&lt;h1 id=&#34;let-me-select-more-than-four-tiles&#34;&gt;Let me select more than four tiles&lt;/h1&gt;
&lt;p&gt;Right now, when you reach four selected tiles, the Submit button is enabled and no further tiles may be selected.&lt;/p&gt;
&lt;p&gt;Instead, continue allowing tiles to be selected above four, but disable the Submit button whenever there aren&amp;rsquo;t exactly four tiles selected.&lt;/p&gt;
&lt;p&gt;Then I could select all of the tiles that I have categorized, and easily focus on what remains.&lt;/p&gt;
&lt;h1 id=&#34;add-gather&#34;&gt;Add Gather&lt;/h1&gt;
&lt;p&gt;The Gather button gathers exactly four selected tiles to the top row, just like the Submit button, except that it doesn&amp;rsquo;t check for correctness and doesn&amp;rsquo;t Submit.&lt;/p&gt;
&lt;p&gt;Then I could Gather my categories one at a time as I find them.&lt;/p&gt;
&lt;h1 id=&#34;add-submit-all&#34;&gt;Add Submit All&lt;/h1&gt;
&lt;p&gt;Once there is a Gather button, or drag-and-drop, or any other non-Submit way to organize tiles, add a Submit All button. This succeeds only if every row is a category; otherwise it fails outright. It is available only when no categories have been Submitted yet.&lt;/p&gt;
&lt;p&gt;This removes any guesswork, and by being all-or-nothing, raises the stakes.&lt;/p&gt;
&lt;h1 id=&#34;add-non-color-affordances&#34;&gt;Add non-color affordances&lt;/h1&gt;
&lt;p&gt;Even small visual clues would make a big difference.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Security through intentional redundancy</title>
      <link>https://commaok.xyz/post/security-through-redundancy/</link>
      <pubDate>Mon, 15 Sep 2025 07:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/security-through-redundancy/</guid>
      <description>&lt;p&gt;When writing a service, it&amp;rsquo;s very easy to accidentally forget to check permissions or ownership of an object.&lt;/p&gt;
&lt;p&gt;This code has a gaping security hole in it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;deletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DeletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Anyone&lt;/em&gt; who gets ahold of a photo ID can delete that photo.&lt;/p&gt;
&lt;p&gt;Developers often address this through middleware, but such middleware tends to get complicated and thus error prone.&lt;/p&gt;
&lt;p&gt;The problem is that &lt;code&gt;DeletePhoto&lt;/code&gt; API has an insecure design: The caller must actively remember to check permissions before calling it. It fails open.&lt;/p&gt;
&lt;p&gt;One approach to fixing this is to add redundant arguments.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s change:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;DeletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DB&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;DeletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;owner&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The owner parameter is, strictly speaking, redundant. The photo ID already uniquely identifies its owner.&lt;/p&gt;
&lt;p&gt;But now, the caller needs a &lt;code&gt;*User&lt;/code&gt; to use the API. They&amp;rsquo;ll probably reach for the most convenient one.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;deletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResponseWriter&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Query&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Get&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// grab user set by middleware
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;).(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DeletePhoto&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is the path of lowest resistance to calling &lt;code&gt;DeletePhoto&lt;/code&gt;. A developer (or an LLM) might write this code without thinking about security at all&amp;hellip;and yet, it&amp;rsquo;s pretty solid, because &lt;code&gt;DeletePhoto&lt;/code&gt; can enforce that the photo must be owned by the provided user. Only one person (the author of &lt;code&gt;DeletePhoto&lt;/code&gt;) had to think about security. Everyone else gets it for free. This API fails closed.&lt;/p&gt;
&lt;p&gt;This approach works across many programming languages, and at many different API levels.&lt;/p&gt;
&lt;p&gt;My favorite is SQL, usually via &lt;a href=&#34;https://sqlc.dev/&#34;&gt;sqlc&lt;/a&gt;. For example, change the query from:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;DELETE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; photos &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;DELETE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; photos &lt;span style=&#34;color:#66d9ef&#34;&gt;WHERE&lt;/span&gt; id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;and&lt;/span&gt; owner_id &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The main challenge I&amp;rsquo;ve encountered with this in the past is that people will want to refactor the code to remove the clutter. It can take some convincing.&lt;/p&gt;
&lt;p&gt;This trick isn&amp;rsquo;t a panacea (nothing is), but it definitely helps. And in an era in which serious amounts of code is being written by LLMs, with only local information, secure-by-default APIs look increasingly appealing.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Simpler backoff</title>
      <link>https://commaok.xyz/post/simple-backoff/</link>
      <pubDate>Fri, 30 May 2025 07:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/simple-backoff/</guid>
      <description>&lt;p&gt;Exponential backoff with jitter is de rigeur for making service calls. This code, or something like it, probably looks really familiar:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func do(ctx context.Context) error {
	const (
		maxAttempts = 10
		baseDelay   = 1 * time.Second
		maxDelay    = 60 * time.Second
	)

	delay := baseDelay
	for attempt := range maxAttempts {
		err := request(ctx)
		if err == nil {
			return nil
		}

		delay *= 2
		delay = min(delay, maxDelay)

		jitter := multiplyDuration(delay, rand.Float64()*0.5-0.25) // ±25%
		sleepTime := delay + jitter

		select {
		case &amp;lt;-ctx.Done():
			return ctx.Err()
		case &amp;lt;-time.After(sleepTime):
		}
	}

	return fmt.Errorf(&amp;#34;failed after %d attempts&amp;#34;, maxAttempts)
}

func multiplyDuration(d time.Duration, mul float64) time.Duration {
	return time.Duration(float64(d) * mul)
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But we can make this much nicer with a simple &lt;a href=&#34;https://commaok.xyz/post/lookup_tables/&#34;&gt;lookup table&lt;/a&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func do(ctx context.Context) error {
	delays := []time.Duration{
		1 * time.Second, 2 * time.Second,
		4 * time.Second, 8 * time.Second,
		16 * time.Second, 32 * time.Second,
		60 * time.Second, 60 * time.Second,
		60 * time.Second, 60 * time.Second,
	}

	for _, delay := range delays {
		err := request(ctx)
		if err == nil {
			return nil
		}

		delay = multiplyDuration(delay, 0.75 + rand.Float64()*0.5) // ±25%
		select {
		case &amp;lt;-ctx.Done():
			return ctx.Err()
		case &amp;lt;-time.After(delay):
		}
	}

	return fmt.Errorf(&amp;#34;failed after %d attempts&amp;#34;, len(delays))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is much simpler. There are fewer variables, with smaller scope. There&amp;rsquo;s no need to reasoning about behavior across loops, and if there&amp;rsquo;s a bug in the calculations, it won&amp;rsquo;t affect subsequent iterations.&lt;/p&gt;
&lt;p&gt;It is more readable. It is obvious how it will behave. It is also more editable. Changing the backoff schedule and number of attempts now feels safe and trivial.&lt;/p&gt;
&lt;p&gt;Don&amp;rsquo;t write code that generates a small, fixed set of values. Use a lookup table instead.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Blog schism</title>
      <link>https://commaok.xyz/post/blog-schism/</link>
      <pubDate>Fri, 23 May 2025 05:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/blog-schism/</guid>
      <description>&lt;p&gt;Lots of people don&amp;rsquo;t want to read about AI.&lt;/p&gt;
&lt;p&gt;I respect that.&lt;/p&gt;
&lt;p&gt;But I&amp;rsquo;m currently steeped in the world of AI, for better or for worse, and I want to blog about it. So I&amp;rsquo;ve split this blog in half.&lt;/p&gt;
&lt;p&gt;The normal blog, which you are reading, is now AI-free.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s another, at &lt;a href=&#34;https://commaok.xyz/ai&#34;&gt;/ai&lt;/a&gt; that contains only AI posts. It has its own RSS feed.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Podcast ho!</title>
      <link>https://commaok.xyz/post/podcast/</link>
      <pubDate>Fri, 12 Jan 2024 15:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/podcast/</guid>
      <description>&lt;p&gt;I have started a podcast, Significant Bits.&lt;/p&gt;
&lt;p&gt;The goal is to have substantive technical discussions about software engineering, very broadly defined.&lt;/p&gt;
&lt;p&gt;You can listen at &lt;a href=&#34;https://sigpod.dev/&#34;&gt;https://sigpod.dev/&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Sometimes Software is Done, or Why Hugo Why</title>
      <link>https://commaok.xyz/post/on_hugo/</link>
      <pubDate>Tue, 09 Jan 2024 09:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/on_hugo/</guid>
      <description>&lt;p&gt;I didn&amp;rsquo;t sit down this morning planning to write a grouchy blog post about Hugo.&lt;/p&gt;
&lt;p&gt;When I first used Hugo I loved it. It was fast. It was simple. It just worked, as much as any software does, and it solved a real problem.&lt;/p&gt;
&lt;p&gt;It was done.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;But people kept working on it.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m sure that it has been improved in countless ways. But along the way it has gotten bigger and more complicated, and has broken backwards compatibility repeatedly.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I am only inspired to write a blog post every few months. It takes a lot of self control to forgo the glittering pile of side projects and use my precious free time to write some words instead of code.&lt;/p&gt;
&lt;p&gt;I commit to myself: Today is the day! I will finally tackle one of the items from my blog post idea list!&lt;/p&gt;
&lt;p&gt;And then&amp;hellip;&lt;/p&gt;
&lt;p&gt;I run &lt;code&gt;hugo&lt;/code&gt;&amp;hellip;&lt;/p&gt;
&lt;p&gt;And it scribbles all over my files, a slew of unimportant changes, unfortunately occasionally interspersed with a few that matter&amp;hellip;&lt;/p&gt;
&lt;p&gt;And it warns me of new deprecations, often with unusable upgrade instructions&amp;hellip;&lt;/p&gt;
&lt;p&gt;And things flat out break.&lt;/p&gt;
&lt;p&gt;(Often, they were deprecated and then broken entirely between two subsequent blog posts, so I never ever saw the deprecation.)&lt;/p&gt;
&lt;p&gt;Instead of writing a blog post, I spend hours fixing build failures.&lt;/p&gt;
&lt;p&gt;Build failures of my static site, which has maybe a few dozen posts.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t care about Hugo&amp;rsquo;s internals. I have never cared. I just want a blog that works.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Enough complaining. Hugo is officially on the chopping block. Suggestions for alternatives welcome.&lt;/p&gt;
&lt;p&gt;And in the meantime, I&amp;rsquo;ll just compile Hugo myself from source, never update it, and live in the ever receding past.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Backwards compatibility matters. And sometimes, software is done.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Type Specialization in Go</title>
      <link>https://commaok.xyz/post/type_specialization/</link>
      <pubDate>Mon, 03 Apr 2023 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/type_specialization/</guid>
      <description>&lt;p&gt;&lt;em&gt;This post was originally tweets but then things happened, and it needed a new linkable home. Btw, I&amp;rsquo;m now @commaok@inuh.net on Mastodon.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This post is about manual type specialization, which can make a big difference in some hot code.&lt;/p&gt;
&lt;p&gt;Consider this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Gopher&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;Goph&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Gopher&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;.(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Goph&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Goph&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;rsquo;s weird. The type assertion to &lt;code&gt;(*T)&lt;/code&gt; is semantically irrelevant. We call &lt;code&gt;.Goph&lt;/code&gt; on each branch!&lt;/p&gt;
&lt;p&gt;But that pointless type assertion is also really cheap. And on the success branch, the compiler can do improved escape analysis (alloc less) and inline the method body (faster).&lt;/p&gt;
&lt;p&gt;This is one form of type specialization, a common optimization done by JIT compilers.&lt;/p&gt;
&lt;p&gt;This technique can help if you have (1) very hot code that (2) is called via an interface but (3) has only one or two primary implementations.&lt;/p&gt;
&lt;p&gt;It hurts readability. Use only when it counts, and document it.&lt;/p&gt;
&lt;p&gt;Why doesn’t the compiler do this for you? It doesn’t know what types would be good to try. &lt;a href=&#34;https://en.wikipedia.org/wiki/Just-in-time_compilation&#34;&gt;JIT&lt;/a&gt; would help. &lt;a href=&#34;https://en.wikipedia.org/wiki/Interprocedural_optimization&#34;&gt;IPO/WHO/LTO&lt;/a&gt; might help.&lt;/p&gt;
&lt;p&gt;And PGO probably will help, in some future Go release! As of &lt;a href=&#34;https://tip.golang.org/doc/go1.20#compiler&#34;&gt;Go 1.20&lt;/a&gt;, cmd/compile has some &lt;a href=&#34;https://github.com/golang/go/issues/28262&#34;&gt;profile-guided optimization&lt;/a&gt; around inlining. More is planned, including register allocation and type specialization, which might end up covering this use case.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Nicer struct literals in Go templates</title>
      <link>https://commaok.xyz/post/tstruct/</link>
      <pubDate>Fri, 24 Jun 2022 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/tstruct/</guid>
      <description>&lt;p&gt;Go templates (&lt;code&gt;text/template&lt;/code&gt;, &lt;code&gt;html/template&lt;/code&gt;) accept a single argument to render. That&amp;rsquo;s generally enough when you&amp;rsquo;re executing them from Go code. But when invoking a template from another template, you often want to pass multiple things to it.&lt;/p&gt;
&lt;p&gt;For example, we might have a template that renders a nav bar item. It requires a title, a url, and an &amp;ldquo;enabled&amp;rdquo; bool. We want to invoke it from another template.&lt;/p&gt;
&lt;p&gt;How do you do that?&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;ll review the existing options and then discuss &lt;a href=&#34;#a-new-approach&#34;&gt;a new one I&amp;rsquo;m working on&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;existing-options&#34;&gt;Existing options&lt;/h1&gt;
&lt;h2 id=&#34;dict&#34;&gt;dict&lt;/h2&gt;
&lt;p&gt;You can combine multiple key/value pairs into a map. &lt;a href=&#34;https://stackoverflow.com/a/18276968/&#34;&gt;Define a &amp;ldquo;dict&amp;rdquo; function in your FuncMap and call it from your template.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This might look like:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ template &amp;#34;navbar&amp;#34; dict &amp;#34;title&amp;#34; &amp;#34;Home&amp;#34; &amp;#34;url&amp;#34; (urlNamed &amp;#34;home&amp;#34;) &amp;#34;enabled&amp;#34; true }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is flexible and gets the job done. But it is a bit of a blob and has no type safety.&lt;/p&gt;
&lt;h2 id=&#34;do-it-all-in-go-code&#34;&gt;Do it all in Go code&lt;/h2&gt;
&lt;p&gt;Define a nav bar item struct:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NavBarItem&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Enabled&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Construct the nav bar item in your Go code using a struct literal. Pass it into your template, and then pass it along to the nested template.&lt;/p&gt;
&lt;p&gt;This works, but it splits your content into two places. And it can be annoying to thread everything through. It is not so much a solution to the problem as it is giving up on solving the problem.&lt;/p&gt;
&lt;h2 id=&#34;tmplfunc&#34;&gt;tmplfunc&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://pkg.go.dev/rsc.io/tmplfunc&#34;&gt;tmplfunc&lt;/a&gt; converts templates to functions. If you define the navbar template using &lt;code&gt;{{ define &amp;quot;navbar title url enabled&amp;quot; }}&lt;/code&gt;, then tmplfunc arranges for it to be callable:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ navbar &amp;#34;Home&amp;#34; (urlNamed &amp;#34;home&amp;#34;) true }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This adds a bit of type safety, but not much. As the list of parameters grows, it loses readability. It only works with template execution; you can&amp;rsquo;t use it to define a local variable. And it requires that you replace the template parsing pipeline with &lt;code&gt;tmplfunc&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;a-new-approach&#34;&gt;A new approach&lt;/h1&gt;
&lt;p&gt;The new approach I&amp;rsquo;m experimenting with is to define a Go struct for the template input (as above) and then autogenerate corresponding FuncMap entries. This provides a template syntax for writing struct literals.&lt;/p&gt;
&lt;p&gt;My initial attempt at this is &lt;a href=&#34;https://github.com/josharian/tstruct&#34;&gt;package tstruct&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, we hook the &lt;code&gt;NavBarItem&lt;/code&gt; struct up to the FuncMap:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;template&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FuncMap&lt;/span&gt;{ &lt;span style=&#34;color:#75715e&#34;&gt;/* your func map here */&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tstruct&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AddFuncMap&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;NavBarItem&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// handle err
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We can now call the template like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ template &amp;#34;navbar&amp;#34; NavBarItem (Title &amp;#34;Home&amp;#34;) (URL (urlNamed &amp;#34;home&amp;#34;)) (Enabled true) }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is a bit more verbose, but I find it far more readable. It is pretty type safe, and it is flexible; you can reorder and omit any of the field arguments.&lt;/p&gt;
&lt;p&gt;Package tstruct also supports map and slice fields. For example, given this struct type:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Example&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After calling &lt;code&gt;tstruct.AddFuncMap[Example](m)&lt;/code&gt;, you can write:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ $x := Example (Map &amp;#34;a&amp;#34; 1 &amp;#34;b&amp;#34; 2) (Slice 5 6 7) }}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;x&lt;/code&gt; now contains the value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Example&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Map&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;b&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt;: []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If it helps with clarity, you can also build maps and slices incrementally. This yields identical results:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ $x := Example
    (Map &amp;#34;a&amp;#34; 1)
    (Map &amp;#34;b&amp;#34; 2)
    (Slice 5)
    (Slice 6)
    (Slice 7)
}}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can also define custom setters for struct fields with named types; look for &lt;code&gt;TStructSet&lt;/code&gt; in the &lt;a href=&#34;https://github.com/josharian/tstruct/blob/main/readme.md&#34;&gt;tstruct readme&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;funcmap-name-collisions&#34;&gt;FuncMap name collisions&lt;/h1&gt;
&lt;p&gt;FuncMaps are global, so if you already have an entry called &lt;code&gt;NavBar&lt;/code&gt;, then package tstruct can&amp;rsquo;t (or rather, won&amp;rsquo;t) add one to construct &lt;code&gt;NavBar&lt;/code&gt; structs. Similarly, tstruct can&amp;rsquo;t add two structs with the same name, or a struct with the same name as a struct field.&lt;/p&gt;
&lt;p&gt;As a special case, however, tstruct supports using the same struct field name across different structs, even if they have different types. (This is possible because the &amp;ldquo;field setter&amp;rdquo; FuncMap entry is only fully evaluated by tstruct itself in the context of a specific struct type.)&lt;/p&gt;
&lt;p&gt;Fortunately, most FuncMap functions start with a lower case letter, and tstruct only works with exported struct fields, so there&amp;rsquo;s some amount of convention-based namespacing.&lt;/p&gt;
&lt;h1 id=&#34;caveats&#34;&gt;Caveats&lt;/h1&gt;
&lt;p&gt;As of June 2022, this is fairly novel, both the idea (I think) and the implementation (definitely).&lt;/p&gt;
&lt;p&gt;I expect the API and details to evolve as I use this more and (hopefully) hear from others using it. Please &lt;a href=&#34;https://github.com/josharian/tstruct/issues&#34;&gt;file issues&lt;/a&gt; with feedback, bugs, and ideas. If it ends up being popular, I&amp;rsquo;ll try to push towards a stable v1.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Performance and files full of code</title>
      <link>https://commaok.xyz/post/perf_files/</link>
      <pubDate>Sat, 30 Apr 2022 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/perf_files/</guid>
      <description>&lt;p&gt;Linus&amp;rsquo;s Famous Law: &amp;ldquo;Given enough eyeballs, all bugs are shallow.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Linus&amp;rsquo;s &lt;a href=&#34;https://git-scm.com/docs/pack-heuristics&#34;&gt;Less Famous Law&lt;/a&gt;: &amp;ldquo;Files grow.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;One of the hardest things programmers do is keep code readable. Splitting code up into separate files is a basic tool for that.&lt;/p&gt;
&lt;p&gt;And yet, crazy as it sounds when you say it out loud, our tools pressure us not to.&lt;/p&gt;
&lt;h1 id=&#34;php&#34;&gt;PHP&lt;/h1&gt;
&lt;p&gt;My first software job was for a company called AdMob. We used PHP. I know.&lt;/p&gt;
&lt;p&gt;I needed to optimize some very hot code. I was a philosophy Ph.D. dropout, so I had very little idea what I was doing. The internet&amp;rsquo;s advice for optimizing and scaling PHP was &amp;ldquo;use memcached!&amp;rdquo;, but we were way beyond that.&lt;/p&gt;
&lt;p&gt;I eventually figured out that if I combined all of our code into a single file, I could get double-digit speed-ups. It turns out that the overhead of statting, opening, and parsing a new file was substantial. I wrote a simple preprocessor, everyone groaned unhappily, and we moved forward.&lt;/p&gt;
&lt;h1 id=&#34;javascript&#34;&gt;JavaScript&lt;/h1&gt;
&lt;p&gt;Today I was looking into a bit of JavaScript that runs as part of our build process. (I care a lot about build time. For many years I was the &lt;em&gt;de facto&lt;/em&gt; watchdog of the Go toolchain&amp;rsquo;s speed and have spent countless hours working on it.) Poking around a bit, I found that a substantive chunk of time was spent opening and parsing JavaScript files containing a bunch of data.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;No way,&amp;rdquo; I thought. So I ran an experiment.&lt;/p&gt;
&lt;p&gt;I created two sets of files, containing the same data, an NxM map. One was all the code in a single JavaScript file, like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;j0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;},&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;j0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;}};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The other was split across N JavaScript files:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./sub/k0&amp;#34;&lt;/span&gt;),&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;require&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./sub/k1&amp;#34;&lt;/span&gt;)};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where, e.g., &lt;code&gt;sub/k0&lt;/code&gt; is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;module&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exports&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;j0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then instead of N=2 and M=1, I set N=1000 and M=100, and executed the two.&lt;/p&gt;
&lt;p&gt;On my M1 mac, with all files in the page cache, going from many files to one was considerably faster:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;name  old time/op         new time/op         delta
Exec          111ms ± 1%           59ms ± 1%  -46.53%  (p=0.000 n=9+8)

name  old user-time/op    new user-time/op    delta
Exec          113ms ± 1%           51ms ± 1%  -54.62%  (p=0.000 n=10+9)

name  old sys-time/op     new sys-time/op     delta
Exec         17.5ms ± 2%          5.8ms ± 3%  -66.67%  (p=0.000 n=9+8)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Since the data files I was looking at today are autogenerated anyway, it would make sense to generate one big file instead of lots of little ones, even though it&amp;rsquo;s a bit less nice that way.&lt;/p&gt;
&lt;p&gt;Some facts don&amp;rsquo;t change: An interpreted language must still stat, open, and parse each file, and that has overhead.&lt;/p&gt;
&lt;p&gt;And it&amp;rsquo;s not just opening the file! &lt;code&gt;/usr/bin/time -l&lt;/code&gt; on a mac now prints an &amp;ldquo;instructions retired&amp;rdquo; count, which is awesome. Spreading the data across many files causes over twice as many instructions to be executed. It also increases the peak memory footprint by 15%.&lt;/p&gt;
&lt;h1 id=&#34;c&#34;&gt;C++&lt;/h1&gt;
&lt;p&gt;It&amp;rsquo;s not just interpreted languages! Compiled languages are also sensitive to the apparently unimportant detail of how your code is organized into files.&lt;/p&gt;
&lt;p&gt;At my first startup, card.io, I was doing computer vision and machine learning on underpowered mobile devices. The heavy computational work was in a bunch of C++ files. On a (somewhat educated) lark, I preprocessed all the files into a single giant input file. Lo! The code got a lot faster.&lt;/p&gt;
&lt;p&gt;The compilation unit (what a single invocation of the compiler works on) of C/C++ is a file. By placing all the code in a single compilation unit, the compiler could see more of the code at one time and thus optimize it much more. I didn&amp;rsquo;t even bother grumbling. I just added the preprocessor to our build system and moved on.&lt;/p&gt;
&lt;p&gt;Link-time optimization has improved the situation some since then, because it provides the opportunity to optimize across compilation units. But that comes at a steep cost. The results of compilation can be cached, but linking must be done every time, so LTO slows down builds.&lt;/p&gt;
&lt;h1 id=&#34;go&#34;&gt;Go&lt;/h1&gt;
&lt;p&gt;Go mostly gets this right.&lt;/p&gt;
&lt;p&gt;The compilation unit of Go is a package, which can contain multiple files. Moving code around between those files has no impact on performance.&lt;/p&gt;
&lt;p&gt;What about moving code around between packages, though? Perhaps surprisingly, there are very few cases in which this matters.&lt;/p&gt;
&lt;p&gt;When compiling a package, the Go compiler emits information about optimizations (mostly inlining and escape analysis) that will be useful when compiling code that imports that package. So moving code around between packages typically has no impact at all.&lt;/p&gt;
&lt;p&gt;As far as I know, this has never been written down as a formal design decision for the language, but it comes up occasionally in discussion.&lt;/p&gt;
&lt;p&gt;One hard problem in compiler design is phase ordering. Here&amp;rsquo;s an example. Should it do inlining before or after dead code elimination?&lt;/p&gt;
&lt;p&gt;Obviously, compilers should inline before dead code elimination, because inlining will often cause code to be provably dead. (Imagine code like &lt;code&gt;if debug() { ... }&lt;/code&gt; and &lt;code&gt;func debug() bool { return false }&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;Obviously, compilers should do dead code elimination before inlining, because dead code elimination will provide a clearer picture of the true complexity and size of a function, which is important for making good inlining decisions.&lt;/p&gt;
&lt;p&gt;Hmmm. Obviously, compilers should apply optimizations in a loop until they reach a fixed point. What could go wrong?&lt;/p&gt;
&lt;p&gt;The Go compiler does inlining early. But the part where it emits information for subsequent compilations occurs very late. We could have the best of both worlds: We could inline early intra-package, but make better inter-package inlining decisions by using information that wasn&amp;rsquo;t available earlier.&lt;/p&gt;
&lt;p&gt;However, this could incentivize programmers to warp the structure of their code to get different optimization results. And that is a showstopper, at least for Go.&lt;/p&gt;
&lt;p&gt;Go&amp;rsquo;s definitely not perfect. For example, its lackluster inlining heuristic (and lack of an pressure release valve) causes programmers to mangle their code. But that&amp;rsquo;s considered a bug. And it&amp;rsquo;s slightly off-topic for this post.&lt;/p&gt;
&lt;h1 id=&#34;moral&#34;&gt;Moral&lt;/h1&gt;
&lt;p&gt;The moral of this story is not that Go is superior, although I am obviously fond of it; there are complex trade-offs here.&lt;/p&gt;
&lt;p&gt;People like to say things like &amp;ldquo;tools don&amp;rsquo;t matter&amp;rdquo; and &amp;ldquo;tools are just a way to get the job done&amp;rdquo;. I disagree.&lt;/p&gt;
&lt;p&gt;Our tools generate incentives that end up warping how we do our jobs, in ways subtle (code organization, dependency culture) and not-so-subtle (formatting flame wars, &lt;a href=&#34;https://xkcd.com/303/&#34;&gt;hallway sword fights&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Programmers should pick their tools carefully. And tool authors should think hard about the incentives they create.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>How to test a Go beta or RC</title>
      <link>https://commaok.xyz/post/test-beta/</link>
      <pubDate>Sun, 13 Jun 2021 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/test-beta/</guid>
      <description>&lt;p&gt;Around this time in the &lt;a href=&#34;https://github.com/golang/go/wiki/Go-Release-Cycle&#34;&gt;Go release cycle&lt;/a&gt;,
the Go team &lt;a href=&#34;https://groups.google.com/forum/#!forum/golang-announce&#34;&gt;asks people to test Go betas and release candidates&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Please help! It is easy, fast, and important.&lt;/p&gt;
&lt;p&gt;This post is about how, what, and why to test.&lt;/p&gt;
&lt;h1 id=&#34;installation&#34;&gt;Installation&lt;/h1&gt;
&lt;p&gt;Pre-releases can be downloaded using &lt;code&gt;go get&lt;/code&gt;. For example:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go install golang.org/dl/go1.17beta1@latest
$ go1.17beta1 download
$ go1.17beta1 test your/favorite/package
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A complete list of pre-releases is available at &lt;a href=&#34;https://pkg.go.dev/golang.org/dl&#34;&gt;https://pkg.go.dev/golang.org/dl&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;betas&#34;&gt;Betas&lt;/h1&gt;
&lt;p&gt;Betas are early looks at a new release. They sometimes have known bugs. Critical bugs are uncommon but not unheard of. New APIs may still change in response to feedback. You should not use a beta release in production.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what you should do with a Go beta release, ordered from &lt;strong&gt;easy and fast&lt;/strong&gt; to &lt;strong&gt;pretty involved&lt;/strong&gt;. Even if you only do the first item or two, it is helpful!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run your tests locally. Investigate and &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;report&lt;/a&gt; any new failures.&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&#34;https://tip.golang.org/doc/go1.17&#34;&gt;the draft release notes&lt;/a&gt;. (You may have to edit this link appropriately for newer releases.) If you see anything concerning, &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;file an issue to discuss&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Run your benchmarks locally. Investigate and &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;report&lt;/a&gt; performance regressions.&lt;/li&gt;
&lt;li&gt;If you have a staging server, CI, or anywhere you can run more involved tests, use the pre-release version there, and &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;file any issues you encounter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Look over &lt;a href=&#34;https://github.com/golang/go/blob/master/api/go1.17.txt&#34;&gt;the API diffs&lt;/a&gt;. (Again, adjust link as appropriate.) If you see anything concerning, &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;file an issue to discuss&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&#34;release-candidiates&#34;&gt;Release candidiates&lt;/h1&gt;
&lt;p&gt;Release candidates are generally free of known serious bugs. (Google tests release candidates on their live servers.) APIs should be stable.&lt;/p&gt;
&lt;p&gt;The list of things to do with a Go RC is the same as with betas, except that, if you have the bandwidth and means, you may want to try running it in production, on a small subset of servers.&lt;/p&gt;
&lt;h1 id=&#34;i-dont-have-that-much-time&#34;&gt;I don&amp;rsquo;t have that much time&lt;/h1&gt;
&lt;p&gt;It is not atypical to have one or two betas and one or two RCs. That&amp;rsquo;s a lot of testing. What if you only have a small amount of time to contribute to helping Go have bug-free releases?&lt;/p&gt;
&lt;p&gt;If you can only do one thing, &lt;strong&gt;run your tests locally using the first beta&lt;/strong&gt;. It takes just a few minutes. The earlier bugs get caught, the more likely it is they can be fixed, and fixed well.&lt;/p&gt;
&lt;p&gt;If you can do a little bit more, please &lt;strong&gt;read the release notes early&lt;/strong&gt;. You&amp;rsquo;d probably read them when the release came out anyway. By reading it early, there&amp;rsquo;s still a chance of fixing any problems you see.&lt;/p&gt;
&lt;h1 id=&#34;why-test-betas-and-rcs&#34;&gt;Why test betas and RCs?&lt;/h1&gt;
&lt;p&gt;Programming languages, and their tooling and communities, are complex creatures. People use them in marvelous and unusual ways. And programming languages are software too, and you know what that means. Despite the Go contributors&amp;rsquo; best efforts, the Go issue tracker has its fair share of frustrated programmers who have discovered too late that a new release doesn&amp;rsquo;t work for them: a subtle behavior change, a rare performance regression, an API design that is not quite right.&lt;/p&gt;
&lt;p&gt;Once a release is out, fixing these problems becomes harder and sometimes even impossible. Security problems get prompt fixes, but anything short of that, even a critical bug, won&amp;rsquo;t see a fix for a month, at the next point release. Non-critical bugs won&amp;rsquo;t be fixed until the next full Go release, six months out, at the earliest. And in many cases, thanks to the &lt;a href=&#34;https://golang.org/doc/go1compat&#34;&gt;Go 1 Compatibility Promise&lt;/a&gt;, we may simply be stuck forever with whatever the problem is.&lt;/p&gt;
&lt;p&gt;Betas and RCs are our only chance as a community to catch many issues while there&amp;rsquo;s still time to really fix them.&lt;/p&gt;
&lt;h1 id=&#34;bonus&#34;&gt;Bonus&lt;/h1&gt;
&lt;p&gt;Consider adding the &amp;ldquo;tip&amp;rdquo; version of Go to your CI. This is especially helpful in catching problems very early, but it does add a fair bit of work: Before filing issues, you need to check &lt;a href=&#34;https://build.golang.org/&#34;&gt;the build dashboard&lt;/a&gt; and investigate a bit to determine whether any failure is worth reporting.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Make your lookup table do more</title>
      <link>https://commaok.xyz/post/lookup_tables/</link>
      <pubDate>Thu, 03 Jun 2021 10:00:00 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/lookup_tables/</guid>
      <description>&lt;p&gt;Lookup tables are powerful micro-optimization tools, because they implement arbitrary transformations in cheap constant time.&lt;/p&gt;
&lt;p&gt;And yet we often do not use them to their full potential. This post is the story of one example.&lt;/p&gt;
&lt;h1 id=&#34;a-good-starting-point&#34;&gt;A good starting point&lt;/h1&gt;
&lt;p&gt;In a recent blog post, &lt;a href=&#34;https://lemire.me/blog/2021/05/28/computing-the-number-of-digits-of-an-integer-quickly/#comment-585804&#34;&gt;Daniel Lemire rediscovered a technique for calculating the base ten length of a uint32&lt;/a&gt;. Start by calculating integer &lt;code&gt;log2(x)&lt;/code&gt;, do an approximate integer division to translate &lt;code&gt;log2(x)&lt;/code&gt; to &lt;code&gt;log10(x)&lt;/code&gt;, and then fix up the result as needed.&lt;/p&gt;
&lt;p&gt;His code, with some annotations:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; table[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;999&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;9999&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99999&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;999999&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;9999999&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;99999999&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;999999999&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(x)) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// log10(2) ~= 0.301, 9/32 ~= 0.281
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;y &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; table[y]; &lt;span style=&#34;color:#75715e&#34;&gt;// use lookup table to discover off-by-one due to using integer math
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; y &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The initial calculation gets us close to the right answer. The lookup table steps in to handles numbers like 9 and 10. &lt;code&gt;log2(9)&lt;/code&gt; is equal to &lt;code&gt;log2(10)&lt;/code&gt;, so we need some way to distinguish them. &lt;code&gt;9 * log2(x) &amp;gt;&amp;gt; 5&lt;/code&gt; yields 0 for both 9 and 10. Comparing &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;table[0]&lt;/code&gt; tells us to increment the result for 10, but not for 9. Then we increment again, yielding the correct result: 1 for 9, 2 for 10.&lt;/p&gt;
&lt;p&gt;But lookup tables let us do arbitrary transformations, and we&amp;rsquo;re getting only a single bit out of it: Increment or not. For example, maybe we could work that increment at the end of the function into the lookup table somehow. (Yes, that increment is free on amd64 architectures with a good enough compiler by using the &lt;code&gt;ADC&lt;/code&gt; instruction.)&lt;/p&gt;
&lt;h1 id=&#34;some-groundwork&#34;&gt;Some groundwork&lt;/h1&gt;
&lt;p&gt;If we used a lookup table to modify the original input, then we would be in a better place to absorb some of the later work. For any given power of two range (e.g. 8–15), there is at most one transition from an n digit number to an n+1 digit number. For the range 8–15, that transition is from 9 to 10. For the range 16–31, there isn’t one.&lt;/p&gt;
&lt;p&gt;My &lt;a href=&#34;https://lemire.me/blog/2021/05/28/computing-the-number-of-digits-of-an-integer-quickly/#comment-585476&#34;&gt;first attempt at using this observation&lt;/a&gt; was to use a lookup table to translate base 2 transitions (7 to 8) to line up with base 10 transitions (9 to 10).&lt;/p&gt;
&lt;p&gt;My code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; table[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10000000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100000000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, (&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1000000000&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; table[&lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(x)]; &lt;span style=&#34;color:#75715e&#34;&gt;// adjust input to align base 2 and base 10 transitions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; ans &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;77&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(x)) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// log10(2) ~= 0.301, 77x/256 ~= 0.301
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; ans &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Consider the inputs 9 and 10. We start with integer log2, which yields 3 in both cases. Then we add &lt;code&gt;table[3]&lt;/code&gt;, which is 6. This transforms 9 and 10 into 15 and 16. Now if we take the integer log2 again we get 3 and 4. Integer division and an increment yields the correct result (1 and 2).&lt;/p&gt;
&lt;p&gt;This doesn’t actually reduce any of the other post-lookup-table work, but it sets us up to do so.&lt;/p&gt;
&lt;p&gt;Note that the table has grown from 9 uint32s to 32 uint32s. This is probably acceptable.&lt;/p&gt;
&lt;h1 id=&#34;a-small-step&#34;&gt;A small step&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&#34;https://lemire.me/blog/2021/05/28/computing-the-number-of-digits-of-an-integer-quickly/#comment-585555&#34;&gt;next iteration&lt;/a&gt; looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; table[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;246&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;240&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;224&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3996&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3968&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3840&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;64536&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64512&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;63488&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;61440&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1038576&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1032192&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;1015808&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;16677216&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;16646144&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;16515072&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;267435456&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;267386880&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;266338304&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;264241152&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4284967296&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;4278190080&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4261412864&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;68619476736&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;68585259008&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;68451041280&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1098511627776&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1098437885952&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#ae81ff&#34;&gt;1097364144128&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; n &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; (&lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt;)(x) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; table[&lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(x)];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(n) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The non-lookup calculations here have gotten simpler. The table is a lot more complex, but that’s OK. That complexity is computationally free! The table has also grown again, from 32 uint32s to 32 uint64s. If speed matters, this is probably acceptable. (And if it doesn&amp;rsquo;t matter, go implement something obvious instead.)&lt;/p&gt;
&lt;p&gt;The basic idea is the same as before. Add an offset to each base 2 range to translate base 2 transitions onto base 10 transitions. But now we also tack on extra amounts to make our post-lookup calculations computationally cheaper: a single shift, instead of a multiply, a shift, and an increment. Adding &lt;code&gt;table[3]&lt;/code&gt; to 9 and 10 make them 255 and 256. &lt;code&gt;log2(255) / 4&lt;/code&gt; is 1 and &lt;code&gt;log2(256) / 4&lt;/code&gt; is 2, as desired.&lt;/p&gt;
&lt;h1 id=&#34;a-great-leap&#34;&gt;A great leap&lt;/h1&gt;
&lt;p&gt;That’s where I left it. Then &lt;a href=&#34;https://lemire.me/blog/2021/05/28/computing-the-number-of-digits-of-an-integer-quickly/#comment-585916&#34;&gt;Kendall Willets stepped in and made a marvelous leap&lt;/a&gt;. The code below is from &lt;a href=&#34;https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-faster/&#34;&gt;Daniel Lemire’s follow-up blog post laying out Kendall&amp;rsquo;s approach&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64_t&lt;/span&gt; table[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;4294967296&lt;/span&gt;,  &lt;span style=&#34;color:#ae81ff&#34;&gt;8589934582&lt;/span&gt;,  &lt;span style=&#34;color:#ae81ff&#34;&gt;8589934582&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;8589934582&lt;/span&gt;,  &lt;span style=&#34;color:#ae81ff&#34;&gt;12884901788&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;12884901788&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;12884901788&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;17179868184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;17179868184&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;17179868184&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;21474826480&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;21474826480&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;21474826480&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;21474826480&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25769703776&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;25769703776&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;25769703776&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;30063771072&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;30063771072&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;30063771072&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;34349738368&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;34349738368&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;34349738368&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;34349738368&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;38554705664&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;38554705664&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;38554705664&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	  &lt;span style=&#34;color:#ae81ff&#34;&gt;41949672960&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;41949672960&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;41949672960&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#ae81ff&#34;&gt;42949672960&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;42949672960&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (x &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; table[&lt;span style=&#34;color:#a6e22e&#34;&gt;int_log2&lt;/span&gt;(x)]) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Lookup tables can implement arbitrary functions! Kendall embeds two pieces of information in a uint64: the integer log10 for that base 2 range in the top 32 bits and the transition translation (if any) in the bottom 32 bits. The table is eye-watering, but your CPU doesn&amp;rsquo;t care.&lt;/p&gt;
&lt;p&gt;Consider 9 and 10 again. &lt;code&gt;table[3]&lt;/code&gt; is &lt;code&gt;8589934582&lt;/code&gt;, which is &lt;code&gt;(2&amp;lt;&amp;lt;32) - 10&lt;/code&gt;. Adding 9 and 10 to that yields &lt;code&gt;(2&amp;lt;&amp;lt;32) - 1&lt;/code&gt; and &lt;code&gt;2&amp;lt;&amp;lt;32&lt;/code&gt;. If we now shift right 32 bits, this yields 1 and 2 respectively. Voilà!&lt;/p&gt;
&lt;p&gt;We now require only an integer log2, a table lookup, an addition, and a shift. Not bad.&lt;/p&gt;
&lt;p&gt;My three takeaways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Lookup tables implement arbitrary transformations at a constant cost. If you have one in your code, it’s worth asking whether it can do more work for you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open collaboration can be delightful, with thoughtful people. Three people’s combined insights and refinements broke new ground (I believe) on an old question. I&amp;rsquo;m not sure any of us would have gotten there alone.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;This is an existence proof that there are websites on the internet where it’s worth reading the comments.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>What happens when you load into x0 on RISC-V?</title>
      <link>https://commaok.xyz/post/riscv_isa_blog_post/</link>
      <pubDate>Wed, 17 Feb 2021 10:00:00 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/riscv_isa_blog_post/</guid>
      <description>&lt;p&gt;A small thing of which I am irrationally proud: I was the proximate cause for the addition of a sentence to the &lt;a href=&#34;https://github.com/riscv/riscv-isa-manual/releases/download/draft-20200727-8088ba4/riscv-spec.pdf&#34;&gt;RISC-V ISA spec&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the sentence:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Loads with a destination of x0 must still raise any exceptions and cause any other side effects even though the load value is discarded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s OK if you have no idea what that means. You will soon.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the story.&lt;/p&gt;
&lt;h1 id=&#34;background&#34;&gt;Background&lt;/h1&gt;
&lt;p&gt;In the summer of 2016, I wrote most of the initial RISC-V Go compiler implementation. (&lt;a href=&#34;https://github.com/prattmic&#34;&gt;Michael Pratt&lt;/a&gt; and &lt;a href=&#34;https://github.com/bbarenblat&#34;&gt;Benjamin Barenblat&lt;/a&gt; worked on the assembler, linker, and runtime, and other people &lt;a href=&#34;https://github.com/sorear&#34;&gt;jumped in&lt;/a&gt; and &lt;a href=&#34;https://github.com/4a6f656c&#34;&gt;ultimately completed the port&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;I was writing the first version of the RISC-V SSA lowering rules. Those rules turn a generic, architecture-independent description of Go code into a RISC-V-specific set of operations that ultimately get lowered into RISC-V instructions.&lt;/p&gt;
&lt;p&gt;One of those lowering rules specified how to lower a nil check.&lt;/p&gt;
&lt;h1 id=&#34;nil-checks-in-the-go-compiler&#34;&gt;Nil checks in the Go compiler&lt;/h1&gt;
&lt;p&gt;Consider this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;5000&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// we&amp;#39;ll explain this later
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;f&lt;/code&gt; does &lt;em&gt;almost&lt;/em&gt; nothing. But not nothing. &lt;code&gt;f&lt;/code&gt; evaluates &lt;code&gt;t.b&lt;/code&gt; for side-effects. If &lt;code&gt;t&lt;/code&gt; is nil, &lt;code&gt;f&lt;/code&gt; panics.&lt;/p&gt;
&lt;p&gt;In the Go compiler, this is (unsurprisingly) called a nil check. The compiler arranges to execute an instruction that will fault if &lt;code&gt;t&lt;/code&gt; is nil.&lt;/p&gt;
&lt;p&gt;On amd64, &lt;code&gt;f&lt;/code&gt; compiles to three instructions:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;MOVQ	&amp;#34;&amp;#34;.t+8(SP), AX
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Get the value of &lt;code&gt;t&lt;/code&gt; off of the stack and put it in the &lt;code&gt;AX&lt;/code&gt; register.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;TESTB	AL, (AX)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Load the value pointed to by &lt;code&gt;AX&lt;/code&gt; and do something with it. The parens around &lt;code&gt;AX&lt;/code&gt; mean dereference the pointer in the &lt;code&gt;AX&lt;/code&gt; register. It doesn&amp;rsquo;t matter here what the &lt;code&gt;TESTB&lt;/code&gt; instruction does; it was chosen because it is short to encode. It&amp;rsquo;s the deferencing that matters. If the load faults, the runtime will receive a signal and turn that into a panic.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;RET
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Return from the function. We only reach this instruction if we don&amp;rsquo;t panic first.&lt;/p&gt;
&lt;h1 id=&#34;implicit-nil-checks&#34;&gt;Implicit nil checks&lt;/h1&gt;
&lt;p&gt;Why does type &lt;code&gt;T&lt;/code&gt; above contain a &lt;code&gt;[5000]byte&lt;/code&gt; field?&lt;/p&gt;
&lt;p&gt;There are &lt;em&gt;lots&lt;/em&gt; of nil checks in a typical Go program. As an optimization, the runtime allocates a &lt;em&gt;guard page&lt;/em&gt; at address 0, typically with size 4096 bytes. Any loads from an address &amp;lt; 4096 will fault.&lt;/p&gt;
&lt;p&gt;As a result, if you&amp;rsquo;re dereferencing a struct field with a small offset, we can directly attempt to load from the calculated address of that struct field. If the pointer is zero, then the calculated address will be &amp;lt; 4096, and it&amp;rsquo;ll fault. There&amp;rsquo;s no need for a separate, explicit nil check.&lt;/p&gt;
&lt;p&gt;For example, if I had used &lt;code&gt;[20]byte&lt;/code&gt; above, then &lt;code&gt;*t.b&lt;/code&gt; requires loading from &lt;code&gt;t&lt;/code&gt; plus 20. If &lt;code&gt;t&lt;/code&gt; is nil (0), then that address is 20, which is located in the guard page.&lt;/p&gt;
&lt;p&gt;Since we have a &lt;code&gt;[5000]byte&lt;/code&gt; field above, the guard page isn&amp;rsquo;t enough, so we need an explicit nil check.&lt;/p&gt;
&lt;p&gt;This makes it sounds like explicit nil checks are exceedingly rare. They&amp;rsquo;re not; they show up in other ways too.&lt;/p&gt;
&lt;h1 id=&#34;back-to-risc-v&#34;&gt;Back to RISC-V&lt;/h1&gt;
&lt;p&gt;I had to decide how RISC-V should lower explicit nil checks.&lt;/p&gt;
&lt;p&gt;RISC-V has a dedicated &lt;em&gt;zero register&lt;/em&gt;, &lt;code&gt;x0&lt;/code&gt;. It always holds the value zero, and writes to it are discarded. It&amp;rsquo;s like &lt;code&gt;/dev/null&lt;/code&gt; and &lt;code&gt;/dev/zero&lt;/code&gt; rolled into one.&lt;/p&gt;
&lt;p&gt;It sounds like just the thing for a nil check: We can derefence the pointer and load the value into &lt;code&gt;x0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s &lt;code&gt;f&lt;/code&gt;, compiled for RISC-V:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;LD	&amp;#34;&amp;#34;.t+8(SP), X3
LB	(X3), X0
JALR	X0, X1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is almost identical to the amd64 version. The first instruction loads the pointer from the stack. The second instruction dereferences it into &lt;code&gt;x0&lt;/code&gt;. The final instruction returns.&lt;/p&gt;
&lt;p&gt;There was only one problem: Would it work?&lt;/p&gt;
&lt;h1 id=&#34;an-ambiguity-in-the-spec&#34;&gt;An ambiguity in the spec&lt;/h1&gt;
&lt;p&gt;If you&amp;rsquo;re loading a value in order to discard it, do you really need to load it at all? if you&amp;rsquo;re writing to &lt;code&gt;x0&lt;/code&gt;, maybe you can just skip it.&lt;/p&gt;
&lt;p&gt;There is an analog from amd64. The &lt;code&gt;CMOV&lt;/code&gt; instruction does a conditional move. If a flag is set, then it loads or moves a value, and not otherwise. It shows up when compiling code like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The core of this function compiled for amd64 is:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;TESTQ	AX, AX
MOVL	$1, AX
MOVL	$3, CX
CMOVQEQ	CX, AX
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;TESTQ&lt;/code&gt; sets the &lt;code&gt;EQ&lt;/code&gt; flag if x is 0. The next two instructions put 1 in &lt;code&gt;AX&lt;/code&gt; and 3 in &lt;code&gt;CX&lt;/code&gt;. Last, if the &lt;code&gt;EQ&lt;/code&gt; flag is set, we move &lt;code&gt;CX&lt;/code&gt; into &lt;code&gt;AX&lt;/code&gt;. &lt;code&gt;AX&lt;/code&gt; now holds the correct value of y to return.&lt;/p&gt;
&lt;p&gt;If a &lt;code&gt;CMOV&lt;/code&gt; instruction includes a load from memory, that load is done unconditionally, even though the write of that value into the destination register is conditional.&lt;/p&gt;
&lt;p&gt;I knew (and know) approximately nothing about hardware, but I can guess why this is a good decision. If you&amp;rsquo;re doing out of order execution, you might not know yet what the flags are going to be when you reach that &lt;code&gt;CMOV&lt;/code&gt; instruction. But memory loads are slow. We want to start that memory load early for maximum benefit. So it is useful to be able to do the load unconditionally, even if it is inconvenient for compiler developers.&lt;/p&gt;
&lt;p&gt;But the same consideration doesn&amp;rsquo;t really apply to RISC-V. There&amp;rsquo;s no uncertainty about whether the instruction writes to &lt;code&gt;x0&lt;/code&gt;. Skipping the load would be easy and cheap.&lt;/p&gt;
&lt;h1 id=&#34;denouement&#34;&gt;Denouement&lt;/h1&gt;
&lt;p&gt;I asked my co-conspirators, and one of them asked &lt;a href=&#34;https://www.sifive.com/about/andrew-waterman&#34;&gt;Andrew Waterman&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;He replied:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We debated this hole in the spec at length, but neglected to write down the conclusion.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The main reason we went with this definition is cleaner semantics for memory-mapped I/O loads that trigger side effects. The opposite choice is also defensible (it gives you a non-binding prefetch instruction for free).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Light-years ahead of me, unsurprisingly. But convenient for Go&amp;rsquo;s nil checks. And me having asked did help tie up one little loose end.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>git rebase --fork-point considered harmful (by me)</title>
      <link>https://commaok.xyz/post/fork-point/</link>
      <pubDate>Mon, 02 Nov 2020 09:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/fork-point/</guid>
      <description>&lt;p&gt;This is the first blog post I&amp;rsquo;ve written that isn&amp;rsquo;t about Go, and it&amp;rsquo;s pretty weedy. Feel free to stop reading now.&lt;/p&gt;
&lt;p&gt;This is a git &lt;a href=&#34;https://github.com/golang/go/wiki/ExperienceReports&#34;&gt;experience report&lt;/a&gt; based on something that bit me hard today, despite being quite experienced with git. Play along!&lt;/p&gt;
&lt;h1 id=&#34;prologue&#34;&gt;Prologue&lt;/h1&gt;
&lt;p&gt;Initialize a repo. Create two commits.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git init .
Initialized empty Git repository in &amp;lt;redacted&amp;gt;

$ touch readme
$ git add readme
$ git commit -a -m &amp;#34;initial commit&amp;#34;
[main (root-commit) ac2d8e7] initial commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 readme

$ touch readme.2
$ git add readme.2
$ git commit -a -m &amp;#34;another commit&amp;#34;
[main fb0f7fe] another commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 readme.2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So far, pretty mundane. Here&amp;rsquo;s what the repo looks like:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git log --all --decorate --oneline --graph
* fb0f7fe (HEAD -&amp;gt; main) another commit
* ac2d8e7 initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;oops&#34;&gt;Oops&lt;/h1&gt;
&lt;p&gt;I meant to create &lt;code&gt;readme.2&lt;/code&gt; on a branch. No problem. Let&amp;rsquo;s create that branch now.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git checkout -b branch
Branch &amp;#39;branch&amp;#39; set up to track local branch &amp;#39;main&amp;#39; by rebasing.
Switched to a new branch &amp;#39;branch&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Oh, and better put &lt;code&gt;main&lt;/code&gt; back where it belongs.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git checkout main
Switched to branch &amp;#39;main&amp;#39;
$ git reset --hard HEAD~1
HEAD is now at ac2d8e7 initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the repo looks like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git log --all --decorate --oneline --graph
* 95cc2c0 (branch) another commit
* 20a231b (HEAD -&amp;gt; main) initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;bug-fix&#34;&gt;Bug fix&lt;/h1&gt;
&lt;p&gt;Let&amp;rsquo;s fix a bug on main.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ echo &amp;#34;nothing to see here&amp;#34; &amp;gt; readme
$ git commit -a -m &amp;#34;fill out the readme&amp;#34;
[main eebece5] fill out the readme
 1 file changed, 1 insertion(+)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;branch&lt;/code&gt; have diverged a bit.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git log --all --decorate --oneline --graph
* eebece5 (HEAD -&amp;gt; main) fill out the readme
| * fb0f7fe (branch) another commit
|/  
* ac2d8e7 initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;time-to-rebase&#34;&gt;Time to rebase&lt;/h1&gt;
&lt;p&gt;Let&amp;rsquo;s get &lt;code&gt;branch&lt;/code&gt; rebased onto &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git checkout branch
Switched to branch &amp;#39;branch&amp;#39;
Your branch and &amp;#39;main&amp;#39; have diverged,
and have 1 and 1 different commits each, respectively.
  (use &amp;#34;git pull&amp;#34; to merge the remote branch into yours)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Before reading any further, stop. Summon your git fu. What will happen when we run &lt;code&gt;git rebase&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re like me, you expect something like this:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;* 7a8805e (HEAD -&amp;gt; branch) another commit
* eebece5 (main) fill out the readme
* ac2d8e7 initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Three commits. &lt;code&gt;branch&lt;/code&gt; has been rebased on top of &lt;code&gt;main&lt;/code&gt;, so it is one commit ahead of it.&lt;/p&gt;
&lt;p&gt;OK, let&amp;rsquo;s find out what really happens.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git rebase
Successfully rebased and updated refs/heads/branch.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Moment of truth.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git log --all --decorate --oneline --graph
* eebece5 (HEAD -&amp;gt; branch, main) fill out the readme
* ac2d8e7 initial commit
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There are only two commits. &lt;code&gt;branch&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; are on the same commit.&lt;/p&gt;
&lt;p&gt;What happened to the third commit? It&amp;rsquo;s gone.&lt;/p&gt;
&lt;h1 id=&#34;denouement&#34;&gt;Denouement&lt;/h1&gt;
&lt;p&gt;What happened was &lt;code&gt;--fork-point&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first step to a rebase (and many other operations) is to find a &lt;a href=&#34;https://git-scm.com/docs/git-merge-base&#34;&gt;merge base&lt;/a&gt;. This is some shared commit in history, common ground from which to trace divergent paths.&lt;/p&gt;
&lt;p&gt;The most obvious way to find a merge base is by looking at the graph for the most recent commit reachable by everyone.&lt;/p&gt;
&lt;p&gt;But inspecting the graph doesn&amp;rsquo;t always get you the ideal result. What if you intentionally abandoned some commits on &lt;code&gt;main&lt;/code&gt;? Looking just at the graph to find the merge base might accidentally resuscitate them. There&amp;rsquo;s a &lt;a href=&#34;https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode&#34;&gt;fully worked example&lt;/a&gt; in the git docs.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;--fork-point&lt;/code&gt; flag is a clever attempt to work around this. &lt;code&gt;git rebase&lt;/code&gt; describes it thus:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use reflog to find a better common ancestor between &lt;code&gt;upstream&lt;/code&gt; and &lt;code&gt;branch&lt;/code&gt; when calculating which commits have been introduced by &lt;code&gt;branch&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;a href=&#34;https://git-scm.com/docs/git-reflog&#34;&gt;git reflog&lt;/a&gt; is a log of changes made to git refs. (If you don&amp;rsquo;t know what a &amp;ldquo;ref&amp;rdquo; is, substitute the word &amp;ldquo;branch&amp;rdquo;.) It&amp;rsquo;s meta version control. It tracks what you did with your version control over time.&lt;/p&gt;
&lt;p&gt;The reflog is quite useful if you make a horrible mistake. You can poke through the reflog to find a lost commit.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--fork-point&lt;/code&gt; looks through the &lt;em&gt;temporal history of your git repo&lt;/em&gt; to pick a merge base, &amp;ldquo;allowing you to replay only the commits on your topic, excluding the commits the other side later discarded.&amp;rdquo; In this context, &amp;ldquo;later&amp;rdquo; really means later in time, not &amp;ldquo;descendent of&amp;rdquo; in abstract git graph world.&lt;/p&gt;
&lt;p&gt;And here we have the explanation for what happened. I discovered I had committed on &lt;code&gt;main&lt;/code&gt; by accident, and &lt;em&gt;reset &lt;code&gt;main&lt;/code&gt; to the previous commit&lt;/em&gt;. From &lt;code&gt;--fork-point&lt;/code&gt;&amp;rsquo;s perspective, the &lt;code&gt;main&lt;/code&gt; branch had &lt;em&gt;discarded&lt;/em&gt; the commit on &lt;code&gt;branch&lt;/code&gt;. Therefore it was not included when we selected a merge base to rebase &lt;code&gt;branch&lt;/code&gt; onto &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&#34;whats-wrong-here&#34;&gt;What&amp;rsquo;s wrong here?&lt;/h1&gt;
&lt;p&gt;To my mind, two things went wrong here.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--fork-point&lt;/code&gt; assumes that discarded commits were discarded &lt;em&gt;because they were unwanted&lt;/em&gt;. But that is not always true. In my case, they were discarded because they were unwanted &lt;em&gt;at that moment&lt;/em&gt;. Adding more clever heuristics might help some here, but I suspect it&amp;rsquo;s impossible to infer intent, which is what is required.&lt;/p&gt;
&lt;p&gt;The bigger issue is that the behavior of &lt;code&gt;git rebase&lt;/code&gt; now depends on (almost) invisible, inscrutable state. The ability to mentally model what a command will do is critical to being able to use any tool. It&amp;rsquo;s pretty easy to view a git graph; it is the default view for most git UIs. And it&amp;rsquo;s not too hard as a human to pick out the topological merge base from there. The reflog is all but invisible. And it is definitely not easy for a human to process.&lt;/p&gt;
&lt;h1 id=&#34;the-fix&#34;&gt;The fix&lt;/h1&gt;
&lt;p&gt;The solution is obviously more flags. My git config&amp;rsquo;s &lt;code&gt;[alias]&lt;/code&gt; section now includes &lt;code&gt;r = rebase --no-fork-point&lt;/code&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Generating safer Go code</title>
      <link>https://commaok.xyz/post/safer-generated-code/</link>
      <pubDate>Wed, 28 Oct 2020 09:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/safer-generated-code/</guid>
      <description>&lt;p&gt;It&amp;rsquo;s easy to forget to call &lt;code&gt;go generate&lt;/code&gt; when you need to. Failure to regenerate can mean nasty bugs.&lt;/p&gt;
&lt;p&gt;Venerable gopher &lt;a href=&#34;https://github.com/rogpeppe/&#34;&gt;Rog Peppe&lt;/a&gt; found an excellent technique for guarding against this class of bugs. Like many good ideas, it is obvious in retrospect.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Generate code that will not compile if needs to be regenerated.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I&amp;rsquo;ll illustrate this with two examples.&lt;/p&gt;
&lt;h3 id=&#34;stringer&#34;&gt;stringer&lt;/h3&gt;
&lt;p&gt;The first example comes directly from Rog, in the &lt;a href=&#34;https://pkg.go.dev/golang.org/x/tools/cmd/stringer&#34;&gt;&lt;code&gt;stringer&lt;/code&gt;&lt;/a&gt; command. &lt;code&gt;stringer&lt;/code&gt; generates a &lt;code&gt;String() string&lt;/code&gt; method for integer types that have defined constants.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;One&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Two&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;stringer&lt;/code&gt; will generate a method that returns &lt;code&gt;&amp;quot;One&amp;quot;&lt;/code&gt; for &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;&amp;quot;Two&amp;quot;&lt;/code&gt; for &lt;code&gt;2&lt;/code&gt;, and &lt;code&gt;&amp;quot;T(3)&amp;quot;&lt;/code&gt; for &lt;code&gt;3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What if you now change the value of &lt;code&gt;One&lt;/code&gt; to be &lt;code&gt;3&lt;/code&gt; and forget to re-generate?&lt;/p&gt;
&lt;p&gt;Well, &lt;code&gt;stringer&lt;/code&gt; also generated this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;One&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;Two&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function is named &lt;code&gt;_&lt;/code&gt;, which means it is impossible to call it. The compiler won&amp;rsquo;t even bother generating code for it. It will, however, typecheck it. And typechecking is where the magic happens.&lt;/p&gt;
&lt;p&gt;When the value of &lt;code&gt;One&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;x[One-1]&lt;/code&gt; evaluates to &lt;code&gt;x[0]&lt;/code&gt;. Since &lt;code&gt;x&lt;/code&gt; has length &lt;code&gt;1&lt;/code&gt;, that&amp;rsquo;s OK.&lt;/p&gt;
&lt;p&gt;When the value of &lt;code&gt;One&lt;/code&gt; is &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;x[One-1]&lt;/code&gt; evaluates to &lt;code&gt;x[2]&lt;/code&gt;. But &lt;code&gt;x&lt;/code&gt; only has length &lt;code&gt;1&lt;/code&gt;! Attempts to compile this generate a compiler error: &lt;code&gt;invalid array index One - 1 (out of bounds for 1-element array)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The function &lt;em&gt;recorded the values of the constants when stringer was run&lt;/em&gt; and &lt;em&gt;fails to compile if those values change&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;cloner&#34;&gt;cloner&lt;/h3&gt;
&lt;p&gt;Now that we know the trick, we can apply it elsewhere.&lt;/p&gt;
&lt;p&gt;Tailscale has a little bespoke &lt;a href=&#34;https://github.com/tailscale/tailscale/blob/main/cmd/cloner/cloner.go&#34;&gt;tool to generate Clone methods for structs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The output of &lt;code&gt;cloner&lt;/code&gt; depends on the input struct fields. How can we trigger a compilation failure if we forget to re-run the tool after changing an input struct?&lt;/p&gt;
&lt;p&gt;The trick is to duplicate the original struct in the generated code and then attempt to convert from the original struct to the current struct.&lt;/p&gt;
&lt;p&gt;We start with this input code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After generating a &lt;code&gt;Clone&lt;/code&gt; method for &lt;code&gt;T&lt;/code&gt;, &lt;code&gt;cloner&lt;/code&gt; also generates:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}{})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here we&amp;rsquo;ve written out the exact form of &lt;code&gt;T&lt;/code&gt; when we generated the code, and assigned it to &lt;code&gt;_&lt;/code&gt;, which the compiler can discard. However, it still must be typechecked.&lt;/p&gt;
&lt;p&gt;Suppose we now change the type &lt;code&gt;T&lt;/code&gt;. Let&amp;rsquo;s add a new field.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;Y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The conversion now fails: It&amp;rsquo;s not possible to convert a &lt;code&gt;struct { X int }&lt;/code&gt; to a &lt;code&gt;struct { X int; Y string }&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Similar to stringer, cloner &lt;em&gt;recorded the types when cloner was run&lt;/em&gt; and now &lt;em&gt;fails to compile if those types change&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&#34;compile-time-assertion-taxonomy&#34;&gt;Compile-time assertion taxonomy&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve seen two forms of assertions that can trigger during typechecking: x == y and a struct&amp;rsquo;s fields are unchanged.&lt;/p&gt;
&lt;p&gt;There are others. For example, you can use conversions to assert that a type implements an interface. You can use conversion to uint to assert that one untyped constant is greater than or equal to than another. (You can&amp;rsquo;t convert a negative constant to uint.)&lt;/p&gt;
&lt;p&gt;There are some obscure ones, of questionable utility. For example, you could assert that two concrete types are distinct by putting them both as cases in a type switch, which disallows duplicate types.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know of any attempt to exhaustively list compile-time assertions (aside from the spec) and how they can be used, with examples. Someone please make one!&lt;/p&gt;
&lt;p&gt;Matthew Dempsky has &lt;a href=&#34;https://github.com/golang/go/issues/34868&#34;&gt;proposed that Go add explicit compile time assertions&lt;/a&gt; for boolean expressions. (That doesn&amp;rsquo;t cover relationships between types, although maybe generics would break some new ground here.) And I&amp;rsquo;ve written about a quirky way that you can write &lt;a href=&#34;https://commaok.xyz/post/compile-time-assertions/&#34;&gt;link-time assertions&lt;/a&gt; in Go.&lt;/p&gt;
&lt;h3 id=&#34;call-to-action&#34;&gt;Call to action&lt;/h3&gt;
&lt;p&gt;If you maintain a code generator, please check whether you can use this technique to protect your users from bugs. One obvious category is generated serialization/deserialization routines. There are almost certainly others.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Discovering alloc size classes in Go</title>
      <link>https://commaok.xyz/post/discovering-size-classes/</link>
      <pubDate>Tue, 01 Sep 2020 09:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/discovering-size-classes/</guid>
      <description>&lt;p&gt;As of Go 1.15, the Go runtime&amp;rsquo;s &lt;a href=&#34;https://github.com/golang/go/blob/12c01f7/src/runtime/malloc.go&#34;&gt;memory allocator&lt;/a&gt; doesn&amp;rsquo;t always allocate exactly the number of bytes required for an object. Instead, it rounds up to the nearest &lt;em&gt;size class&lt;/em&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Type &lt;code&gt;T&lt;/code&gt; has a size of 9 bytes, but allocating a &lt;code&gt;T&lt;/code&gt; will use 16 bytes.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re trying to &lt;a href=&#34;https://go-review.googlesource.com/c/go/+/41797/&#34;&gt;reduce the memory usage of a program that allocates a lot of one particular type of object&lt;/a&gt;, it&amp;rsquo;s good to be aware of the size classes, as the impact of shrinking the object will be a step function.&lt;/p&gt;
&lt;h1 id=&#34;what-are-the-size-classes&#34;&gt;What are the size classes?&lt;/h1&gt;
&lt;p&gt;The easiest way to find out the size classes is to &lt;a href=&#34;https://github.com/golang/go/blob/12c01f7698cd257b7d2e4795b0f8a971ec8533b6/src/runtime/sizeclasses.go&#34;&gt;read the source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s also possible to discover them at run time!&lt;/p&gt;
&lt;p&gt;The trick is to use &lt;code&gt;append&lt;/code&gt;. &lt;code&gt;append&lt;/code&gt; gets to choose the capacity of the returned slice. And, as you would hope, &lt;code&gt;append&lt;/code&gt; is &lt;a href=&#34;https://github.com/golang/go/blob/12c01f7698cd257b7d2e4795b0f8a971ec8533b6/src/runtime/slice.go#L201&#34;&gt;aware of the allocator&lt;/a&gt;; it picks a cap that fills as much as possible of the size class it selected.&lt;/p&gt;
&lt;p&gt;We are going to start with a nil slice, cap 0. We will then append &lt;code&gt;n&lt;/code&gt; bytes to it. &lt;code&gt;append&lt;/code&gt; will helpfully round &lt;code&gt;n&lt;/code&gt; up to the nearest size class as the new cap.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sizeup&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; append([]byte(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;), make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; cap(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you &lt;a href=&#34;https://play.golang.org/p/hAfgbpwa45t&#34;&gt;run this in a loop&lt;/a&gt;, you get a nice size class list. In the unlikely event that you were going to do this in a real program, you&amp;rsquo;d probably calculate the size classes at startup and cache them.&lt;/p&gt;
&lt;p&gt;This technique relies on an implementation detail, but hey, the mere existence of size classes is also an implementation detail.&lt;/p&gt;
&lt;h1 id=&#34;who-cares&#34;&gt;Who cares?&lt;/h1&gt;
&lt;p&gt;In particularly performance sensitive code, it sometimes makes sense to overallocate a slice, to avoid allocation in subsequent appends, such as in &lt;a href=&#34;https://github.com/golang/go/blob/master/src/math/big/nat.go#L68&#34;&gt;math/big&lt;/a&gt;. When deciding how much to overallocate, you might want to be size-class aware, so as not to waste capacity that is effectively free. See &lt;a href=&#34;https://github.com/golang/go/issues/24204&#34;&gt;#24204&lt;/a&gt; for interesting related discussion.&lt;/p&gt;
&lt;p&gt;And there&amp;rsquo;s an interesting generics connection. People are fond of pointing out that generics would obviate the need for &lt;code&gt;append&lt;/code&gt;. You could implement it yourself. But if you want your custom &lt;code&gt;append&lt;/code&gt; to be as optimized as the runtime&amp;rsquo;s, you need to be aware of the size classes.&lt;/p&gt;
&lt;h1 id=&#34;why-not-hard-code-the-size-classes&#34;&gt;Why not hard-code the size classes?&lt;/h1&gt;
&lt;p&gt;They change.&lt;/p&gt;
&lt;p&gt;Hard-coding the size classes, per-release, behind build tags, is a fine idea. But they&amp;rsquo;re also pretty easy to calculate.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Life without line numbers</title>
      <link>https://commaok.xyz/post/no-line-numbers/</link>
      <pubDate>Thu, 30 Apr 2020 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/no-line-numbers/</guid>
      <description>&lt;p&gt;If you are desperate for 6% smaller Go binaries, this blog post is for you. (I did this experiment to help out &lt;a href=&#34;https://www.tailscale.com/&#34;&gt;Tailscale&lt;/a&gt;. Disclosure: I&amp;rsquo;m an investor.) If binary size doesn&amp;rsquo;t worry you, well, maybe you&amp;rsquo;ll find it entertaining.&lt;/p&gt;
&lt;p&gt;In order to get example numbers for this post, I grabbed a random item from my GOPATH. All the hard numbers in this blog post are for &lt;code&gt;github.com/mvdan/sh/cmd/shfmt&lt;/code&gt;. From a bit of experimenting, they seem fairly representative.&lt;/p&gt;
&lt;p&gt;I am using &lt;a href=&#34;https://github.com/golang/go/commit/9d812cfa5c&#34;&gt;commit 9d812cfa5c&lt;/a&gt; of the Go toolchain as my base commit. This is the &lt;code&gt;master&lt;/code&gt; branch as of April 29, 2020; it will probably be similar to the Go 1.15beta1 release. I&amp;rsquo;m using it rather than Go 1.14 because it contains several binary size reductions, including &lt;a href=&#34;https://go-review.googlesource.com/c/go/+/230544&#34;&gt;one in particular&lt;/a&gt; that you&amp;rsquo;ll definitely want if you&amp;rsquo;re concerned about binary sizes.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;There are lots of ways to shrink a binary. Removing extraneous dependencies is probably the best way. &lt;a href=&#34;https://go-review.googlesource.com/c/go/+/210284&#34;&gt;Avoiding global maps through judicious use of sync.Once&lt;/a&gt; can help. &lt;a href=&#34;https://go-review.googlesource.com/c/go/+/228111&#34;&gt;Keeping separable code separate by indirection&lt;/a&gt; can help. You can &lt;a href=&#34;https://twitter.com/bradfitz/status/1255704982893912064&#34;&gt;suppress equality algorithm generation&lt;/a&gt; (ick&amp;hellip;until you really need it). You can usually save double-digit percentages by stripping debugging information: pass &lt;a href=&#34;https://github.com/golang/go/issues/38777&#34;&gt;&lt;code&gt;-ldflags=-w&lt;/code&gt; to &lt;code&gt;go build&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s assume you&amp;rsquo;ve done all that. And you still need to shrink more. And that need is so pressing you&amp;rsquo;re willing to make some sacrifices for it.&lt;/p&gt;
&lt;p&gt;Go binaries contain a lot more than just executable code. There are type descriptors that describe the types in a Go program. There are garbage collection data structures. There&amp;rsquo;s debugger information. And there are mappings from PCs to position information. (And there&amp;rsquo;s lots more, too.)&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to get rid of the position information.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;We can&amp;rsquo;t just strip out the position information entirely from the binary. That would break lots of stuff.&lt;/p&gt;
&lt;p&gt;But we can make all the line numbers the same. That shouldn&amp;rsquo;t break anything. After all, no one (except gofmt) said we had to put our code on multiple lines.&lt;/p&gt;
&lt;p&gt;For example, instead of &lt;a href=&#34;https://play.golang.org/&#34;&gt;this&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, playground&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We could write &lt;a href=&#34;https://play.golang.org/p/skI5nMleZgt&#34;&gt;this&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; ( &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt; ); &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() { &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, playground&amp;#34;&lt;/span&gt;) }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Go compiler and runtime has to be prepared for lots of stuff to be on one line.&lt;/p&gt;
&lt;p&gt;We could write a preprocessor, maybe using &lt;a href=&#34;https://golang.org/cmd/go/#hdr-Compile_packages_and_dependencies&#34;&gt;&lt;code&gt;-toolexec&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://golang.org/cmd/compile/#hdr-Compiler_Directives&#34;&gt;&lt;code&gt;//line&lt;/code&gt; directives&lt;/a&gt;, but it&amp;rsquo;s easier to just hack the compiler. Fortunately, this is well-factored code, so we only need to touch two little spots.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- a/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ b/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -23,3 +23,3 @@ type Pos struct {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; // MakePos returns a new Pos for the given PosBase, line and column.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line), sat32(col)} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, 1, 1} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -101,2 +101,3 @@ type PosBase struct {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; func NewFileBase(filename string) *PosBase {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+       filename = &amp;#34;x.go&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;        base := &amp;amp;PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every file is now named &lt;code&gt;x.go&lt;/code&gt;, and every source position has line 1 and column 1. (Columns don&amp;rsquo;t actually matter for binary size, once you&amp;rsquo;ve stripped DWARF.)&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t quite enough. There are two other spots in the toolchain that get unhappy if all code lives at &lt;code&gt;x.go:1:1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The first is in &lt;a href=&#34;https://github.com/golang/go/issues/38698&#34;&gt;constructing DWARF&lt;/a&gt;, for debuggers. We can just remove that check: We are already stripping DWARF, so generating invalid DWARF doesn&amp;rsquo;t matter.&lt;/p&gt;
&lt;p&gt;The second is in cgo. There are some security checks about where certain cgo pragma can be located. We&amp;rsquo;re going to trust ourselves not to violate them (by ensuring all code keeps building with an unaltered toolchain), and remove that security check.&lt;/p&gt;
&lt;p&gt;The full diff is at &lt;a href=&#34;https://github.com/josharian/go/commit/1a3e66ceed&#34;&gt;https://github.com/josharian/go/commit/1a3e66ceed&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Now all code we compile has &lt;code&gt;x.go:1:1&lt;/code&gt; as its position.&lt;/p&gt;
&lt;p&gt;Our program, compiled with &lt;code&gt;-ldflags=-w&lt;/code&gt;, shrinks from 3,126,800 bytes to 2,938,384 bytes, or about 6%.&lt;/p&gt;
&lt;p&gt;Most of this is from shrinking the encoding of position information. A little bit of it comes from a compiler optimization.&lt;/p&gt;
&lt;p&gt;These two programs compile slightly differently:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you run &lt;code&gt;go tool compile -S x.go&lt;/code&gt; on each of these files, you&amp;rsquo;ll see that &lt;a href=&#34;https://godbolt.org/z/UFf2JL&#34;&gt;the first program&lt;/a&gt; contains two separate calls to &lt;code&gt;runtime.panicIndex&lt;/code&gt;. &lt;a href=&#34;https://godbolt.org/z/26rRog&#34;&gt;The second program&lt;/a&gt; contains only one such call. The reason is that &lt;code&gt;runtime.panicIndex&lt;/code&gt; must display a backtrace containing the line number of the line that panicked. In the first program, we need two separate panics, one for each possible panicking line number. In the second program, we don&amp;rsquo;t, so the compiler combines them.&lt;/p&gt;
&lt;p&gt;Since we are now putting all code on the same line, the compiler can combine more panics than before.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;What do we lose by doing this? Anything that needs accurate position information. Panic backtraces will still show you the PC, the function, the arguments, and so on. But all line numbers will be &lt;code&gt;x.go:1&lt;/code&gt;. With patience, you could still figure out the line number yourself based on the PC, but it&amp;rsquo;d take some manual work. Pprof will still be able to analyze performance by function and by instruction, but it&amp;rsquo;ll think everything happens on the same line, which will make analysis by line number useless.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Let&amp;rsquo;s play around a bit. What if we ditch only filenames, and keep the true line numbers? It saves only 0.9%. And as you&amp;rsquo;d then expect, keeping only accurate filenames and making all line number 1 saves 5.1%.&lt;/p&gt;
&lt;p&gt;So most of the savings are from the line numbers. What if we keep the original filenames, and truncate all line numbers to the nearest multiple of 16? That is, trim our diff down to:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- a/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ b/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -23,3 +23,3 @@ type Pos struct {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; // MakePos returns a new Pos for the given PosBase, line and column.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, 1, 1} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line/16*16 + 1), 1} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This cuts our binaries by 2.2%. Not bad. What if we divide all line numbers by 16 instead? That preserves exactly the same information as truncating, but we have to multiply by hand to get the &amp;ldquo;nearby&amp;rdquo; line number.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--- a/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+++ b/src/cmd/compile/internal/syntax/pos.go
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;@@ -23,3 +23,3 @@ type Pos struct {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt; // MakePos returns a new Pos for the given PosBase, line and column.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, 1, 1} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;+func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line/16 + 1), 1} }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This cuts our binaries by 2.75%! Why does &lt;code&gt;/16&lt;/code&gt; save 0.5% more than &lt;code&gt;/16*16&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Line numbers are stored in the binary using a &lt;a href=&#34;https://golang.org/pkg/encoding/binary/#PutVarint&#34;&gt;varint encoding&lt;/a&gt; relative to the previous line number. Smaller numbers mean smaller deltas, and can thus be stored more efficiently.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Interning strings in Go</title>
      <link>https://commaok.xyz/post/intern-strings/</link>
      <pubDate>Tue, 17 Dec 2019 08:12:48 -0700</pubDate>
      
      <guid>https://commaok.xyz/post/intern-strings/</guid>
      <description>&lt;p&gt;This blog post covers string interning in Go.&lt;/p&gt;
&lt;h1 id=&#34;what-is-a-string&#34;&gt;What is a string?&lt;/h1&gt;
&lt;p&gt;In Go, a string is &lt;a href=&#34;https://golang.org/ref/spec#String_types&#34;&gt;a (possibly empty) immutable sequence of bytes&lt;/a&gt;. The critical word here for our purposes is &lt;em&gt;immutable&lt;/em&gt;. Because byte slices are mutable, converting between &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;[]byte&lt;/code&gt; generally requires an alloc and copy, which is expensive.&lt;/p&gt;
&lt;p&gt;Under the hood, strings in Go are (currently) represented &lt;a href=&#34;https://research.swtch.com/godata&#34;&gt;as a length and a pointer to the string data&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&#34;what-is-string-interning&#34;&gt;What is string interning?&lt;/h1&gt;
&lt;p&gt;Consider this code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;s&lt;/code&gt; and &lt;code&gt;t&lt;/code&gt; are strings, so they both have a length and a data pointer. Their lengths are obviously the same. What about their data pointers?&lt;/p&gt;
&lt;p&gt;The Go language doesn&amp;rsquo;t provide us a direct way to find out. But we can sniff around with unsafe:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pointer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;reflect&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StringHeader&lt;/span&gt;)(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(This function ought to return an &lt;code&gt;unsafe.Pointer&lt;/code&gt;. See &lt;a href=&#34;https://golang.org/issue/19367&#34;&gt;Go issue 19367&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;If we &lt;code&gt;fmt.Println(pointer(s), pointer(t))&lt;/code&gt;, we get something like &lt;code&gt;4302664 4302632&lt;/code&gt;. The pointers are different; there are two separate copies of the data &lt;code&gt;hello&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;(Here&amp;rsquo;s a &lt;a href=&#34;https://play.golang.org/p/oyq6Pz79EGa&#34;&gt;playground link&lt;/a&gt; if you want to experiment. What happens if you change &lt;code&gt;&amp;quot;hello&amp;quot;&lt;/code&gt; to just &lt;code&gt;&amp;quot;h&amp;quot;&lt;/code&gt;? &lt;a href=&#34;https://golang.org/cl/97717&#34;&gt;Explanation.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Suppose you wanted instead to re-use a single copy of the data &lt;code&gt;hello&lt;/code&gt;? That&amp;rsquo;s &lt;a href=&#34;https://en.wikipedia.org/wiki/String_interning&#34;&gt;string interning&lt;/a&gt;. There are two advantages to interned strings. The obvious one is that you don&amp;rsquo;t need to allocate and copy the data. The other is that it speeds up string equality checks. If two strings have the same length and same data pointer, they are equal; there is no need to actually examine the bytes.&lt;/p&gt;
&lt;p&gt;As of Go 1.14, Go doesn&amp;rsquo;t intern most strings. Interning, like any form of caching, also has costs: synchronization for concurrency safety, garbage collector complexity, and extra code to execute every time a string is created. And, like caching, there are cases in which it is harmful rather than helpful. If you were processing a list of dictionary words, no word would ever occur twice, so interning strings would be waste both time and memory.&lt;/p&gt;
&lt;h1 id=&#34;manual-string-interning&#34;&gt;Manual string interning&lt;/h1&gt;
&lt;p&gt;It is possible to manually intern strings in Go. What we need is a way to look for an existing string to re-use given a byte slice, perhaps using something like a &lt;code&gt;map[[]byte]string&lt;/code&gt;. If a lookup succeeds, we use the existing string; if it fails, we convert and then store that string for future use.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s only one problem: You can&amp;rsquo;t use &lt;code&gt;[]byte&lt;/code&gt; as a map key.&lt;/p&gt;
&lt;p&gt;Thanks to a &lt;a href=&#34;https://golang.org/cl/83740044&#34;&gt;long-standing compiler optimization&lt;/a&gt;, we can use a &lt;code&gt;map[string]string&lt;/code&gt; instead. The optimization is that map operations whose key is a converted byte slice don&amp;rsquo;t actually generate a new string  to use during the lookup.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []byte(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hello&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// allocates
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)] &lt;span style=&#34;color:#75715e&#34;&gt;// doesn&amp;#39;t allocate!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(A similar optimization applies in other scenarios in which the compiler can prove that a converted byte slice doesn&amp;rsquo;t get modified during use, such as &lt;a href=&#34;https://github.com/golang/go/blob/056a3d1c6f6f92b095f88b01d004eb2656a688c5/src/cmd/compile/internal/gc/swt.go#L249&#34;&gt;&lt;code&gt;switch string(b)&lt;/code&gt; when all switch cases are free of side-effects&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;The entirety of the code required to intern strings is this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;intern&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// look for an existing string to re-use
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// found an existing string
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// didn&amp;#39;t find one, so make one and store it
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; string(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pretty simple.&lt;/p&gt;
&lt;h1 id=&#34;complications&#34;&gt;Complications&lt;/h1&gt;
&lt;p&gt;Note that this manual interning routine pushes the problems with interning into the calling code. You need to manage concurrent access to the map; you need to decide the lifetime of the map (and thus everything in it); and you need to pay the extra cost of a map lookup every time you need a string.&lt;/p&gt;
&lt;p&gt;Pushing these decisions onto the calling code can yield better performance. For example, suppose you were &lt;a href=&#34;https://golang.org/issue/32779&#34;&gt;decoding json into a &lt;code&gt;map[string]interface{}&lt;/code&gt;&lt;/a&gt;. The json decoder is probably not concurrent. The lifetime of the map can be tied to the json decoder. And the keys of this map are likely to be repeated frequently, which is the best case scenario for string interning; it makes the extra cost of the map lookup worth it.&lt;/p&gt;
&lt;h1 id=&#34;a-helper-package&#34;&gt;A helper package&lt;/h1&gt;
&lt;p&gt;If you don&amp;rsquo;t want to have to think about any of these complications, and are willing to accept the slight concomitant loss of performance, and have code in which string interning may help, there&amp;rsquo;s a package for that: &lt;a href=&#34;https://github.com/josharian/intern&#34;&gt;github.com/josharian/intern&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It works by horribly abusing &lt;code&gt;sync.Pool&lt;/code&gt;. It stores interning maps in a &lt;code&gt;sync.Pool&lt;/code&gt;, retrieving them as needed. This neatly solves the concurrent access problem, because &lt;code&gt;sync.Pool&lt;/code&gt; access is concurrency-safe. It mostly solves the lifetime problem, because the contents in a &lt;code&gt;sync.Pool&lt;/code&gt; are usually &lt;a href=&#34;https://golang.org/issue/22950&#34;&gt;eventually&lt;/a&gt; garbaged collected. (For related reading about managing lifetimes, see &lt;a href=&#34;https://golang.org/issue/29696&#34;&gt;Go issue 29696&lt;/a&gt;.)&lt;/p&gt;
&lt;h1 id=&#34;more-reading&#34;&gt;More reading&lt;/h1&gt;
&lt;p&gt;There&amp;rsquo;s lots more discussion and links about string interning in Go in &lt;a href=&#34;https://golang.org/issue/5160&#34;&gt;issue 5160&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>testing.B.ReportMetric</title>
      <link>https://commaok.xyz/post/report-metric/</link>
      <pubDate>Wed, 03 Jul 2019 18:07:05 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/report-metric/</guid>
      <description>&lt;p&gt;My favorite new API in Go 1.13 is &lt;a href=&#34;https://tip.golang.org/pkg/testing/#B.ReportMetric&#34;&gt;&lt;code&gt;testing.B.ReportMetric&lt;/code&gt;&lt;/a&gt;. It allows you to report custom metrics from within your benchmarks.&lt;/p&gt;
&lt;p&gt;When the API was &lt;a href=&#34;https://github.com/golang/go/issues/26037&#34;&gt;proposed&lt;/a&gt;, the motivating example was &lt;code&gt;package sort&lt;/code&gt;. The &lt;code&gt;package sort&lt;/code&gt; benchmarks, like all benchmarks, measure elapsed wall time and (optionally) allocations. But wall time measurements can be noisy, and the sort routines don&amp;rsquo;t allocate much. There is another really useful algorithm-level metric for a sorting routine: How many comparisons does it perform?&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s use our new to API find out. Here&amp;rsquo;s a simple sort benchmark.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;demo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;sort&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// ignore big allocation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; ^ &lt;span style=&#34;color:#ae81ff&#34;&gt;0x2cc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StartTimer&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sort&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StopTimer&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(Aside: Some of the sort benchmarks in the standard library allocate inside the loop. Oops. Carefully fixing this might make a nice first contribution for someone wanting to try their hand at the Go standard library.)&lt;/p&gt;
&lt;p&gt;On my machine, executing this looks like:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -count=5
goos: darwin
goarch: amd64
pkg: github.com/commaok/blog/content/post
BenchmarkSort-8   	   19536	     60568 ns/op
BenchmarkSort-8   	   19666	     60592 ns/op
BenchmarkSort-8   	   19569	     60674 ns/op
BenchmarkSort-8   	   19724	     61363 ns/op
BenchmarkSort-8   	   19705	     60792 ns/op
PASS
ok  	github.com/commaok/blog/content/post	11.772s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If the number of iterations looks funny to you, it&amp;rsquo;s because you are used to seeing round numbers there. That also &lt;a href=&#34;https://golang.org/cl/112155/&#34;&gt;changed in Go 1.13&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s use the new &lt;code&gt;testing.B.ReportMetric&lt;/code&gt; API to report the number of comparisons. To do this, we need to count the number of comparisons. Then we&amp;rsquo;ll divide by &lt;code&gt;b.N&lt;/code&gt;. The reason we must do the division ourselves is to allow metrics that aren&amp;rsquo;t naturally represented as per-op counts, such as ratios or percentiles.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the updated code, with added lines marked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkSort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cmps&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// remove allocation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; ^ &lt;span style=&#34;color:#ae81ff&#34;&gt;0x2cc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StartTimer&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;sort&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Slice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;			&lt;span style=&#34;color:#a6e22e&#34;&gt;cmps&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;			&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;] &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StopTimer&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReportMetric&lt;/span&gt;(float64(&lt;span style=&#34;color:#a6e22e&#34;&gt;cmps&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;float64(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cmps/op&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// &amp;lt;--------
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Running this yields:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -count=5
goos: darwin
goarch: amd64
pkg: github.com/commaok/blog/content/post
BenchmarkSort-8   	   18523	     69874 ns/op	     10091 cmps/op
BenchmarkSort-8   	   18654	     64621 ns/op	     10091 cmps/op
BenchmarkSort-8   	   18657	     64589 ns/op	     10091 cmps/op
BenchmarkSort-8   	   18774	     64367 ns/op	     10091 cmps/op
BenchmarkSort-8   	   18704	     64408 ns/op	     10091 cmps/op
PASS
ok  	github.com/commaok/blog/content/post	12.062s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note that the number of comparisons is stable. This is a wonderful property when benchmarking. It means you can run your benchmarks a small number of times, without quitting your browser or trying to disable thermal scaling or worrying about how your laptop CPU may be different from your production CPUs.&lt;/p&gt;
&lt;p&gt;Now let&amp;rsquo;s reach into the standard library and tweak something! There&amp;rsquo;s a function called &lt;a href=&#34;https://golang.org/src/sort/sort.go?s=5609:5622#L223&#34;&gt;&lt;code&gt;maxDepth&lt;/code&gt; inside &lt;code&gt;package sort&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// maxDepth returns a threshold at which quicksort should switch
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// to heapsort. It returns 2*ceil(lg(n+1)).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxDepth&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;depth&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;depth&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;depth&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(Aside: maxDepth should probably use &lt;code&gt;math/bits.Len&lt;/code&gt; to calculate &lt;code&gt;ceil(lg(n+1))&lt;/code&gt;. This is another candidate for a good first contribution to the Go core.)&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s make &lt;code&gt;maxDepth&lt;/code&gt; just return 0 instead and re-run our benchmark:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -count=5 -run=NONE
goos: darwin
goarch: amd64
pkg: github.com/commaok/blog/content/post
BenchmarkSort-8   	   12618	     94792 ns/op	     17426 cmps/op
BenchmarkSort-8   	   12668	     94769 ns/op	     17426 cmps/op
BenchmarkSort-8   	   12642	     94645 ns/op	     17426 cmps/op
BenchmarkSort-8   	   12738	     94623 ns/op	     17426 cmps/op
BenchmarkSort-8   	   12654	     94431 ns/op	     17426 cmps/op
PASS
ok  	github.com/commaok/blog/content/post	12.867s
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can see that not only is it slower, but that it is clearly an algorithmic degradation: The number of comparisons has increased markedly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://godoc.org/golang.org/x/perf/benchstat&#34;&gt;benchstat&lt;/a&gt; supports custom metrics, so we can use it to tell us exactly how much:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ benchstat a b
name    old time/op   new time/op   delta
Sort-8   64.5µs ± 0%   94.7µs ± 0%  +46.76%  (p=0.016 n=4+5)

name    old cmps/op   new cmps/op  delta
Sort-8    10.1k ± 0%    17.4k ± 0%  +72.69%  (p=0.008 n=5+5)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There&amp;rsquo;s one more trick worth worth mentioning. &lt;code&gt;testing.B.ReportMetric&lt;/code&gt; generally overrides built-in metrics. If you call &lt;code&gt;b.ReportMetric(5, &amp;quot;allocs/op&amp;quot;)&lt;/code&gt;, then &lt;code&gt;go test&lt;/code&gt; will report &lt;code&gt;5 allocs/op&lt;/code&gt;, regardless of how much your benchmark actually allocated. There&amp;rsquo;s one special case: &lt;code&gt;ns/op&lt;/code&gt;. If set to &lt;code&gt;0&lt;/code&gt;, then &lt;code&gt;ns/op&lt;/code&gt; won&amp;rsquo;t be reported at all. This is useful to avoid confusion or distraction if your benchmark&amp;rsquo;s elapsed time is meaningless. For example, &lt;a href=&#34;https://golang.org/cl/166959/&#34;&gt;one of the earliest uses of &lt;code&gt;testing.B.ReportAlloc&lt;/code&gt;&lt;/a&gt; was for a &lt;code&gt;package sync&lt;/code&gt; benchmark that reported garbage collector stop-the-world time, in percentiles. It is irrelevant how long it takes that benchmark to run; only the percentiles matter.&lt;/p&gt;
&lt;p&gt;On a sad note, there&amp;rsquo;s currently &lt;a href=&#34;https://github.com/golang/go/issues/18454&#34;&gt;no good way&lt;/a&gt; to get profiling tools to tell you &lt;em&gt;where&lt;/em&gt; a particular custom metric increased.&lt;/p&gt;
&lt;p&gt;What else could you use &lt;code&gt;testing.B.ReportMetric&lt;/code&gt; for? Obvious use cases include cache hit rates, I/O amounts, fast path/slow path heuristics, percentile reporting, and algorithmic improvements. (We measured comparisons during sorting here; how about swaps?) I&amp;rsquo;m sure there will be non-obvious ones as well.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Compatibility: Not just about code</title>
      <link>https://commaok.xyz/post/compatibility/</link>
      <pubDate>Wed, 06 Feb 2019 16:05:13 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/compatibility/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://golang.org/doc/go1compat&#34;&gt;Go 1 compatibility promise&lt;/a&gt;
was designed to ensure &amp;ldquo;that Go 1 will be a firm foundation
for the development of Go and its ecosystem.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.golang.org/go2-here-we-come&#34;&gt;Go 2 is coming.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ianlancetaylor&#34;&gt;Ian Lance Taylor&lt;/a&gt; has written a
masterful, thoroughly researched
&lt;a href=&#34;https://github.com/golang/proposal/blob/master/design/28221-go2-transitions.md&#34;&gt;design document&lt;/a&gt;
about &amp;ldquo;how to make incompatible changes from Go 1 to Go 2 while breaking as little as possible&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Interestingly, both documents are clearly geared towards code and APIs.&lt;/p&gt;
&lt;p&gt;A few examples from the Go 1 compatibility promise (emphasis added):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is intended that &lt;em&gt;programs&lt;/em&gt; written to the Go 1 specification will continue to &lt;em&gt;compile and run correctly, unchanged&lt;/em&gt;, over the lifetime of that specification.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;blockquote&gt;
&lt;p&gt;Compatibility is &lt;em&gt;at the source level&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;blockquote&gt;
&lt;p&gt;Of course, for all of these possibilities, should they arise, we would endeavor whenever feasible to update the specification, compilers, or libraries &lt;em&gt;without affecting existing code&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And from the Go 2 transitions proposal (emphasis added):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A key feature of these options is that &lt;em&gt;code compiled&lt;/em&gt; at different language/library versions can in general all be linked together and work as expected.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;blockquote&gt;
&lt;p&gt;While we can provide tooling to &lt;em&gt;convert pre-1.20 code into working 1.20 code&lt;/em&gt;, we can&amp;rsquo;t force package authors to run those tools.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;!-- raw HTML omitted --&gt;
&lt;blockquote&gt;
&lt;p&gt;This can be used to take incremental steps toward new language versions, and to make it easier to &lt;em&gt;share the same code&lt;/em&gt; among different language versions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;As we all know, however, there is much more to a language&amp;rsquo;s ecosystem than the extant body of code.
There is culture. There is infrastructure, like conferences and training. There is tooling. There is trust.
There is an aesthetic. (Ian Lance Taylor&amp;rsquo;s takeaway from the history of C++: &amp;ldquo;A new version may have a very different feel while remaining backward compatible.&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;And then there is a giant, sprawling, chaotic mess of documentation,
ranging from official docs to blog posts to Stack Overflow to mailing list archives and beyond.&lt;/p&gt;
&lt;p&gt;This organic documentary hodgepodge is invaluable.
With the help of search engines, it ensures that most questions
will have multiple answers written in different ways, at different levels, by different authors.
This is a great boon, particularly to newcomers to a language.&lt;/p&gt;
&lt;p&gt;A year ago or so, I needed to write something in Swift. The single biggest pain point by far
was that when I searched for examples and discussion, I found answers written
for Swift 2, Swift 3, and Swift 4. I ended up having to simultaneously learn three dialects
of Swift and how to translate between them. This situation also commonly arises with popular libraries.&lt;/p&gt;
&lt;p&gt;My code was brand new, so I didn&amp;rsquo;t care that the language had changed in incompatible ways.
But it sure did break the documentation ecosystem in a deep way.
And docs, unlike code, are impossible to &lt;a href=&#34;https://blog.golang.org/introducing-gofix&#34;&gt;go fix&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course, docs do go stale even when there is backwards compatibility. For example, strings.Builder
made some old performance advice obsolete. But such breakage is relatively localized, easy to repair gradually,
and not particularly damaging to people who find it instead of up-to-date docs.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/golang/go/issues/20706&#34;&gt;tentatively&lt;/a&gt; &lt;a href=&#34;https://github.com/golang/go/issues/19308&#34;&gt;accepted&lt;/a&gt;
&lt;a href=&#34;https://github.com/golang/go/issues/28493&#34;&gt;Go 2&lt;/a&gt; &lt;a href=&#34;https://github.com/golang/go/issues/19113&#34;&gt;changes&lt;/a&gt;
look unlikely to break much documentation,
and the discussion so far on the &lt;a href=&#34;https://github.com/golang/go/labels/Go2&#34;&gt;many Go 2 proposals&lt;/a&gt; give no particular reason for concern.
Nevertheless, as we all ponder Go 2, it&amp;rsquo;s probably worth explicitly thinking about
compatibility in terms much broader than working code.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Benchmarking package initialization</title>
      <link>https://commaok.xyz/post/benchmark-init/</link>
      <pubDate>Thu, 31 Jan 2019 13:53:05 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/benchmark-init/</guid>
      <description>&lt;p&gt;Go program execution doesn&amp;rsquo;t start at &lt;code&gt;func main&lt;/code&gt;.
First is &lt;a href=&#34;https://github.com/golang/go/blob/9473c044f1d492a6ba49ec695042dec4365d70ca/src/runtime/asm_amd64.s#L87&#34;&gt;a bit of bootstrapping&lt;/a&gt;.
Then the &lt;a href=&#34;https://github.com/golang/go/blob/688667716ede8b133d361db0a1d47eab24ced7f7/src/runtime/proc.go#L518&#34;&gt;runtime gets initialized&lt;/a&gt;.
Then, package by package, the program initializes global variables and runs &lt;code&gt;init&lt;/code&gt; functions.
Then it&amp;rsquo;s time for &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Usually, the startup time for a Go program is negligible,
and irrelevant compared to its steady state performance.&lt;/p&gt;
&lt;p&gt;For short-lived programs, though, startup performance can matter a lot.
This is particularly true if &lt;a href=&#34;https://golang.org/issue/29382&#34;&gt;the program is a low level tool that is executed repeatedly by other programs&lt;/a&gt;.
There has also been &lt;a href=&#34;https://golang.org/issue/26775&#34;&gt;recent interest in optimizing the startup impact of the standard library&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;So: How do you benchmark and profile program initialization?&lt;/p&gt;
&lt;p&gt;If you are interested in memory allocation, &lt;a href=&#34;https://github.com/bradfitz&#34;&gt;Brad Fitzpatrick&lt;/a&gt; has &lt;a href=&#34;https://play.golang.org/p/9ervXCWzV_z&#34;&gt;a simple solution&lt;/a&gt;. This works because &lt;a href=&#34;https://commaok.xyz/post/memprofilerate/&#34;&gt;memory profiling is on by default&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But what about execution time?&lt;/p&gt;
&lt;p&gt;One obvious idea is to copy your global variables and init functions into a regular Go benchmark. This is tedious and (like most tedious things) error-prone. It also fails for a more subtle reason: The compiler generates different (slower) code for variable initialization when it occurs inside a function instead of at the top level. This is because the compiler can make fewer assumptions (although as always &lt;a href=&#34;https://golang.org/issue/29573#issuecomment-451596366&#34;&gt;there are ways to improve&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Another idea is to hack your code to return immediately from &lt;code&gt;main&lt;/code&gt; and then use &lt;a href=&#34;https://github.com/aclements/go-misc/blob/master/benchcmd/main.go&#34;&gt;&lt;code&gt;benchcmd&lt;/code&gt;&lt;/a&gt; to benchmark and &lt;a href=&#34;https://en.wikipedia.org/wiki/Perf_%28Linux%29&#34;&gt;&lt;code&gt;perf&lt;/code&gt;&lt;/a&gt; to profile. This works on Linux, although it’d be nicer to have an option that uses standard Go tooling. Also, because initialization is generally fast, you need to do a bunch of runs to gather data, and the exec and profiler tool overhead can be considerable. (I tried using macOS’s &lt;code&gt;instruments&lt;/code&gt; for profiling the &lt;code&gt;go&lt;/code&gt; tool&amp;rsquo;s startup and found that—in addition to being generally useless—it added &lt;em&gt;300x&lt;/em&gt; overhead per run!)&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Instead, let’s &lt;a href=&#34;https://golang.org/doc/go1compat&#34;&gt;void the warranty&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Here’s &lt;a href=&#34;https://github.com/golang/go/blob/faf187fb8e2ca074711ed254c72ffbaed4383c64/src/cmd/compile/internal/gc/init.go#L58&#34;&gt;how the compiler implements package initialization&lt;/a&gt;, at least as of Go 1.12. For each package, it generates code like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;initdone&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;initdone&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;initdone&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;throw&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;initdone&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// for all imported packages {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;pkg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ializers&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;.&amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;&amp;gt;() &lt;span style=&#34;color:#75715e&#34;&gt;// call user init functions, if any
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;initdone&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ializers&lt;/span&gt;() {                          (&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	{ &amp;lt;&lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;global&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;variables&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;this&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt;&amp;gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This &lt;code&gt;init&lt;/code&gt; takes the place of any &lt;code&gt;init&lt;/code&gt; functions in the package; those are renamed &lt;code&gt;init.0&lt;/code&gt;, &lt;code&gt;init.1&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;p&gt;If we could reset &lt;code&gt;initdone·&lt;/code&gt; to 0 and then call this &lt;code&gt;init&lt;/code&gt; function, then we’d be (re-)executing the exact code that gets executed during package initialization.&lt;/p&gt;
&lt;p&gt;We can do that! We&amp;rsquo;ll use &lt;a href=&#34;https://github.com/golang/go/blob/5efe9a8f11c81116f102f56c49a9415fd992c038/src/cmd/compile/doc.go#L168&#34;&gt;&lt;code&gt;//go:linkname&lt;/code&gt;&lt;/a&gt; to get access.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example, benchmarking &lt;code&gt;net/http&lt;/code&gt; package initialization:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p_test&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// must import net/http, so that net/http.init actually ends up in the executable
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;	&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;testing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;unsafe&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// must import unsafe to use go:linkname
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:linkname _initdone net/http.initdone·
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_initdone&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:linkname _init net/http.init
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkNetHTTPInit&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_initdone&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;_init&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And voila! A regular old Go benchmark that does just what we want.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Mostly. There are a few gotchas, above and beyond merely being a terrible idea.&lt;/p&gt;
&lt;p&gt;First, if you do non-idempotent work in one of your &lt;code&gt;init&lt;/code&gt; functions, things could get wonky. We did just void the warranty, after all. And I don’t know what might happen if you re-initialize package runtime or testing or something else low level while running a benchmark. Almost certainly something bad.&lt;/p&gt;
&lt;p&gt;Second, as written, this only measures the initialization of &lt;code&gt;net/http&lt;/code&gt; and &lt;em&gt;not any of its dependencies&lt;/em&gt;. This might or might not be want you want. You can work around this by using more &lt;code&gt;//go:linkname&lt;/code&gt; to reset &lt;code&gt;initdone·&lt;/code&gt; to 0 for all dependencies. Then, as you can see from the compiler pseudocode, a single call to &lt;code&gt;_init&lt;/code&gt; will re-initialize those packages as well.&lt;/p&gt;
&lt;p&gt;Third, using &lt;code&gt;//go:linkname&lt;/code&gt; requires that the symbol we are linkname-ing to must actually be in the executable. The easiest way to do this is to import the package in question. If you are working with an internal package, that means you might need to put this code somewhere with sufficient visibility for that import to work.&lt;/p&gt;
&lt;p&gt;Fourth, line number support for autogenerated code isn&amp;rsquo;t all that fabulous. If you encounter frustrating pprof output while doing this, consider &lt;a href=&#34;https://golang.org/issue/new&#34;&gt;filing bugs&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Now that you can benchmark, what do you do if you find a bottleneck you want to fix? Mostly, lazily initialize things instead, usually using &lt;a href=&#34;https://golang.org/pkg/sync/#Once&#34;&gt;&lt;code&gt;sync.Once&lt;/code&gt;&lt;/a&gt;, which is fast and hopefully &lt;a href=&#34;https://golang.org/cl/152697&#34;&gt;will be faster still in Go 1.13&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Thanks to &lt;a href=&#34;https://github.com/mvdan&#34;&gt;Daniel Martí&lt;/a&gt; for posing this question and for reading an early draft of this blog post.&lt;/p&gt;
&lt;p&gt;Daniel has also created a tool based on this blog post, &lt;a href=&#34;https://github.com/mvdan/benchinit&#34;&gt;benchinit&lt;/a&gt;, so that you can &lt;a href=&#34;https://github.com/golang/go/issues/19348#issuecomment-309446070&#34;&gt;break your programs&lt;/a&gt; this way with even less effort.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Logging, interfaces, and allocation</title>
      <link>https://commaok.xyz/post/interface-allocs/</link>
      <pubDate>Mon, 06 Feb 2017 10:52:40 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/interface-allocs/</guid>
      <description>&lt;p&gt;This post is about some new compiler optimizations scheduled for Go 1.9,
but I want to start with logging.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A couple of weeks ago, Peter Bourgon started a
&lt;a href=&#34;https://groups.google.com/forum/#!topic/golang-dev/F3l9Iz1JX4g&#34;&gt;thread on golang-dev about standardizing logging&lt;/a&gt;.
Logging is pervasive, so performance came up quickly.
The &lt;a href=&#34;https://github.com/go-kit/kit/tree/master/log&#34;&gt;go-kit log package&lt;/a&gt; uses structured logging,
centered on this interface:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Logger&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;keyvals&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sample call:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transport&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;addr&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;addr&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;listening&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that everything that goes into a logging call gets converted into an interface.
This means that it allocates a lot.&lt;/p&gt;
&lt;p&gt;Compare with another structured logger, &lt;a href=&#34;https://github.com/uber-go/zap&#34;&gt;zap&lt;/a&gt;.
Zap has uglier call sites, specifically to avoid using interfaces, in order to be zero-allocation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Failed to fetch URL.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;zap&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;zap&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Int&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;attempt&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;tryNum&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;zap&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;backoff&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;sleepFor&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The arguments to &lt;code&gt;logger.Info&lt;/code&gt; have type &lt;code&gt;logger.Field&lt;/code&gt;.
&lt;code&gt;logger.Field&lt;/code&gt; is a kind of union-ish struct
that includes a type and a field each for a &lt;code&gt;string&lt;/code&gt;, an &lt;code&gt;int&lt;/code&gt;, and an &lt;code&gt;interface{}&lt;/code&gt;.
Thus interfaces are not necessary to pass the most common kinds of values.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Enough about logging. Why does converting a concrete value to an interface sometime allocate?&lt;/p&gt;
&lt;p&gt;Interfaces are represented as two words, a type pointer and a value pointer.
Russ Cox wrote a &lt;a href=&#34;https://research.swtch.com/interfaces&#34;&gt;lovely explanation of this&lt;/a&gt;,
which I will not attempt to repeat. Just go read it.&lt;/p&gt;
&lt;p&gt;His post is slightly out of date, however.
He points out an obvious optimization: When the value is pointer-sized or smaller,
we can just put the value directly into the second interface word.
However, with the advent of concurrent garbage collection,
&lt;a href=&#34;https://golang.org/issue/8405&#34;&gt;that optimization got eliminated&lt;/a&gt;.
Now the second word in the interface is always a pointer.&lt;/p&gt;
&lt;p&gt;Consider:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before Go 1.4, this code did not allocate,
because the value &lt;code&gt;1&lt;/code&gt; could be put directly into the second interface word.&lt;/p&gt;
&lt;p&gt;That is, the compiler treated it something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;({&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;where &lt;code&gt;{typ, val}&lt;/code&gt; represents the two words in an interface.&lt;/p&gt;
&lt;p&gt;As of Go 1.4, this code started allocating, because &lt;code&gt;1&lt;/code&gt; is not a pointer,
and the second word must contain a pointer.
So instead the compiler+runtime conspired to turn it into something roughly like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// allocates!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;({&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This was painful, and there was much wringing of hands and gnashing of teeth.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/golang/go/commit/22701339817a591cd352ecd43b0439b84dbe8095&#34;&gt;first significant optimization to remove allocations&lt;/a&gt;
was added a bit later. It kicked in when the resulting interface did not escape.
In that case, the temporary value could be put on the stack instead of the heap.
Using our example code above:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// now doesn&amp;#39;t allocate, as long as e doesn&amp;#39;t escape
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{} = {&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// do things with e that don&amp;#39;t make it escape
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Unfortunately, many interfaces do escape, including those used in calls
to &lt;code&gt;fmt.Println&lt;/code&gt; and in our logging examples above.&lt;/p&gt;
&lt;p&gt;Happily, Go 1.9 will bring a few more optimizations,
in part inspired by the logging conversation.
(Unless those optimizations get reverted in the next six months,
which is always a possibility.)&lt;/p&gt;
&lt;p&gt;The first optimization is &lt;a href=&#34;https://golang.org/issue/18704&#34;&gt;to not allocate to convert a constant to an interface&lt;/a&gt;.
So &lt;code&gt;fmt.Println(1)&lt;/code&gt; will no longer allocate. The compiler puts
the value &lt;code&gt;1&lt;/code&gt; in a readonly global, roughly like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// at the top level, marked as readonly
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;({&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is possible because constants are immutable,
and will thus be the same every time the interface conversion is reached,
including recursively and concurrently.&lt;/p&gt;
&lt;p&gt;This was inspired directly by the logging discussion.
In structured logging, many of the arguments are constants&amp;ndash;
almost certainly all the keys, and probably a few of the values.
Recall the go-kit example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Log&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transport&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HTTP&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;addr&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;addr&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;listening&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This code drops from 6 allocations to 1, because five of the arguments are constant strings.&lt;/p&gt;
&lt;p&gt;The second new optimization is &lt;a href=&#34;https://golang.org/issue/17725&#34;&gt;to not allocate to convert bools and bytes to interfaces&lt;/a&gt;.
This optimization works by adding a global &lt;code&gt;[256]byte&lt;/code&gt; array called &lt;code&gt;staticbytes&lt;/code&gt; to every binary,
where &lt;code&gt;staticbytes[b] = b&lt;/code&gt; for all b.
When the compiler wants to put a bool or uint8 or other single-byte value
into an interface, instead of allocating, it calculates a pointer into this array.
That is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;staticbytes&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt; = {&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; uint8(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;({&lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;staticbytes&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is a third new optimization proposed that is still under review,
which is &lt;a href=&#34;https://golang.org/cl/36476&#34;&gt;to not allocate to convert common zero values in an interface&lt;/a&gt;.
It applies to integers, floats, strings, and slices.
This optimization works by checking at runtime whether the value is &lt;code&gt;0&lt;/code&gt; (or &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;).
If so, it uses a pointer to &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc3/src/runtime/hashmap.go#L1182&#34;&gt;an existing large chunk of zeroed memory&lt;/a&gt;
rather than allocating some memory and zeroing it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;If all goes well, Go 1.9 should eliminate a fair number of allocations during interface conversions.
But it won&amp;rsquo;t eliminate all of them, which leaves performance still on the table as the logging discussion continues.&lt;/p&gt;
&lt;p&gt;The interplay between implementation decisions and APIs is interesting.&lt;/p&gt;
&lt;p&gt;Picking an API requires thinking about the performance consequences.
It is not an accident that &lt;code&gt;io.Reader&lt;/code&gt; requires/allows callers to bring their own buffer.&lt;/p&gt;
&lt;p&gt;Performance is in no small part a consequence of the implementation decisions.
We have seen in this post that the implementation details of interfaces can substantially alter
what code allocates.&lt;/p&gt;
&lt;p&gt;And yet those very implementation decisions depend on what kind of code people write.
The compiler and runtime authors want to optimize real, common code.
For example, the &lt;a href=&#34;https://golang.org/issue/8405&#34;&gt;decision to in Go 1.4 to keep interface values at two words instead of changing them to three&lt;/a&gt;,
which made &lt;code&gt;fmt.Println(1)&lt;/code&gt; allocate, was based on looking at the kind of code people wrote.&lt;/p&gt;
&lt;p&gt;Since the kind of code people write is often shaped heavily by the APIs they use,
we have the kind of organic feedback loop that is fascinating and sometimes challenging to manage.&lt;/p&gt;
&lt;p&gt;Not a terribly deep observation, perhaps, but there is one takeaway:
If you&amp;rsquo;re designing an API and worrying about performance,
keep in mind not just what the existing compiler and runtime actually do,
but what they could do.
Write code for the present, but design APIs for the future.&lt;/p&gt;
&lt;p&gt;And if you&amp;rsquo;re not sure, ask. It worked (a bit) for logging.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Picking up pennies: Disabling memory profiling</title>
      <link>https://commaok.xyz/post/memprofilerate/</link>
      <pubDate>Sat, 28 Jan 2017 18:06:36 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/memprofilerate/</guid>
      <description>&lt;p&gt;If you work on a short-lived, allocation heavy program
and care about a tiny (maybe 0.5%) performance improvement,
this post is for you.&lt;/p&gt;
&lt;p&gt;I was looking at a CPU profile of the &lt;a href=&#34;https://golang.org/cmd/compile/&#34;&gt;Go compiler&lt;/a&gt;
when I noticed something odd: An entry in &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc3/src/runtime/mprof.go&#34;&gt;&lt;code&gt;mprof.go&lt;/code&gt;&lt;/a&gt;.
&lt;code&gt;mprof.go&lt;/code&gt; contains the memory profiling implementation, but I was doing cpu profiling.
Was there a bug in &lt;a href=&#34;https://godoc.org/rsc.io/compilebench&#34;&gt;compilebench&lt;/a&gt;, perhaps?&lt;/p&gt;
&lt;p&gt;Nope. The variable &lt;a href=&#34;https://golang.org/pkg/runtime/#pkg-variables&#34;&gt;&lt;code&gt;runtime.MemProfileRate&lt;/code&gt;&lt;/a&gt;
controls the rate at which the runtime samples allocations.
And its default value is not 0 (disabled), but &lt;code&gt;512 * 1024&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a good default.
One sample per 500k of allocations is not much overhead.
And when something goes wrong on a server, you want to be able to find out why,
rather than fussing with profiling settings and then hoping it happens again.&lt;/p&gt;
&lt;p&gt;But if you work on a short-lived program, like a compiler,
when something goes wrong, you probably don&amp;rsquo;t have any mechanism for gathering ad hoc profiles.
For any given run, you either have profiling enabled or you don&amp;rsquo;t,
and if something goes wrong, you just enable profiling and try again.&lt;/p&gt;
&lt;p&gt;And if your program is allocation-heavy, like the Go compiler,
there might be enough memory profiling samples collected to absorb some CPU time.
(As currently implemented, the first sample is particularly expensive,
as it allocates a pretty large data structure.)&lt;/p&gt;
&lt;p&gt;And I&amp;rsquo;m always looking for performance wins in the compiler, even little ones (hoping they add up).
So I sent a CL to &lt;a href=&#34;https://go-review.googlesource.com/c/35916/&#34;&gt;disable memory profiling entirely when not explicitly requested&lt;/a&gt;.
The benefits aren&amp;rsquo;t head-turning, but it&amp;rsquo;s a very cheap, low risk 0.5% to put in the bank.
It&amp;rsquo;ll get reviewed for Go 1.9.&lt;/p&gt;
&lt;p&gt;Doing this in your own program requires nothing more than setting
&lt;code&gt;runtime.MemProfileRate = 0&lt;/code&gt; when memory profiling has not been requested.
But please, think twice first.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Compile-time assertions in Go</title>
      <link>https://commaok.xyz/post/compile-time-assertions/</link>
      <pubDate>Tue, 24 Jan 2017 09:37:05 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/compile-time-assertions/</guid>
      <description>&lt;p&gt;This post is about a little-known way to make compile-time assertions in Go.
You probably shouldn&amp;rsquo;t use it, but it is interesting to know about.&lt;/p&gt;
&lt;p&gt;As a warm-up, here&amp;rsquo;s a fairly well-known form of compile-time assertions in Go: Interface satisfaction checks.&lt;/p&gt;
&lt;p&gt;In this code (&lt;a href=&#34;https://play.golang.org/p/MJ6zF1oNsX&#34;&gt;playground&lt;/a&gt;),
the &lt;code&gt;var _ =&lt;/code&gt; line ensures that type &lt;code&gt;W&lt;/code&gt; is a &lt;code&gt;stringWriter&lt;/code&gt;,
as checked for by &lt;a href=&#34;https://golang.org/pkg/io/#WriteString&#34;&gt;&lt;code&gt;io.WriteString&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;io&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)       { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringWriter&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringWriter&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;{}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#a6e22e&#34;&gt;io&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;very long string&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you comment out &lt;code&gt;W&lt;/code&gt;&amp;rsquo;s &lt;code&gt;WriteString&lt;/code&gt; method, the code will not compile:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;main.go:14: cannot use W literal (type W) as type stringWriter in assignment:
	W does not implement stringWriter (missing WriteString method)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is useful. For most types that satisfy both &lt;code&gt;io.Writer&lt;/code&gt; and &lt;code&gt;stringWriter&lt;/code&gt;,
if you eliminate the &lt;code&gt;WriteString&lt;/code&gt; method, everything will continue to work
as it did before, but with worse performance.&lt;/p&gt;
&lt;p&gt;Rather than trying to write a fragile test for a performance regression using
&lt;a href=&#34;https://golang.org/pkg/testing/#AllocsPerRun&#34;&gt;&lt;code&gt;testing.T.AllocsPerRun&lt;/code&gt;&lt;/a&gt;,
you can simply protect your code with a compile-time assertion.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc2/src/io/multi.go#L72&#34;&gt;a real world example of this technique from package io&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;OK, onward to obscurity!&lt;/p&gt;
&lt;p&gt;Interface satisfaction checks are great.
But what if you wanted to check a plain old boolean expression, like &lt;code&gt;1+1==2&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;Consider this code (&lt;a href=&#34;https://play.golang.org/p/mjIMWsWu4V&#34;&gt;playground&lt;/a&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;crypto/md5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Hash&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;Hash&lt;/span&gt;{}) &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;md5&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Size&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		panic(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hash is too small&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Hash&lt;/code&gt; is perhaps some kind of abstracted hash result.
The &lt;code&gt;init&lt;/code&gt; function ensures that it will work with &lt;a href=&#34;https://golang.org/pkg/crypto/md5/&#34;&gt;crypto/md5&lt;/a&gt;.
If you change &lt;code&gt;Hash&lt;/code&gt; to be (say) &lt;code&gt;[8]byte&lt;/code&gt;, it&amp;rsquo;ll panic when the process starts.
However, this is a run-time check.
What if we wanted it to fail earlier?&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how. (There&amp;rsquo;s no playground link, because this doesn&amp;rsquo;t work on the playground.)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;crypto/md5&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Hash&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hashIsTooSmall&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;Hash&lt;/span&gt;{}) &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;md5&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Size&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;		&lt;span style=&#34;color:#a6e22e&#34;&gt;hashIsTooSmall&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#75715e&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now if you change &lt;code&gt;Hash&lt;/code&gt; to be &lt;code&gt;[8]byte&lt;/code&gt;, it will fail during compilation.
(Actually, it fails during linking. Close enough for our purposes.)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go build .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# demo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main.hashIsTooSmall: call to external &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main.init.1: relocation target main.hashIsTooSmall not defined
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main.init.1: undefined: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;main.hashIsTooSmall&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;What&amp;rsquo;s going on here?&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hashIsTooSmall&lt;/code&gt; is &lt;a href=&#34;https://golang.org/ref/spec#Function_declarations&#34;&gt;declared without a function body&lt;/a&gt;.
The compiler assumes that someone else will provide an implementation,
perhaps an assembly routine.&lt;/p&gt;
&lt;p&gt;When the compiler can prove that &lt;code&gt;len(Hash{}) &amp;lt; md5.Size&lt;/code&gt;,
it eliminates the code inside the if statement.
As a result, no one uses the function &lt;code&gt;hashIsTooSmall&lt;/code&gt;,
so the linker eliminates it. No harm done.
As soon as the assertion fails, the code inside the if statement is preserved.
&lt;code&gt;hashIsTooSmall&lt;/code&gt; can&amp;rsquo;t be eliminated.
The linker then notices that no one else has provided an implementation
for the function and fails with an error, which was the goal.&lt;/p&gt;
&lt;p&gt;One last oddity: Why &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt;?
The go tool knows that in normal Go code, all functions must have bodies,
and instructs the compiler to enforce that.
By switching to cgo, we remove that check.
(If you run &lt;code&gt;go build -x&lt;/code&gt; on the code above, without the &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt; line,
you will see that the compiler is invoked with the &lt;code&gt;-complete&lt;/code&gt; flag.)
An alternative to adding &lt;code&gt;import &amp;quot;C&amp;quot;&lt;/code&gt; is to &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc2/src/os/signal/sig.s&#34;&gt;add an empty file called &lt;code&gt;foo.s&lt;/code&gt;
to the package&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I know of only one use of this technique,
in the &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc2/test/fixedbugs/issue9608.dir/issue9608.go&#34;&gt;compiler test suite&lt;/a&gt;.
There are other &lt;a href=&#34;https://github.com/golang/go/blob/go1.8rc2/src/runtime/hashmap.go#L261&#34;&gt;imaginable places to apply it&lt;/a&gt;,
but no one has bothered.&lt;/p&gt;
&lt;p&gt;And that&amp;rsquo;s probably how it should be. :)&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>new(Blog)</title>
      <link>https://commaok.xyz/post/new-blog/</link>
      <pubDate>Mon, 23 Jan 2017 15:19:05 -0800</pubDate>
      
      <guid>https://commaok.xyz/post/new-blog/</guid>
      <description>&lt;p&gt;I&amp;rsquo;m going to try this blogging thing again.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve failed at it a few times before.
I&amp;rsquo;m going to try &lt;a href=&#34;https://jvns.ca/blog/2016/05/22/how-do-you-write-blog-posts/&#34;&gt;Julia Evans&lt;/a&gt; style this time.
Maybe this one will stick?&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
