<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://nicolast.be/feed.xml" rel="self" type="application/atom+xml" /><link href="https://nicolast.be/" rel="alternate" type="text/html" /><updated>2024-12-07T16:29:40+01:00</updated><id>https://nicolast.be/feed.xml</id><title type="html">nicolast.be</title><subtitle>My blog.</subtitle><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><entry><title type="html">`concurrency` and Performance</title><link href="https://nicolast.be/development/concurrency-and-performance/" rel="alternate" type="text/html" title="`concurrency` and Performance" /><published>2023-04-14T19:54:00+02:00</published><updated>2023-04-14T19:54:00+02:00</updated><id>https://nicolast.be/development/concurrency-and-performance</id><content type="html" xml:base="https://nicolast.be/development/concurrency-and-performance/"><![CDATA[<p>When using <a href="https://hackage.haskell.org/package/dejafu">DejaFu</a> to test concurrent code,
as introduced in <a href="/development/testing-concurrent-code-using-dejafu/">a previous post</a>,
the <a href="https://hackage.haskell.org/package/concurrency-1.11.0.2/docs/Control-Monad-Conc-Class.html#t:MonadConc"><code class="language-plaintext highlighter-rouge">MonadConc</code></a>
and <a href="https://hackage.haskell.org/package/concurrency-1.11.0.2/docs/Control-Monad-STM-Class.html#t:MonadSTM"><code class="language-plaintext highlighter-rouge">MonadSTM</code></a>
type classes must be used to abstract over
the implementation of concurrency and STM. In <em>regular</em> code, the types and functions in the
standard <code class="language-plaintext highlighter-rouge">IO</code> and <code class="language-plaintext highlighter-rouge">STM</code> monads would be used instead. Luckily, there’s an <code class="language-plaintext highlighter-rouge">instance MonadConc IO</code>
and an <code class="language-plaintext highlighter-rouge">instance MonadSTM STM</code>, so code using the <a href="https://hackage.haskell.org/package/concurrency-1.11.0.2"><code class="language-plaintext highlighter-rouge">concurrency</code></a>
abstractions will work
just fine in <code class="language-plaintext highlighter-rouge">IO</code> or <code class="language-plaintext highlighter-rouge">STM</code>, but going through a type class can have a performance impact due to
a dictionary lookup that comes with it. This was one of the questions raised in the
<a href="/development/testing-concurrent-code-using-dejafu/#future-work">Future Work</a> section
of last week’s article.</p>

<p>In the implementation of <code class="language-plaintext highlighter-rouge">MonadConc</code> for <code class="language-plaintext highlighter-rouge">IO</code>, as well as the implementation of <code class="language-plaintext highlighter-rouge">MonadSTM</code> for
<code class="language-plaintext highlighter-rouge">STM</code>, most if not all functions map directly to their <code class="language-plaintext highlighter-rouge">IO</code> and <code class="language-plaintext highlighter-rouge">STM</code> counterparts from <code class="language-plaintext highlighter-rouge">base</code>
and <code class="language-plaintext highlighter-rouge">stm</code>. Hence, if we can convince the compiler to emit code not using the type class dictionary
when using testable functions (i.e., functions using <code class="language-plaintext highlighter-rouge">MonadConc</code> and <code class="language-plaintext highlighter-rouge">MonadSTM</code>) in environments
where <em>testability</em> is not needed (i.e., when used in <code class="language-plaintext highlighter-rouge">IO</code> and <code class="language-plaintext highlighter-rouge">STM</code>), there should be no
performance impact.</p>

<p>Since this is a Literate Haskell file, some boilerplate before we continue
(see <a href="/various/jekyll-literate-haskell/">this article</a> for more
information on how this works):</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{- cabal:
build-depends:
  , base ^&gt;=4.17
  , concurrency ^&gt;=1.11.0.2
  , stm ^&gt;=2.5.1.0
  , tasty ^&gt;=1.4.3
  , tasty-bench ^&gt;=0.3.3
  , tasty-inspection-testing ^&gt;=0.2
default-language: Haskell2010
build-tool-depends: markdown-unlit:markdown-unlit
ghc-options:
  -pgmL markdown-unlit
  -rtsopts=all "-with-rtsopts=-T -A32m"
  -fproc-alignment=64
  -ddump-simpl
  -dsuppress-idinfo
  -dsuppress-coercions
  -dsuppress-type-applications
  -dsuppress-uniques
  -dsuppress-module-prefixes
-}</span>

<span class="cp">{-# LANGUAGE TemplateHaskell #-}</span>

<span class="kr">module</span> <span class="nn">Main</span> <span class="p">(</span>
  <span class="nf">main</span><span class="p">,</span>
  <span class="nf">benchSTM</span><span class="p">,</span>
  <span class="nf">benchConcurrencyNoInline</span><span class="p">,</span>
  <span class="nf">benchConcurrency</span><span class="p">,</span>
  <span class="nf">benchConcurrencySpecialized</span>
  <span class="p">)</span> <span class="kr">where</span>

<span class="kr">import</span> <span class="k">qualified</span> <span class="nn">Control.Concurrent.STM</span> <span class="k">as</span> <span class="n">STM</span>
<span class="kr">import</span> <span class="k">qualified</span> <span class="nn">Control.Concurrent.Classy.STM</span> <span class="k">as</span> <span class="n">C</span>
<span class="kr">import</span> <span class="k">qualified</span> <span class="nn">Control.Monad.Conc.Class</span> <span class="k">as</span> <span class="n">C</span>
<span class="kr">import</span> <span class="nn">Test.Tasty</span> <span class="p">(</span><span class="kt">TestTree</span><span class="p">,</span> <span class="nf">testGroup</span><span class="p">,</span> <span class="nf">withResource</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Test.Tasty.Bench</span> <span class="p">(</span><span class="kt">Benchmark</span><span class="p">,</span> <span class="nf">bench</span><span class="p">,</span> <span class="nf">bcompare</span><span class="p">,</span> <span class="nf">bgroup</span><span class="p">,</span> <span class="nf">defaultMain</span><span class="p">,</span> <span class="nf">nfIO</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Test.Tasty.Inspection</span> <span class="p">(</span><span class="nf">inspectTest</span><span class="p">,</span> <span class="nf">hasNoTypeClasses</span><span class="p">,</span> <span class="p">(</span><span class="o">==-</span><span class="p">))</span>
</code></pre></div></div>

<h2 id="benchmark-baseline">Benchmark Baseline</h2>

<p>To start, let’s measure the baseline performance of a very simple STM transaction which takes three
<code class="language-plaintext highlighter-rouge">TVar Int</code>s, reads the contents of the first two, puts their sum in the third, then reads the
third and returns the value:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">benchSTM</span> <span class="o">::</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">STM</span> <span class="kt">Int</span>
<span class="n">benchSTM</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v1'</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v1</span>
  <span class="n">v2'</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v2</span>
  <span class="kt">STM</span><span class="o">.</span><span class="n">writeTVar</span> <span class="n">v3</span> <span class="o">$!</span> <span class="n">v1'</span> <span class="o">+</span> <span class="n">v2'</span>
  <span class="kt">STM</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v3</span>

<span class="n">benchConcurrencyNoInline</span> <span class="o">::</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="n">stm</span> <span class="kt">Int</span>
<span class="n">benchConcurrencyNoInline</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v1'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v1</span>
  <span class="n">v2'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v2</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">writeTVar</span> <span class="n">v3</span> <span class="o">$!</span> <span class="n">v1'</span> <span class="o">+</span> <span class="n">v2'</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v3</span>
<span class="cp">{-# NOINLINE benchConcurrencyNoInline #-}</span>

<span class="n">withVars</span><span class="o">::</span> <span class="p">(</span><span class="kt">IO</span> <span class="p">(</span><span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span><span class="p">,</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span><span class="p">,</span> <span class="kt">STM</span><span class="o">.</span><span class="kt">TVar</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">TestTree</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">TestTree</span>
<span class="n">withVars</span> <span class="o">=</span> <span class="n">withResource</span> <span class="n">mkTVars</span> <span class="p">(</span><span class="n">const</span> <span class="o">$</span> <span class="n">pure</span> <span class="nb">()</span><span class="p">)</span>
  <span class="kr">where</span>
    <span class="n">mkTVars</span> <span class="o">=</span> <span class="p">(,,)</span> <span class="o">&lt;$&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="n">newTVarIO</span> <span class="mi">1</span>
                   <span class="o">&lt;*&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="n">newTVarIO</span> <span class="mi">2</span>
                   <span class="o">&lt;*&gt;</span> <span class="kt">STM</span><span class="o">.</span><span class="n">newTVarIO</span> <span class="mi">0</span>

<span class="n">benchSTMvsBenchConcurrencyNoInline</span> <span class="o">::</span> <span class="kt">Benchmark</span>
<span class="n">benchSTMvsBenchConcurrencyNoInline</span> <span class="o">=</span> <span class="n">withVars</span> <span class="o">$</span> <span class="nf">\</span><span class="n">getVars</span> <span class="o">-&gt;</span> <span class="n">testGroup</span> <span class="s">"baseline"</span> <span class="p">[</span>
    <span class="n">bench</span> <span class="s">"STM"</span> <span class="o">$</span> <span class="n">nfIO</span> <span class="o">$</span> <span class="n">getVars</span> <span class="o">&gt;&gt;=</span> <span class="nf">\</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">,</span> <span class="n">v3</span><span class="p">)</span> <span class="o">-&gt;</span>
      <span class="kt">STM</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchSTM</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span><span class="p">,</span>
    <span class="n">bcompare</span> <span class="s">"STM"</span> <span class="o">$</span>
      <span class="n">bench</span> <span class="s">"ConcurrencyNoInline"</span> <span class="o">$</span> <span class="n">nfIO</span> <span class="o">$</span> <span class="n">getVars</span> <span class="o">&gt;&gt;=</span> <span class="nf">\</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">,</span> <span class="n">v3</span><span class="p">)</span> <span class="o">-&gt;</span>
        <span class="kt">C</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchConcurrencyNoInline</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span>
  <span class="p">]</span>
</code></pre></div></div>

<p>Running this benchmark yields not-so-stellar results:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  baseline
    STM:                 OK (0.40s)
      45.4 ns ± 4.2 ns,  63 B  allocated,   0 B  copied,  34 MB peak memory
    ConcurrencyNoInline: OK (0.27s)
      126  ns ± 5.5 ns, 505 B  allocated,   0 B  copied,  34 MB peak memory, 2.78x
</code></pre></div></div>

<h2 id="automatic-specialization">Automatic Specialization</h2>

<p>The <code class="language-plaintext highlighter-rouge">NOINLINE</code> pragma on <code class="language-plaintext highlighter-rouge">benchConcurrencyNoInline</code> prohibits GHC to inline the
code (in the benchmark), otherwise specialization could trigger.</p>

<p>If we create a version of the code without the <code class="language-plaintext highlighter-rouge">INLINE</code> pragma and benchmark it again,
it appears the code performs roughly the same as the native <code class="language-plaintext highlighter-rouge">STM</code> version:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">benchConcurrency</span> <span class="o">::</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="n">stm</span> <span class="kt">Int</span>
<span class="n">benchConcurrency</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v1'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v1</span>
  <span class="n">v2'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v2</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">writeTVar</span> <span class="n">v3</span> <span class="o">$!</span> <span class="n">v1'</span> <span class="o">+</span> <span class="n">v2'</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v3</span>

<span class="n">benchSTMvsBenchConcurrency</span> <span class="o">::</span> <span class="kt">Benchmark</span>
<span class="n">benchSTMvsBenchConcurrency</span> <span class="o">=</span> <span class="n">withVars</span> <span class="o">$</span> <span class="nf">\</span><span class="n">getVars</span> <span class="o">-&gt;</span> <span class="n">testGroup</span> <span class="s">"plain"</span> <span class="p">[</span>
    <span class="n">bcompare</span> <span class="s">"STM"</span> <span class="o">$</span>
      <span class="n">bench</span> <span class="s">"Concurrency"</span> <span class="o">$</span> <span class="n">nfIO</span> <span class="o">$</span> <span class="n">getVars</span> <span class="o">&gt;&gt;=</span> <span class="nf">\</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">,</span> <span class="n">v3</span><span class="p">)</span> <span class="o">-&gt;</span>
        <span class="kt">C</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchConcurrency</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span>
  <span class="p">]</span>
</code></pre></div></div>

<p>yields</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  plain
    Concurrency:         OK (0.39s)
      45.8 ns ± 3.4 ns,  63 B  allocated,   0 B  copied,  35 MB peak memory, 1.01x
</code></pre></div></div>

<p>Why does this happen, and can we be certain this is not a fluke?</p>

<h2 id="inspecting-core">Inspecting Core</h2>
<p>To investigate, we can pass some options to GHC so it prints the <em>Core</em> it generates. <em>Core</em> is a
language somewhat like a very simplified version of Haskell, without type classes (which are
desugared into dictionaries at this point), that can then be compiled into even more low-level
languages before binary code is generated. Here are the important bits:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>benchSTM1
  :: TVar Int
     -&gt; TVar Int
     -&gt; TVar Int
     -&gt; State# RealWorld
     -&gt; (# State# RealWorld, Int #)
benchSTM1
  = \ (v1 :: TVar Int)
      (v2 :: TVar Int)
      (v3 :: TVar Int)
      (s :: State# RealWorld) -&gt;
      case v1 of { TVar tvar# -&gt;
      case readTVar# tvar# s of { (# ipv, ipv1 #) -&gt;
      case v2 of { TVar tvar#1 -&gt;
      case readTVar# tvar#1 ipv of { (# ipv2, ipv3 #) -&gt;
      case ipv1 of { I# x -&gt;
      case ipv3 of { I# y -&gt;
      case v3 of { TVar tvar#2 -&gt;
      case writeTVar# tvar#2 (I# (+# x y)) ipv2 of s2# { __DEFAULT -&gt;
      readTVar# tvar#2 s2#
      }
      }
      }
      }
      }
      }
      }
      }

benchSTM :: TVar Int -&gt; TVar Int -&gt; TVar Int -&gt; STM Int
benchSTM
  = benchSTM1
    `cast` &lt;Co:15&gt; :: (TVar Int
                       -&gt; TVar Int
                       -&gt; TVar Int
                       -&gt; State# RealWorld
                       -&gt; (# State# RealWorld, Int #))
                      ~R# (TVar Int -&gt; TVar Int -&gt; TVar Int -&gt; STM Int)
</code></pre></div></div>

<p>With a bit of imagination, we can see <code class="language-plaintext highlighter-rouge">benchSTM1</code> resembles our original <code class="language-plaintext highlighter-rouge">benchSTM</code> code,
in a state monad over <code class="language-plaintext highlighter-rouge">State# RealWorld</code>. Keep in mind <code class="language-plaintext highlighter-rouge">TVar</code> is a
<code class="language-plaintext highlighter-rouge">newtype</code> constructor over the compiler-internal representation of a <code class="language-plaintext highlighter-rouge">TVar</code> (which is
<code class="language-plaintext highlighter-rouge">TVar# RealWorld a</code>), and <code class="language-plaintext highlighter-rouge">readTVar#</code> and friends are alike <code class="language-plaintext highlighter-rouge">readTVar</code>, but for the
internal <code class="language-plaintext highlighter-rouge">TVar#</code> type.</p>

<p><code class="language-plaintext highlighter-rouge">benchSTM</code> is <code class="language-plaintext highlighter-rouge">benchSTM1</code> <code class="language-plaintext highlighter-rouge">cast</code>ed to plain <code class="language-plaintext highlighter-rouge">STM</code> (which is, like <code class="language-plaintext highlighter-rouge">IO</code>, a <code class="language-plaintext highlighter-rouge">newtype</code> of
<code class="language-plaintext highlighter-rouge">State# RealWorld -&gt; (# State# RealWorld, a #)</code>).</p>

<p>Here’s <code class="language-plaintext highlighter-rouge">benchConcurrencyNoInline</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>benchConcurrencyNoInline
  :: forall (stm :: * -&gt; *).
     MonadSTM stm =&gt;
     TVar stm Int -&gt; TVar stm Int -&gt; TVar stm Int -&gt; stm Int
benchConcurrencyNoInline
  = \ (@(stm :: * -&gt; *)) ($dMonadSTM :: MonadSTM stm) -&gt;
      let {
        $dMonad :: MonadPlus stm
        $dMonad = $p2MonadSTM $dMonadSTM } in
      let {
        $dMonad1 :: Monad stm
        $dMonad1 = $p2MonadPlus $dMonad } in
      \ (v1 :: TVar stm Int) (v2 :: TVar stm Int) (v3 :: TVar stm Int) -&gt;
        let {
          lvl15 :: stm Int
          lvl15 = readTVar $dMonadSTM v2 } in
        let {
          lvl16 :: stm Int
          lvl16 = readTVar $dMonadSTM v3 } in
        &gt;&gt;=
          $dMonad1
          (readTVar $dMonadSTM v1)
          (\ (v1' :: Int) -&gt;
             &gt;&gt;=
               $dMonad1
               lvl15
               (\ (v2' :: Int) -&gt;
                  &gt;&gt;
                    $dMonad1
                    (case v1' of { I# x -&gt;
                     case v2' of { I# y -&gt; writeTVar $dMonadSTM v3 (I# (+# x y)) }
                     })
                    lvl16))
</code></pre></div></div>

<p>Here, the <code class="language-plaintext highlighter-rouge">MonadSTM</code> dictionary is passed along (and then unpacked to retrieve the <code class="language-plaintext highlighter-rouge">MonadPlus</code>
and <code class="language-plaintext highlighter-rouge">Monad</code> instances as well), and every call to, e.g., <code class="language-plaintext highlighter-rouge">readTVar</code> becomes a field lookup
from the dictionary (<code class="language-plaintext highlighter-rouge">readTVar $dMonadSTM</code> is like a regular field lookup in a <code class="language-plaintext highlighter-rouge">data</code> record),
hence an indirect call. Also, the monadic binds (<code class="language-plaintext highlighter-rouge">&gt;&gt;=</code> and <code class="language-plaintext highlighter-rouge">&gt;&gt;</code>) can’t be expanded as is the
case in <code class="language-plaintext highlighter-rouge">benchSTM</code>. It seems pretty clear why <code class="language-plaintext highlighter-rouge">benchConcurrencyNoInline</code> performs about 2.78x
slower than <code class="language-plaintext highlighter-rouge">benchSTM</code>!</p>

<p>Last but not least, the code GHC generates for <code class="language-plaintext highlighter-rouge">benchConcurrency</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>benchConcurrency
  :: forall (stm :: * -&gt; *).
     MonadSTM stm =&gt;
     TVar stm Int -&gt; TVar stm Int -&gt; TVar stm Int -&gt; stm Int
benchConcurrency
  = \ (@(stm :: * -&gt; *)) ($dMonadSTM :: MonadSTM stm) -&gt;
      let {
        $dMonad :: MonadPlus stm
        $dMonad = $p2MonadSTM $dMonadSTM } in
      let {
        $dMonad1 :: Monad stm
        $dMonad1 = $p2MonadPlus $dMonad } in
      \ (v1 :: TVar stm Int) (v2 :: TVar stm Int) (v3 :: TVar stm Int) -&gt;
        let {
          lvl15 :: stm Int
          lvl15 = readTVar $dMonadSTM v2 } in
        let {
          lvl16 :: stm Int
          lvl16 = readTVar $dMonadSTM v3 } in
        &gt;&gt;=
          $dMonad1
          (readTVar $dMonadSTM v1)
          (\ (v1' :: Int) -&gt;
             &gt;&gt;=
               $dMonad1
               lvl15
               (\ (v2' :: Int) -&gt;
                  &gt;&gt;
                    $dMonad1
                    (case v1' of { I# x -&gt;
                     case v2' of { I# y -&gt; writeTVar $dMonadSTM v3 (I# (+# x y)) }
                     })
                    lvl16))
</code></pre></div></div>

<p>This looks… suspiciously similar to the <code class="language-plaintext highlighter-rouge">benchConcurrencyNoInline</code> code. But when running
the benchmark, the performance of the regular version was aligned with the <code class="language-plaintext highlighter-rouge">benchSTM</code> code.
What’s going on?</p>

<p>It turns out GHC spotted an opportunity for specialization, and performed the following two
steps:</p>

<ul>
  <li>It created a specialized version of the function:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>benchConcurrency1
  :: TVar STM Int
     -&gt; TVar STM Int
     -&gt; TVar STM Int
     -&gt; State# RealWorld
     -&gt; (# State# RealWorld, Int #)
benchConcurrency1
  = \ (v1 :: TVar STM Int)
      (v2 :: TVar STM Int)
      (v3 :: TVar STM Int)
      (eta :: State# RealWorld) -&gt;
      case v1 `cast` &lt;Co:3&gt; :: TVar STM Int ~R# TVar Int of
      { TVar tvar# -&gt;
      case readTVar# tvar# eta of { (# ipv, ipv1 #) -&gt;
      case v2 `cast` &lt;Co:3&gt; :: TVar STM Int ~R# TVar Int of
      { TVar tvar#1 -&gt;
      case readTVar# tvar#1 ipv of { (# ipv2, ipv3 #) -&gt;
      case ipv1 of { I# x -&gt;
      case ipv3 of { I# y -&gt;
      case v3 `cast` &lt;Co:3&gt; :: TVar STM Int ~R# TVar Int of
      { TVar tvar#2 -&gt;
      case writeTVar# tvar#2 (I# (+# x y)) ipv2 of s2# { __DEFAULT -&gt;
      readTVar# tvar#2 s2#
      }
      }
      }
      }
      }
      }
      }
      }
</code></pre></div></div>

<p>Note this is, modulo some different but related <code class="language-plaintext highlighter-rouge">cast</code> invocations (which have no runtime impact)
the very same as <code class="language-plaintext highlighter-rouge">benchSTM1</code>. Indeed, this is a specialized version of <code class="language-plaintext highlighter-rouge">benchConcurrency</code> for
<code class="language-plaintext highlighter-rouge">TVar STM Int -&gt; TVar STM Int -&gt; TVar STM Int -&gt; STM Int</code>, i.e., when using <code class="language-plaintext highlighter-rouge">benchConcurrency</code>
in the regular <code class="language-plaintext highlighter-rouge">STM</code> monad.</p>

<ul>
  <li>It created a rule to rewrite calls to <code class="language-plaintext highlighter-rouge">benchConcurrency</code>, when used in the <code class="language-plaintext highlighter-rouge">STM</code> monad, to
<code class="language-plaintext highlighter-rouge">benchConcurrency1</code>:</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"SPEC benchConcurrency @STM"
    forall ($dMonadSTM :: MonadSTM STM).
      benchConcurrency $dMonadSTM
      = benchConcurrency1
        `cast` &lt;Co:18&gt; :: (TVar STM Int
                           -&gt; TVar STM Int
                           -&gt; TVar STM Int
                           -&gt; State# RealWorld
                           -&gt; (# State# RealWorld, Int #))
                          ~R# (TVar STM Int -&gt; TVar STM Int -&gt; TVar STM Int -&gt; STM Int)
</code></pre></div></div>

<p>Note the <code class="language-plaintext highlighter-rouge">$dMonadSTM</code> dictionary isn’t used on the right hand side of the rewrite rule,
so we can be certain no indirections through the <code class="language-plaintext highlighter-rouge">MonadSTM</code> dictionary can be used in
<code class="language-plaintext highlighter-rouge">benchConcurrency1</code>.</p>

<p>When inspecting the actual benchmark code, we can see a call to <code class="language-plaintext highlighter-rouge">benchConcurrency1</code> is
used instead of a call to <code class="language-plaintext highlighter-rouge">benchConcurrency</code>, and hence, we get the very same performance as the
<code class="language-plaintext highlighter-rouge">benchSTM</code> version:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{ (# ipv, ipv1 #) -&gt;
case ipv1 of { (v1, v2, v3) -&gt;
case atomically#
       (benchConcurrency1
          (v1 `cast` &lt;Co:4&gt; :: TVar Int ~R# TVar STM Int)
          (v2 `cast` &lt;Co:4&gt; :: TVar Int ~R# TVar STM Int)
          (v3 `cast` &lt;Co:4&gt; :: TVar Int ~R# TVar STM Int))
       ipv
</code></pre></div></div>

<h2 id="explicit-specialization">Explicit Specialization</h2>

<p>Great, GHC is able to specialize <code class="language-plaintext highlighter-rouge">MonadSTM</code> code to the equivalent <code class="language-plaintext highlighter-rouge">STM</code> code when it
spots an opportunity to do so. However, this only works within a single module: if <code class="language-plaintext highlighter-rouge">benchConcurrency</code> were
defined in one module, and used from another to benchmark it, the implementation of
<code class="language-plaintext highlighter-rouge">benchConcurrency</code> is no longer visible to GHC, except if it decided the function is small enough
to be inlineable, or we told it (with the <code class="language-plaintext highlighter-rouge">INLINE</code> pragma) to do so. Many <code class="language-plaintext highlighter-rouge">STM</code> functions are
relatively large though, so we don’t necessarily want to inline them. What to do?</p>

<p>As a library author, we can force GHC to create specialized versions of some code for us, and
generate the according rewrite rule as well, as if it decided to do so by itself within a single
module. Let’s give this a try:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">benchConcurrencySpecialized</span> <span class="o">::</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="kt">C</span><span class="o">.</span><span class="kt">TVar</span> <span class="n">stm</span> <span class="kt">Int</span> <span class="o">-&gt;</span>
  <span class="n">stm</span> <span class="kt">Int</span>
<span class="n">benchConcurrencySpecialized</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v1'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v1</span>
  <span class="n">v2'</span> <span class="o">&lt;-</span> <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v2</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">writeTVar</span> <span class="n">v3</span> <span class="o">$!</span> <span class="n">v1'</span> <span class="o">+</span> <span class="n">v2'</span>
  <span class="kt">C</span><span class="o">.</span><span class="n">readTVar</span> <span class="n">v3</span>
<span class="cp">{-# SPECIALIZE benchConcurrencySpecialized ::
      STM.TVar Int -&gt; STM.TVar Int -&gt; STM.TVar Int -&gt; STM.STM Int #-}</span>

<span class="n">benchSTMvsBenchConcurrencySpecialized</span> <span class="o">::</span> <span class="kt">Benchmark</span>
<span class="n">benchSTMvsBenchConcurrencySpecialized</span> <span class="o">=</span> <span class="n">withVars</span> <span class="o">$</span> <span class="nf">\</span><span class="n">getVars</span> <span class="o">-&gt;</span> <span class="n">testGroup</span> <span class="s">"specialized"</span> <span class="p">[</span>
    <span class="n">bcompare</span> <span class="s">"STM"</span> <span class="o">$</span>
      <span class="n">bench</span> <span class="s">"ConcurrencySpecialized"</span> <span class="o">$</span> <span class="n">nfIO</span> <span class="o">$</span> <span class="n">getVars</span> <span class="o">&gt;&gt;=</span> <span class="nf">\</span><span class="p">(</span><span class="n">v1</span><span class="p">,</span> <span class="n">v2</span><span class="p">,</span> <span class="n">v3</span><span class="p">)</span> <span class="o">-&gt;</span>
        <span class="kt">C</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchConcurrencySpecialized</span> <span class="n">v1</span> <span class="n">v2</span> <span class="n">v3</span>
  <span class="p">]</span>
</code></pre></div></div>

<p>Note the use of the <code class="language-plaintext highlighter-rouge">SPECIALIZE</code> pragma above. Running this gives</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  specialized
    ConcurrencySpecialized: OK (0.20s)
      47.9 ns ± 4.4 ns,  63 B  allocated,   0 B  copied,  35 MB peak memory, 1.03x
</code></pre></div></div>

<p>Furthermore, the following <em>Core</em> is generated:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>benchConcurrencySpecialized
  :: forall (stm :: * -&gt; *).
     MonadSTM stm =&gt;
     TVar stm Int -&gt; TVar stm Int -&gt; TVar stm Int -&gt; stm Int
benchConcurrencySpecialized
  = \ (@(stm :: * -&gt; *)) ($dMonadSTM :: MonadSTM stm) -&gt;
      let {
        $dMonad :: MonadPlus stm
        $dMonad = $p2MonadSTM $dMonadSTM } in
      let {
        $dMonad1 :: Monad stm
        $dMonad1 = $p2MonadPlus $dMonad } in
      \ (v1 :: TVar stm Int) (v2 :: TVar stm Int) (v3 :: TVar stm Int) -&gt;
        let {
          lvl19 :: stm Int
          lvl19 = readTVar $dMonadSTM v2 } in
        let {
          lvl20 :: stm Int
          lvl20 = readTVar $dMonadSTM v3 } in
        &gt;&gt;=
          $dMonad1
          (readTVar $dMonadSTM v1)
          (\ (v1' :: Int) -&gt;
             &gt;&gt;=
               $dMonad1
               lvl19
               (\ (v2' :: Int) -&gt;
                  &gt;&gt;
                    $dMonad1
                    (case v1' of { I# x -&gt;
                     case v2' of { I# y -&gt; writeTVar $dMonadSTM v3 (I# (+# x y)) }
                     })
                    lvl20))

"SPEC benchConcurrencySpecialized"
    forall ($dMonadSTM :: MonadSTM STM).
      benchConcurrencySpecialized $dMonadSTM
      = benchConcurrency1
        `cast` &lt;Co:18&gt; :: (TVar STM Int
                           -&gt; TVar STM Int
                           -&gt; TVar STM Int
                           -&gt; State# RealWorld
                           -&gt; (# State# RealWorld, Int #))
                          ~R# (TVar STM Int -&gt; TVar STM Int -&gt; TVar STM Int -&gt; STM Int)
</code></pre></div></div>

<p>The compiler detected the specialized version of <code class="language-plaintext highlighter-rouge">benchConcurrencySpecialized</code> for <code class="language-plaintext highlighter-rouge">STM</code>
is the very same as the specialized version it already created for <code class="language-plaintext highlighter-rouge">benchConcurrency</code>, so
<code class="language-plaintext highlighter-rouge">benchConcurrency1</code> gets simply reused.</p>

<p>With the <code class="language-plaintext highlighter-rouge">SPECIALIZE</code> pragma in place, we can write and test code using <code class="language-plaintext highlighter-rouge">MonadSTM</code>, whilst
at the same time guaranteeing that users of the library using plain <code class="language-plaintext highlighter-rouge">STM</code> code won’t incur
any performance hit.</p>

<h2 id="testing">Testing</h2>

<p>We can even go one step further, and ensure <code class="language-plaintext highlighter-rouge">MonadSTM</code> usage is completely erased: in a test
using the <a href="https://hackage.haskell.org/package/inspection-testing-0.5.0.1"><code class="language-plaintext highlighter-rouge">inspection-testing</code></a>
library. Even more, we can check whether two versions of a
function using our library function are (after inlining) the same:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">stmVersion</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">stmVersion</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">newTVarIO</span> <span class="mi">0</span>
  <span class="kr">_</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchSTM</span> <span class="n">v</span> <span class="n">v</span> <span class="n">v</span>
  <span class="n">pure</span> <span class="nb">()</span>

<span class="n">concurrencyVersion</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">concurrencyVersion</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">v</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">newTVarIO</span> <span class="mi">0</span>
  <span class="kr">_</span> <span class="o">&lt;-</span> <span class="kt">STM</span><span class="o">.</span><span class="n">atomically</span> <span class="o">$</span> <span class="n">benchConcurrencySpecialized</span> <span class="n">v</span> <span class="n">v</span> <span class="n">v</span>
  <span class="n">pure</span> <span class="nb">()</span>

<span class="n">testMonadSTMErased</span> <span class="o">::</span> <span class="kt">TestTree</span>
<span class="n">testMonadSTMErased</span> <span class="o">=</span> <span class="o">$</span><span class="p">(</span><span class="n">inspectTest</span> <span class="o">$</span> <span class="n">hasNoTypeClasses</span> <span class="n">'concurrencyVersion</span><span class="p">)</span>

<span class="n">testFunctionsEqual</span> <span class="o">::</span> <span class="kt">TestTree</span>
<span class="n">testFunctionsEqual</span> <span class="o">=</span> <span class="o">$</span><span class="p">(</span><span class="n">inspectTest</span> <span class="o">$</span> <span class="n">'concurrencyVersion</span> <span class="o">==-</span> <span class="n">'stmVersion</span><span class="p">)</span>
</code></pre></div></div>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  concurrencyVersion does not contain dictionary values: OK
  concurrencyVersion ==- stmVersion:                     OK
</code></pre></div></div>

<p>Success!</p>

<h2 id="conclusion">Conclusion</h2>

<p>This article showns how, with liberal use of <code class="language-plaintext highlighter-rouge">SPECIALIZE</code> pragmas in library code,
it’s possible to eliminate the overhead of <code class="language-plaintext highlighter-rouge">MonadConc</code> and <code class="language-plaintext highlighter-rouge">MonadSTM</code> when library functions
are used in the regular <code class="language-plaintext highlighter-rouge">IO</code> and <code class="language-plaintext highlighter-rouge">STM</code> monads. Hence, let this be a call to library authors
to write their code using <code class="language-plaintext highlighter-rouge">MonadConc</code> and <code class="language-plaintext highlighter-rouge">MonadSTM</code> such that consumers of the library
can still write DejaFu tests for code using data structures and functions defined in it!</p>

<h3 id="wrapping-up">Wrapping Up</h3>

<p>To wrap up, run all benchmarks and tests:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">main</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">main</span> <span class="o">=</span> <span class="n">defaultMain</span> <span class="p">[</span>
  <span class="n">benchSTMvsBenchConcurrencyNoInline</span><span class="p">,</span>
  <span class="n">benchSTMvsBenchConcurrency</span><span class="p">,</span>
  <span class="n">benchSTMvsBenchConcurrencySpecialized</span><span class="p">,</span>
  <span class="n">testMonadSTMErased</span><span class="p">,</span>
  <span class="n">testFunctionsEqual</span>
  <span class="p">]</span>
</code></pre></div></div>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Development" /><summary type="html"><![CDATA[Testing concurrent code using DejaFu requires the use of `MonadConc` and `MonadSTM` instead of plain `IO` and `STM`. Is there any performance impact, and if there is, can it be recovered?]]></summary></entry><entry><title type="html">Using Literate Haskell with Jekyll</title><link href="https://nicolast.be/various/jekyll-literate-haskell/" rel="alternate" type="text/html" title="Using Literate Haskell with Jekyll" /><published>2023-04-10T23:28:00+02:00</published><updated>2023-04-10T23:28:00+02:00</updated><id>https://nicolast.be/various/jekyll-literate-haskell</id><content type="html" xml:base="https://nicolast.be/various/jekyll-literate-haskell/"><![CDATA[<p>This blog is powered by the <a href="https://jekyllrb.com/">Jekyll</a> static site generator, hosted on
<a href="https://pages.github.com/">GitHub Pages</a>.
With Jekyll, you write posts in
<a href="https://daringfireball.net/projects/markdown/syntax">Markdown</a>-formatted files, which are
then rendered into HTML using some templates. When writing technical articles including code
examples, as an author I want to make sure these examples are correct, i.e., they compile
cleanly and, ideally, some tests pass. I assume the reader appreciates this as well (I know
I do!).</p>

<p>One way to tackle this is keeping the code in some source file(s), ensure these compile, and
copy-paste snippets into the Markdown source of an article. This works, but copy-paste leaves
room for error, and updating source-code while writing the article, then making sure all snippets
are updated correctly, is definitely error-prone.</p>

<p>Wouldn’t it be nice if the article file itself would be executable (or, at least, checked by the
compiler)? Luckily this is possible, without all too much hassle! Given a working Jekyll
installation, here’s what we want:</p>

<ul>
  <li>A way to turn an article, including code blocks, into input the compiler can work with.</li>
  <li>A way to <em>run</em> the article file, or load it in a REPL, including any dependencies the code
relies on.</li>
  <li>A way for Jekyll to include such articles in the rendered website.</li>
</ul>

<h2 id="compiling-markdown">Compiling Markdown</h2>

<p>The <a href="https://www.haskell.org/ghc/">GHC</a> <a href="https://www.haskell.org/">Haskell</a> compiler has
built-in support for Literate Haskell, which allows to interleave code blocks with text.
The native Literate Haskell support doesn’t know about Markdown formatting, but with some
flags, GHC can be instructed to use some custom preprocessor which knows how to extract code
from some literate source file.</p>

<p>The <a href="https://github.com/sol/markdown-unlit">markdown-unlit</a> package does exactly this for
Markdown-formatted files: it extracts all Haskell code blocks and passes these to the compiler.
So Markdown-formatted input like</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Here's how to print the string "Hello, world" on the console:

```haskell
printHelloWorld :: IO ()
printHelloWorld = putStrLn "Hello, world"
```

Simple!
</code></pre></div></div>

<p>becomes</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">printHelloWorld</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">printHelloWorld</span> <span class="o">=</span> <span class="n">putStrLn</span> <span class="s">"Hello, world"</span>
</code></pre></div></div>

<p>For GHC to use the <code class="language-plaintext highlighter-rouge">markdown-unlit</code> preprocessor, the <code class="language-plaintext highlighter-rouge">-pgmL</code> option must be used, and the
source file must have the <code class="language-plaintext highlighter-rouge">.lhs</code> file extension.</p>

<h3 id="aside-testing-readmemd">Aside: Testing <code class="language-plaintext highlighter-rouge">README.md</code></h3>

<p>Next to running Markdown articles, <code class="language-plaintext highlighter-rouge">markdown-unlit</code> can be used to test your project’s
<code class="language-plaintext highlighter-rouge">README.md</code>, as I do in the <a href="https://github.com/NicolasT/landlock-hs/tree/main/landlock"><code class="language-plaintext highlighter-rouge">landlock</code></a>
package. See <a href="https://github.com/sol/markdown-unlit#extended-example">this example</a>
for more information!</p>

<h2 id="running-articles">Running Articles</h2>

<p>Now we know how to extract code blocks from article source files for the compiler to process
them, we need a way to invoke the compiler (or launch it in REPL mode) with some source file.
Of course the <code class="language-plaintext highlighter-rouge">ghc</code> binary can be invoked as-is, passing the necessary <code class="language-plaintext highlighter-rouge">-pgmL</code> option and
any others, but this has several drawbacks, especially when the code in the article depends on
some other packages:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">markdown-unlit</code> must be pre-installed</li>
  <li>We must not forget the <code class="language-plaintext highlighter-rouge">-pgmL</code> option, including the path to <code class="language-plaintext highlighter-rouge">markdown-unlit</code> unless it’s
installed in <code class="language-plaintext highlighter-rouge">$PATH</code></li>
  <li>Any dependencies must be installed in a way for GHC to find them</li>
  <li>Dependencies may require <code class="language-plaintext highlighter-rouge">-package ...</code> or other options to be passed to GHC</li>
</ul>

<p>In the Haskell ecosystem, the <code class="language-plaintext highlighter-rouge">cabal</code> tool is used to install dependencies, invoke
the compiler with the right options to find these dependencies, etc. In regular Haskell
packages, a Cabal project description file (<code class="language-plaintext highlighter-rouge">packagename.cabal</code>) contains all information
needed for <code class="language-plaintext highlighter-rouge">cabal</code> to do its job. A Jekyll article Markdown source file doesn’t come with
a project description file, so how can the <code class="language-plaintext highlighter-rouge">cabal-install</code> functionality be reused? I recently
found out <code class="language-plaintext highlighter-rouge">cabal</code> nowadays has a <em>scripting mode</em>: it can read metadata, enclosed in a comment block,
from a source file, and use it accordingly. So, including the following in the Markdown source
of an article will instruct <code class="language-plaintext highlighter-rouge">cabal</code> to provide all dependencies (none but <code class="language-plaintext highlighter-rouge">base</code> for this
article), ensure <code class="language-plaintext highlighter-rouge">markdown-unlit</code> is available, and invoke <code class="language-plaintext highlighter-rouge">ghc</code> with the right options:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{- cabal:
build-depends: base ^&gt;=4.17
default-language: Haskell2010
build-tool-depends: markdown-unlit:markdown-unlit
ghc-options: -pgmL markdown-unlit -Wall -Werror
-}</span>
</code></pre></div></div>

<p>The above snippet could be put in any kind of section, but I prefer to put it in a
<code class="language-plaintext highlighter-rouge">haskell</code> code-block, so it’s retained in the output of <code class="language-plaintext highlighter-rouge">markdown-unlit</code>.</p>

<p>Next to <code class="language-plaintext highlighter-rouge">build-depends</code> and similar fields in a <code class="language-plaintext highlighter-rouge">cabal</code> section, configuration used in
a <code class="language-plaintext highlighter-rouge">cabal.project</code> file can be put in a <code class="language-plaintext highlighter-rouge">project</code> section. See
<a href="https://cabal.readthedocs.io/en/stable/getting-started.html#run-a-single-file-haskell-script">the documentation</a>
for more details.</p>

<p>With all this in place, articles can be executed using <code class="language-plaintext highlighter-rouge">cabal run article.lhs</code>, or
even better, loaded in a REPL session, including all dependencies, using
<code class="language-plaintext highlighter-rouge">cabal repl article.lhs</code>.</p>

<h2 id="rendering-literate-haskell-articles">Rendering Literate Haskell Articles</h2>

<p>By default, Jekyll won’t read <code class="language-plaintext highlighter-rouge">.lhs</code> files in the <code class="language-plaintext highlighter-rouge">_drafts</code> or <code class="language-plaintext highlighter-rouge">_posts</code> folders as Markdown
files. By default, it will only read files with the <code class="language-plaintext highlighter-rouge">.md</code> extension (and several others)
as Markdown. To treat <code class="language-plaintext highlighter-rouge">.lhs</code> files the same way, add the following to your site’s
<code class="language-plaintext highlighter-rouge">_config.yml</code>:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">markdown_ext</span><span class="pi">:</span> <span class="s2">"</span><span class="s">markdown,mkdown,mkdn,mkd,md,lhs"</span>
</code></pre></div></div>

<p>Any <code class="language-plaintext highlighter-rouge">.lhs</code> files in the <code class="language-plaintext highlighter-rouge">_drafts</code>, <code class="language-plaintext highlighter-rouge">_posts</code> and other folders will now be rendered as Markdown
sources.</p>

<h2 id="finishing-up">Finishing Up</h2>

<p>Finally, let’s wrap things up for this particular article:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">main</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">main</span> <span class="o">=</span> <span class="n">printHelloWorld</span>
</code></pre></div></div>

<p>and indeed:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cabal run _drafts/jekyll-literate-haskell.lhs
Hello, world
</code></pre></div></div>

<p>Of course, this could launch a <a href="https://hackage.haskell.org/package/tasty">tasty</a> test-suite
or similar, see <a href="/development/testing-concurrent-code-using-dejafu/#testing">here</a>
for an example.</p>

<p>Happy hacking^Wwriting!</p>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Various" /><summary type="html"><![CDATA[With a little bit of configuration, Haskell code in Jekyll articles can be executed or loaded in a REPL: a great way to ensure the code actually works!]]></summary></entry><entry><title type="html">Testing concurrent code using DejaFu</title><link href="https://nicolast.be/development/testing-concurrent-code-using-dejafu/" rel="alternate" type="text/html" title="Testing concurrent code using DejaFu" /><published>2023-04-06T21:17:00+02:00</published><updated>2023-04-14T21:31:00+02:00</updated><id>https://nicolast.be/development/testing-concurrent-code-using-dejafu</id><content type="html" xml:base="https://nicolast.be/development/testing-concurrent-code-using-dejafu/"><![CDATA[<p>Recently I was working on some code using <a href="https://www.haskell.org/ghc/">GHC</a>
<a href="https://www.haskell.org">Haskell</a>’s <a href="https://hackage.haskell.org/package/stm">STM</a> (short for
Software Transactional Memory)
functionality. STM gives a programmer mutable variables (so-called <code class="language-plaintext highlighter-rouge">TVar</code>s), functions to work on such
variables in some context (e.g., <code class="language-plaintext highlighter-rouge">writeTVar :: TVar a -&gt; a -&gt; STM ()</code>), and a way to run a program
working with such variables transactionally (<code class="language-plaintext highlighter-rouge">atomically :: STM a -&gt; IO a</code>). The transactional aspect
is what makes STM so powerful: when multiple threads of execution mutate the same <code class="language-plaintext highlighter-rouge">TVar</code>s concurrently,
a transaction will be automatically aborted and restarted by the runtime upon conflicts. As such, we
can construct programs working with one or more mutable variables, without the need for explicit locking.</p>

<p>The above only scratches the surface of what’s possible with STM. To learn more, see
<a href="https://book.realworldhaskell.org/read/software-transactional-memory.html">chapter 28</a>
of <a href="https://book.realworldhaskell.org/">Real World Haskell</a>.</p>

<p>STM makes writing concurrent code with shared mutable state easier, but still leaves room for mistakes.
Code with mutable state, especially with concurrent access to shared mutable state, is more difficult
to test than pure computations. Using <a href="https://hackage.haskell.org/package/dejafu">DejaFu</a>, we can
write tests of concurrent code which will simulate various schedulings of application threads and
validate the result, e.g., by ensuring a program yields the same value no matter the order in which
threads were scheduled, or by ensuring some invariants were maintained at every observable point in
time. In this post, I want to show two patterns I adopted when writing concurrent code, using STM,
with the ability to test it using DejaFu. If you’re not familiar with the latter, you can find more
information on its <a href="https://dejafu.readthedocs.io/en/latest/getting_started.html#why-deja-fu">website</a>.</p>

<p>First, some boilerplate so this post can be executed as a Literal Haskell script:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cm">{- cabal: 
build-depends:
  , base ^&gt;=4.17.0.0
  , concurrency ^&gt;=1.11.0.2
  , exceptions ^&gt;=0.10.7
  , tasty ^&gt;=1.4.3
  , tasty-dejafu ^&gt;=2.1.0.0
build-tool-depends: markdown-unlit:markdown-unlit
ghc-options: -threaded -pgmL markdown-unlit -Wall -Werror
default-language: Haskell2010
-}</span>
</code></pre></div></div>

<p>To test code using DejaFu, it can’t be written using, e.g., <code class="language-plaintext highlighter-rouge">readTVar :: TVar a -&gt; STM a</code>, but
instead needs to use the abstractions provided by the
<a href="https://hackage.haskell.org/package/concurrency-1.11.0.2"><code class="language-plaintext highlighter-rouge">concurrency</code></a> package, e.g.,
<code class="language-plaintext highlighter-rouge">readTVar :: MonadSTM stm =&gt; TVar stm a -&gt; stm a</code>. Notice how the <code class="language-plaintext highlighter-rouge">TVar</code> type is parametrized
by the monad in which it’ll be used. This allows for use in the traditional <code class="language-plaintext highlighter-rouge">STM</code> monad (which
is an instance of <code class="language-plaintext highlighter-rouge">MonadSTM</code>), as well as in emulations of it provided by DejaFu.</p>

<p>Furthermore, we’ll use the <a href="https://hackage.haskell.org/package/exceptions-0.10.7"><code class="language-plaintext highlighter-rouge">exceptions</code></a>
package to throw exceptions while checking invariants, and the
<a href="https://hackage.haskell.org/package/tasty-1.4.3"><code class="language-plaintext highlighter-rouge">tasty</code></a> test framework, including DejaFu
integration for it brought by
<a href="https://hackage.haskell.org/package/tasty-dejafu-2.1.0.0"><code class="language-plaintext highlighter-rouge">tasty-dejafu</code></a> to define and run
some tests.</p>

<p>All good Haskell code starts with some <code class="language-plaintext highlighter-rouge">LANGUAGE</code> pragmas and some <code class="language-plaintext highlighter-rouge">import</code>s, so let’s get those out
of the way:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{-# LANGUAGE QuantifiedConstraints #-}</span>
<span class="cp">{-# LANGUAGE RankNTypes #-}</span>
<span class="cp">{-# LANGUAGE StandaloneDeriving #-}</span>
<span class="cp">{-# LANGUAGE UndecidableInstances #-}</span>

<span class="kr">import</span> <span class="nn">Control.Concurrent.Classy.Async</span> <span class="p">(</span><span class="nf">concurrently_</span><span class="p">,</span> <span class="nf">wait</span><span class="p">,</span> <span class="nf">withAsync</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Concurrent.Classy.STM</span> <span class="p">(</span><span class="kt">TVar</span><span class="p">,</span> <span class="nf">readTVar</span><span class="p">,</span> <span class="nf">modifyTVar'</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Monad</span> <span class="p">(</span><span class="nf">unless</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Monad.Catch</span> <span class="p">(</span><span class="kt">Exception</span><span class="p">(</span><span class="o">..</span><span class="p">),</span> <span class="kt">MonadThrow</span><span class="p">,</span> <span class="nf">throwM</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Monad.Conc.Class</span> <span class="p">(</span><span class="kt">MonadConc</span><span class="p">,</span> <span class="kt">STM</span><span class="p">,</span> <span class="nf">atomically</span><span class="p">,</span> <span class="nf">newTVarConc</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Monad.STM.Class</span> <span class="p">(</span><span class="kt">MonadSTM</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Data.Functor.Identity</span> <span class="p">(</span><span class="kt">Identity</span><span class="p">(</span><span class="o">..</span><span class="p">))</span>
<span class="kr">import</span> <span class="nn">Test.Tasty</span> <span class="p">(</span><span class="nf">defaultMain</span><span class="p">,</span> <span class="nf">testGroup</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Test.Tasty.DejaFu</span> <span class="p">(</span><span class="kt">Basic</span><span class="p">,</span> <span class="kt">Program</span><span class="p">,</span> <span class="kt">WithSetup</span><span class="p">,</span> <span class="nf">inspectTVar</span><span class="p">,</span> <span class="nf">registerInvariant</span><span class="p">,</span> <span class="nf">testAuto</span><span class="p">,</span> <span class="nf">withSetup</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="state-and-mutations">State and Mutations</h2>

<p>In the (admittedly contrived) example used throughout this post, our program keeps track of
two <code class="language-plaintext highlighter-rouge">Int</code> values, and provides two actions to mutate them: one to add an <code class="language-plaintext highlighter-rouge">Int</code> which will
add the given value to the first mutable variable and substract it from the second, and another
to substract an <code class="language-plaintext highlighter-rouge">Int</code> which will, as you may have guessed, substract the given value from the
first mutable variable and add it to the second. Hence, there’s an invariant that should be
maintained at all times: the sum of both mutable variables should be <code class="language-plaintext highlighter-rouge">0</code>.</p>

<h3 id="state-type">State Type</h3>

<p>In regular STM code, we’d use a datatype like the following to maintain the state:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data Store = Store
  { storeA :: TVar Int,
    storeB :: TVar Int
  }
</code></pre></div></div>

<p>This works, but as mentioned before, we need to use the types provided by the <code class="language-plaintext highlighter-rouge">concurrency</code> package
to be able to test our code using DejaFu. Hence, we need to use its <code class="language-plaintext highlighter-rouge">TVar stm a</code> type (family)
instead:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>data Store stm = Store
  { storeA :: TVar stm Int,
    storeB :: TVar stm Int
  }
</code></pre></div></div>

<p>This goes in the right direction, and indeed, we could provide implementations for <code class="language-plaintext highlighter-rouge">add</code> and <code class="language-plaintext highlighter-rouge">sub</code>
and test those. However, there are still some shortcomings:</p>

<ul>
  <li>
    <p>When checking invariants, writing code doing so in a <em>pure</em> style (modulo throwing exceptions)
simplifies the implementation a lot, instead of littering the validation code with <code class="language-plaintext highlighter-rouge">readTVar</code> calls
and monadic binds. This, in turn, makes testing of the invariants validation code easier as well.</p>
  </li>
  <li>
    <p>DejaFu can be used to validate a concurrent computation always yields the same result, which imposes
an <code class="language-plaintext highlighter-rouge">Eq</code> constraint on the result type. We often want to check the shared mutable state is the same
no matter which scheduling of mutators happened, but a data type with <code class="language-plaintext highlighter-rouge">TVar</code>s inside can’t have an
<code class="language-plaintext highlighter-rouge">Eq</code> instance.</p>
  </li>
</ul>

<p>So, we build <code class="language-plaintext highlighter-rouge">Store</code> such that it’s paramterized over a <code class="language-plaintext highlighter-rouge">cell</code> type which, for the mutable version
of <code class="language-plaintext highlighter-rouge">Store</code> will be some <code class="language-plaintext highlighter-rouge">TVar</code>, whilst <code class="language-plaintext highlighter-rouge">cell</code> can also be <code class="language-plaintext highlighter-rouge">Identity</code> in which case the resulting
type is immutable:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">data</span> <span class="kt">Store'</span> <span class="n">cell</span> <span class="o">=</span> <span class="kt">Store'</span>
  <span class="p">{</span> <span class="n">storeA</span> <span class="o">::</span> <span class="n">cell</span> <span class="kt">Int</span><span class="p">,</span>
    <span class="n">storeB</span> <span class="o">::</span> <span class="n">cell</span> <span class="kt">Int</span>
  <span class="p">}</span>

<span class="kr">deriving</span> <span class="kr">instance</span> <span class="p">(</span><span class="n">forall</span> <span class="n">a</span><span class="o">.</span> <span class="kt">Show</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Show</span> <span class="p">(</span><span class="n">cell</span> <span class="n">a</span><span class="p">))</span> <span class="o">=&gt;</span> <span class="kt">Show</span> <span class="p">(</span><span class="kt">Store'</span> <span class="n">cell</span><span class="p">)</span>
<span class="kr">deriving</span> <span class="kr">instance</span> <span class="p">(</span><span class="n">forall</span> <span class="n">a</span><span class="o">.</span> <span class="kt">Eq</span> <span class="n">a</span> <span class="o">=&gt;</span> <span class="kt">Eq</span> <span class="p">(</span><span class="n">cell</span> <span class="n">a</span><span class="p">))</span> <span class="o">=&gt;</span> <span class="kt">Eq</span> <span class="p">(</span><span class="kt">Store'</span> <span class="n">cell</span><span class="p">)</span>

<span class="kr">type</span> <span class="kt">FrozenStore</span> <span class="o">=</span> <span class="kt">Store'</span> <span class="kt">Identity</span>
<span class="kr">type</span> <span class="kt">Store</span> <span class="n">stm</span> <span class="o">=</span> <span class="kt">Store'</span> <span class="p">(</span><span class="kt">TVar</span> <span class="n">stm</span><span class="p">)</span>
</code></pre></div></div>

<p>As in the above, we can derive a <code class="language-plaintext highlighter-rouge">Show</code> and <code class="language-plaintext highlighter-rouge">Eq</code> instance for <code class="language-plaintext highlighter-rouge">Store' cell</code> as long as there’s
a <code class="language-plaintext highlighter-rouge">Show</code> and <code class="language-plaintext highlighter-rouge">Eq</code> instance for <code class="language-plaintext highlighter-rouge">cell a</code>, for all possible <code class="language-plaintext highlighter-rouge">a</code>s. This is not the case for <code class="language-plaintext highlighter-rouge">Store</code>
(e.g., there’s no <code class="language-plaintext highlighter-rouge">Show</code> instance for <code class="language-plaintext highlighter-rouge">TVar stm a</code>), but it is for <code class="language-plaintext highlighter-rouge">FrozenStore</code>.</p>

<h3 id="functions">Functions</h3>

<p>We can now define a function to create a new <code class="language-plaintext highlighter-rouge">Store</code>, and implement <code class="language-plaintext highlighter-rouge">add</code> and <code class="language-plaintext highlighter-rouge">sub</code>:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">newStoreConc</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="n">m</span> <span class="p">(</span><span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">))</span>
<span class="n">newStoreConc</span> <span class="o">=</span>
  <span class="kt">Store'</span>
    <span class="o">&lt;$&gt;</span> <span class="n">newTVarConc</span> <span class="mi">0</span>
    <span class="o">&lt;*&gt;</span> <span class="n">newTVarConc</span> <span class="mi">0</span>

<span class="n">addSTM</span> <span class="o">::</span> <span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="n">stm</span> <span class="o">-&gt;</span> <span class="n">stm</span> <span class="nb">()</span>
<span class="n">addSTM</span> <span class="n">i</span> <span class="n">store</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">modifyTVar'</span> <span class="p">(</span><span class="n">storeA</span> <span class="n">store</span><span class="p">)</span> <span class="p">(</span><span class="nf">\</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">+</span> <span class="n">i</span><span class="p">)</span>
  <span class="n">modifyTVar'</span> <span class="p">(</span><span class="n">storeB</span> <span class="n">store</span><span class="p">)</span> <span class="p">(</span><span class="nf">\</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span>

<span class="n">add</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">add</span> <span class="n">i</span> <span class="n">store</span> <span class="o">=</span> <span class="n">atomically</span> <span class="p">(</span><span class="n">addSTM</span> <span class="n">i</span> <span class="n">store</span><span class="p">)</span>

<span class="n">subSTM</span> <span class="o">::</span> <span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="n">stm</span> <span class="o">-&gt;</span> <span class="n">stm</span> <span class="nb">()</span>
<span class="n">subSTM</span> <span class="n">i</span> <span class="n">store</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="n">modifyTVar'</span> <span class="p">(</span><span class="n">storeA</span> <span class="n">store</span><span class="p">)</span> <span class="p">(</span><span class="nf">\</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="n">a</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span>
  <span class="n">modifyTVar'</span> <span class="p">(</span><span class="n">storeB</span> <span class="n">store</span><span class="p">)</span> <span class="p">(</span><span class="nf">\</span><span class="n">b</span> <span class="o">-&gt;</span> <span class="n">b</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span>

<span class="n">sub</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">sub</span> <span class="n">i</span> <span class="n">store</span> <span class="o">=</span> <span class="n">atomically</span> <span class="p">(</span><span class="n">subSTM</span> <span class="n">i</span> <span class="n">store</span><span class="p">)</span>
</code></pre></div></div>

<p>(Did you spot the bug?)</p>

<p>If the types in the code above are a bit daunting, when specialized to <code class="language-plaintext highlighter-rouge">IO</code> we’d get</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import Control.Concurrent.STM (STM, TVar)

type Store = Store' TVar

-- | 'newStoreIO', so you want.
newStoreConc :: IO Store

addSTM :: Int -&gt; Store -&gt; STM ()
add :: Int -&gt; Store -&gt; IO ()

subSTM :: Int -&gt; Store -&gt; STM ()
sub :: Int -&gt; Store -&gt; IO ()
</code></pre></div></div>

<h3 id="snapshots">Snapshots</h3>

<p>The code above works on the mutable version of <code class="language-plaintext highlighter-rouge">Store'</code>. However, we went through this <code class="language-plaintext highlighter-rouge">cell</code>
hassle in order to get an immutable version of a <code class="language-plaintext highlighter-rouge">Store'</code> for use in invariant checks and
consistency tests. The following functions can be defined to turn a <code class="language-plaintext highlighter-rouge">Store stm</code> into an
<code class="language-plaintext highlighter-rouge">stm FrozenStore</code>:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">snapshotWith</span> <span class="o">::</span>
  <span class="kt">Applicative</span> <span class="n">m</span> <span class="o">=&gt;</span>
  <span class="p">(</span><span class="n">forall</span> <span class="n">a</span><span class="o">.</span> <span class="n">cell</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span>
  <span class="kt">Store'</span> <span class="n">cell</span> <span class="o">-&gt;</span>
  <span class="n">m</span> <span class="kt">FrozenStore</span>
<span class="n">snapshotWith</span> <span class="n">readCell</span> <span class="n">store</span> <span class="o">=</span>
  <span class="kt">Store'</span>
    <span class="o">&lt;$&gt;</span> <span class="p">(</span><span class="kt">Identity</span> <span class="o">&lt;$&gt;</span> <span class="n">readCell</span> <span class="p">(</span><span class="n">storeA</span> <span class="n">store</span><span class="p">))</span>
    <span class="o">&lt;*&gt;</span> <span class="p">(</span><span class="kt">Identity</span> <span class="o">&lt;$&gt;</span> <span class="n">readCell</span> <span class="p">(</span><span class="n">storeB</span> <span class="n">store</span><span class="p">))</span>

<span class="n">snapshotSTM</span> <span class="o">::</span> <span class="kt">MonadSTM</span> <span class="n">stm</span> <span class="o">=&gt;</span> <span class="kt">Store</span> <span class="n">stm</span> <span class="o">-&gt;</span> <span class="n">stm</span> <span class="kt">FrozenStore</span>
<span class="n">snapshotSTM</span> <span class="o">=</span> <span class="n">snapshotWith</span> <span class="n">readTVar</span>

<span class="n">snapshot</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="kt">FrozenStore</span>
<span class="n">snapshot</span> <span class="o">=</span> <span class="n">atomically</span> <span class="o">.</span> <span class="n">snapshotSTM</span>
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">snapshotWith</code> function is where the magic happens. It takes an action which, in some
<code class="language-plaintext highlighter-rouge">Applicative</code> context, can read the value of a <code class="language-plaintext highlighter-rouge">cell</code>, and can then turn a <code class="language-plaintext highlighter-rouge">Store' cell</code> into
a <code class="language-plaintext highlighter-rouge">FrozenStore</code> (where <code class="language-plaintext highlighter-rouge">cell</code> is <code class="language-plaintext highlighter-rouge">Identity</code>) within said context. <code class="language-plaintext highlighter-rouge">snapshotSTM</code> is a utility
to work with a <code class="language-plaintext highlighter-rouge">MonadSTM stm =&gt; Store stm</code> (i.e., snapshotting with <code class="language-plaintext highlighter-rouge">readTVar</code>), and <code class="language-plaintext highlighter-rouge">snapshot</code>
wraps <code class="language-plaintext highlighter-rouge">snapshotSTM</code> to run in a <code class="language-plaintext highlighter-rouge">MonadConc</code>.</p>

<p>We need <code class="language-plaintext highlighter-rouge">snapshotWith</code>, and not only <code class="language-plaintext highlighter-rouge">snapshotSTM</code>, for use in DejaFu’s <code class="language-plaintext highlighter-rouge">Invariant</code> monad later.</p>

<h3 id="invariants">Invariants</h3>

<p>Finally, we can define <code class="language-plaintext highlighter-rouge">checkInvariants</code>, which ensures invariants are met in a <code class="language-plaintext highlighter-rouge">FrozenStore</code>.
If not, it throws an <code class="language-plaintext highlighter-rouge">InvariantViolation</code> exception:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kr">newtype</span> <span class="kt">InvariantViolation</span> <span class="o">=</span> <span class="kt">InvariantViolation</span> <span class="kt">String</span>
  <span class="kr">deriving</span> <span class="p">(</span><span class="kt">Show</span><span class="p">)</span>

<span class="kr">instance</span> <span class="kt">Exception</span> <span class="kt">InvariantViolation</span> <span class="kr">where</span>
  <span class="n">displayException</span> <span class="p">(</span><span class="kt">InvariantViolation</span> <span class="n">msg</span><span class="p">)</span> <span class="o">=</span> <span class="s">"Invariant violation: "</span> <span class="o">&lt;&gt;</span> <span class="n">msg</span>

<span class="n">invariantViolation</span> <span class="o">::</span> <span class="kt">MonadThrow</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">String</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span>
<span class="n">invariantViolation</span> <span class="o">=</span> <span class="n">throwM</span> <span class="o">.</span> <span class="kt">InvariantViolation</span>

<span class="n">checkInvariants</span> <span class="o">::</span> <span class="kt">MonadThrow</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">FrozenStore</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">checkInvariants</span> <span class="n">store</span> <span class="o">=</span> <span class="kr">do</span>
  <span class="kr">let</span> <span class="kt">Identity</span> <span class="n">a</span> <span class="o">=</span> <span class="n">storeA</span> <span class="n">store</span>
      <span class="kt">Identity</span> <span class="n">b</span> <span class="o">=</span> <span class="n">storeB</span> <span class="n">store</span>

  <span class="n">unless</span> <span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="o">$</span>
    <span class="n">invariantViolation</span> <span class="p">(</span><span class="s">"a + b /= 0, a = "</span> <span class="o">&lt;&gt;</span> <span class="n">show</span> <span class="n">a</span> <span class="o">&lt;&gt;</span> <span class="s">", b = "</span> <span class="o">&lt;&gt;</span> <span class="n">show</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>

<p>There are many ways to implement <code class="language-plaintext highlighter-rouge">checkInvariants</code>, and the above is only one of them. Some
alternatives include</p>

<ul>
  <li>
    <p>Making <code class="language-plaintext highlighter-rouge">checkInvariants</code> pure, returning, e.g., <code class="language-plaintext highlighter-rouge">Either String ()</code> or a <code class="language-plaintext highlighter-rouge">Bool</code> value, and
wrapping it later to turn a non-successful result into an exception (as required by DejaFu).</p>
  </li>
  <li>
    <p>Using the 
<a href="https://hackage.haskell.org/package/either-5.0.2/docs/Data-Either-Validation.html"><code class="language-plaintext highlighter-rouge">Validation</code> monad</a>
to capture all invariant violations instead of only the first one, and either returning
them or throwing them at the end.</p>
  </li>
</ul>

<h2 id="concurrent-access">Concurrent Access</h2>
<p>With the above code in place, here’s some code using a <code class="language-plaintext highlighter-rouge">Store</code>, mutating it
concurrently in various ways:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cd">-- | Add two values to a `Store`, concurrently.</span>
<span class="n">concurrentAdd</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">concurrentAdd</span> <span class="n">i</span> <span class="n">j</span> <span class="n">store</span> <span class="o">=</span>
  <span class="n">concurrently_</span>
    <span class="p">(</span><span class="n">add</span> <span class="n">i</span> <span class="n">store</span><span class="p">)</span>
    <span class="p">(</span><span class="n">add</span> <span class="n">j</span> <span class="n">store</span><span class="p">)</span>

<span class="cd">-- | Add two values to a `Store`, concurrently. With a bug.</span>
<span class="n">brokenConcurrentAdd</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">brokenConcurrentAdd</span> <span class="n">i</span> <span class="n">j</span> <span class="n">store</span> <span class="o">=</span>
  <span class="n">withAsync</span> <span class="p">(</span><span class="n">add</span> <span class="n">i</span> <span class="n">store</span><span class="p">)</span> <span class="o">$</span> <span class="nf">\</span><span class="n">a</span> <span class="o">-&gt;</span>
    <span class="n">withAsync</span> <span class="p">(</span><span class="n">add</span> <span class="n">j</span> <span class="n">store</span><span class="p">)</span> <span class="o">$</span> <span class="nf">\</span><span class="kr">_</span> <span class="o">-&gt;</span>
      <span class="n">wait</span> <span class="n">a</span>

<span class="cd">-- | Add and substract a value from a `Store`, concurrently.</span>
<span class="n">concurrentAddAndSub</span> <span class="o">::</span> <span class="kt">MonadConc</span> <span class="n">m</span> <span class="o">=&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Int</span> <span class="o">-&gt;</span> <span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="n">m</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="nb">()</span>
<span class="n">concurrentAddAndSub</span> <span class="n">i</span> <span class="n">j</span> <span class="n">store</span> <span class="o">=</span>
  <span class="n">concurrently_</span>
    <span class="p">(</span><span class="n">add</span> <span class="n">i</span> <span class="n">store</span><span class="p">)</span>
    <span class="p">(</span><span class="n">sub</span> <span class="n">j</span> <span class="n">store</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="testing">Testing</h2>

<p>Finally, we can write some tests for the above code. First, <code class="language-plaintext highlighter-rouge">withStore</code> is a helper to
create a <code class="language-plaintext highlighter-rouge">Store'</code> (within the appropriate DejaFu <code class="language-plaintext highlighter-rouge">MonadConc</code> environment), and register
an invariant check. The latter will create a <code class="language-plaintext highlighter-rouge">FrozenStore</code> from the mutable one using
<code class="language-plaintext highlighter-rouge">snapshotWith inspectTVar</code>. <code class="language-plaintext highlighter-rouge">inspectTVar</code> is a function in DejaFu’s <code class="language-plaintext highlighter-rouge">Invariant</code> monad
which allows to peek inside the contents of a <code class="language-plaintext highlighter-rouge">TVar</code> in the model:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">withStore</span> <span class="o">::</span>
  <span class="kt">Monad</span> <span class="n">m</span> <span class="o">=&gt;</span>
  <span class="p">(</span><span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="p">(</span><span class="kt">Program</span> <span class="kt">Basic</span> <span class="n">m</span><span class="p">))</span> <span class="o">-&gt;</span> <span class="kt">Program</span> <span class="kt">Basic</span> <span class="n">m</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span>
  <span class="kt">Program</span> <span class="p">(</span><span class="kt">WithSetup</span> <span class="p">(</span><span class="kt">Store</span> <span class="p">(</span><span class="kt">STM</span> <span class="p">(</span><span class="kt">Program</span> <span class="kt">Basic</span> <span class="n">m</span><span class="p">))))</span> <span class="n">m</span> <span class="n">a</span>
<span class="n">withStore</span> <span class="o">=</span> <span class="n">withSetup</span> <span class="o">$</span> <span class="kr">do</span>
  <span class="n">store</span> <span class="o">&lt;-</span> <span class="n">newStoreConc</span>

  <span class="n">registerInvariant</span> <span class="o">$</span>
    <span class="n">checkInvariants</span> <span class="o">=&lt;&lt;</span> <span class="n">snapshotWith</span> <span class="n">inspectTVar</span> <span class="n">store</span>

  <span class="n">pure</span> <span class="n">store</span>
</code></pre></div></div>

<p>Then, the tests. Each test runs the default DejaFu validations calling one of the
concurrent functions on a provisioned <code class="language-plaintext highlighter-rouge">Store'</code>, and returns a snapshot of the
store. DejaFu will then check whether every interleaving of concurrent actions
results in the same value/state.</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">main</span> <span class="o">::</span> <span class="kt">IO</span> <span class="nb">()</span>
<span class="n">main</span> <span class="o">=</span> <span class="n">defaultMain</span> <span class="o">$</span> <span class="n">testGroup</span> <span class="s">"store-app"</span> <span class="p">[</span>
  <span class="n">testAuto</span> <span class="s">"concurrentAdd"</span> <span class="o">$</span> <span class="n">withStore</span> <span class="o">$</span> <span class="nf">\</span><span class="n">store</span> <span class="o">-&gt;</span> <span class="kr">do</span>
    <span class="n">concurrentAdd</span> <span class="mi">10</span> <span class="mi">20</span> <span class="n">store</span>

    <span class="n">snapshot</span> <span class="n">store</span><span class="p">,</span>

  <span class="n">testAuto</span> <span class="s">"brokenConcurrentAdd"</span> <span class="o">$</span> <span class="n">withStore</span> <span class="o">$</span> <span class="nf">\</span><span class="n">store</span> <span class="o">-&gt;</span> <span class="kr">do</span>
    <span class="n">brokenConcurrentAdd</span> <span class="mi">10</span> <span class="mi">20</span> <span class="n">store</span>

    <span class="n">snapshot</span> <span class="n">store</span><span class="p">,</span>

  <span class="n">testAuto</span> <span class="s">"concurrentAddAndSub"</span> <span class="o">$</span> <span class="n">withStore</span> <span class="o">$</span> <span class="nf">\</span><span class="n">store</span> <span class="o">-&gt;</span> <span class="kr">do</span>
    <span class="n">concurrentAddAndSub</span> <span class="mi">10</span> <span class="mi">20</span> <span class="n">store</span>

    <span class="n">snapshot</span> <span class="n">store</span>
  <span class="p">]</span>
</code></pre></div></div>

<p>The first test succeeds, as desired:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>store-app
  concurrentAdd
    Never Deadlocks:   OK (0.13s)
    No Exceptions:     OK (0.02s)
    Consistent Result: OK (0.02s)
</code></pre></div></div>

<p>The second one, however, fails, as expected:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  brokenConcurrentAdd
    Never Deadlocks:   OK
    No Exceptions:     OK
    Consistent Result: FAIL
      Failed:
        Store' {storeA = Identity 30, storeB = Identity (-30)} S0-----------S1---------S0---S2---------S0-------------

        Store' {storeA = Identity 10, storeB = Identity (-10)} S0-----------S1---------S0---S2--P0---S2---S0-----------

      Use -p '/brokenConcurrentAdd.Consistent Result/' to rerun this test only.
</code></pre></div></div>

<p>Indeed, <code class="language-plaintext highlighter-rouge">brokenConcurrentAdd</code> fails to <code class="language-plaintext highlighter-rouge">wait</code> for the inner <code class="language-plaintext highlighter-rouge">Async</code>. Hence, there are
two possible interleavings: one where the second <code class="language-plaintext highlighter-rouge">add</code> succeeds before the thread
running it is killed (the first interleaving above, where <code class="language-plaintext highlighter-rouge">storeA</code> is <code class="language-plaintext highlighter-rouge">30</code>), or another
one where the thread is killed before its <code class="language-plaintext highlighter-rouge">add</code> action has completed, and the
snapshotted state has <code class="language-plaintext highlighter-rouge">10</code> in <code class="language-plaintext highlighter-rouge">storeA</code> (the second interleaving above).</p>

<p>The last test also fails, in this case not because some concurrency bug as above,
but because the invariants we expect our state to adhere to are violated:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  concurrentAddAndSub
    Never Deadlocks:   OK
    No Exceptions:     OK
    Consistent Result: FAIL
      Failed:
        [invariant failure] S0-------S1--------S2---

        [invariant failure] S0-------S2---

      Use -p '/concurrentAddAndSub.Consistent Result/' to rerun this test only.

2 out of 9 tests failed (0.19s)
</code></pre></div></div>

<p>Indeed, once the second thread (which runs <code class="language-plaintext highlighter-rouge">sub j store</code>) ran, no matter
whether the first thread (running <code class="language-plaintext highlighter-rouge">add i store</code>) ran before or not, the <code class="language-plaintext highlighter-rouge">a + b == 0</code>
invariant no longer holds. Indeed, there’s a bug in the <code class="language-plaintext highlighter-rouge">subSTM</code> function: instead of
substracting <code class="language-plaintext highlighter-rouge">i</code> from <code class="language-plaintext highlighter-rouge">storeB</code>, it should add it.</p>

<p>Sadly, at this point <code class="language-plaintext highlighter-rouge">tasty-dejafu</code> won’t show which exception was raised
while checking invariants, and only displays <code class="language-plaintext highlighter-rouge">invariant failure</code>. I opened an
<a href="https://github.com/barrucadu/dejafu/issues/385">issue</a> to maybe improve this.</p>

<h2 id="conclusion">Conclusion</h2>
<p>STM allows for safe concurrent access to shared mutable state with fine-grained
locking. However, when multiple variables are at play, defining invariants between
their values and ensuring these invariants aren’t breached in some interleaving
of concurrent mutations is important. The DejaFu library can help to achieve this,
so building your code on the <code class="language-plaintext highlighter-rouge">concurrency</code> abstractions from the start allows to
write all kinds of tests later.</p>

<h3 id="future-work">Future Work</h3>
<ul>
  <li>
    <p>The trick used above to use <code class="language-plaintext highlighter-rouge">Identity</code> as the <code class="language-plaintext highlighter-rouge">cell</code> type allows for immutable
versions of the data type bundling all variables. However, the <code class="language-plaintext highlighter-rouge">Identity</code> wrapper
is a bit of a burden when dissecting <code class="language-plaintext highlighter-rouge">FrozenStore</code>. It’d be nice if <code class="language-plaintext highlighter-rouge">cell a</code> could
become a plain <code class="language-plaintext highlighter-rouge">a</code> removing the need to unpack the <code class="language-plaintext highlighter-rouge">Identity</code> constructor. I have
a hunch this might be possible by using some closed type family, but didn’t pursue
this further yet.</p>
  </li>
  <li>
    <p>Implementing <code class="language-plaintext highlighter-rouge">snapshotWith</code> is quite boring. I imagine it’s possible to have
a generic version of it using <code class="language-plaintext highlighter-rouge">GHC.Generics</code>.</p>
  </li>
  <li>
    <p>Using the <code class="language-plaintext highlighter-rouge">concurrency</code> abstraction brings a <code class="language-plaintext highlighter-rouge">MonadConc</code> or <code class="language-plaintext highlighter-rouge">MonadSTM</code> constraint
and hence a dictionary lookup at runtime. I’d love to see some benchmarks where
a library is defined in terms of <code class="language-plaintext highlighter-rouge">MonadConc</code> and <code class="language-plaintext highlighter-rouge">MonadSTM</code>, but every function
is <code class="language-plaintext highlighter-rouge">INLINEABLE</code> and/or <code class="language-plaintext highlighter-rouge">SPECIALIZE</code>d to <code class="language-plaintext highlighter-rouge">Control.Concurrent.STM.STM</code> and <code class="language-plaintext highlighter-rouge">IO</code> so
there’s, ideally, no performance hit for <em>regular application</em> consumers of the
library vs. using plain <code class="language-plaintext highlighter-rouge">STM</code> and <code class="language-plaintext highlighter-rouge">IO</code> in the library code. [Update: <a href="/development/concurrency-and-performance/">here’s the
answer</a>]</p>
  </li>
</ul>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Development" /><summary type="html"><![CDATA[Writing correct concurrent code with shared mutable state is hard. Testing concurrent code with shared mutable state is hard. In Haskell, we can use STM to transactionally change state, and DejaFu to test concurrent code. In this post, we look into how this is done, and discuss an approach to simplify the testing effort.]]></summary></entry><entry><title type="html">xinU, a Haskell Experiment</title><link href="https://nicolast.be/development/xinu-a-haskell-experiment/" rel="alternate" type="text/html" title="xinU, a Haskell Experiment" /><published>2022-09-16T01:01:00+02:00</published><updated>2022-09-16T01:01:00+02:00</updated><id>https://nicolast.be/development/xinu-a-haskell-experiment</id><content type="html" xml:base="https://nicolast.be/development/xinu-a-haskell-experiment/"><![CDATA[<p>Even though <a href="https://www.haskell.org">Haskell</a> is considered to be a high-level
programming language, it’s a good fit for various system-level applications and
services as well, similar to how <a href="https://go.dev">Go</a> is used for many
applications.</p>

<p>A lot of functionality can be implemented in high-level user-space libraries,
but at some point we must interact with the system and its kernel through
<em><a href="https://en.wikipedia.org/wiki/System_call">syscalls</a></em>. In the
<a href="https://www.haskell.org/ghc/">GHC</a> Haskell ecosystem, we use the wrappers
provided by the system C library instead of directly calling into the kernel,
which doesn’t take a lot of effort thanks to GHC’s excellent <a href="https://wiki.haskell.org/Foreign_Function_Interface">Foreign Function
Interface</a> support.
Exposing the</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">openat</span><span class="p">(</span><span class="kt">int</span> <span class="n">dirfd</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span><span class="n">pathname</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span><span class="p">)</span>
</code></pre></div></div>
<p>function from <em>libc</em> to Haskell code is as simple as</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">foreign</span> <span class="kr">import</span> <span class="nn">capi</span> <span class="n">safe</span> <span class="s">"fcntl.h openat"</span>
    <span class="n">c_openat</span> <span class="o">::</span> <span class="kt">CInt</span> <span class="o">-&gt;</span> <span class="kt">CString</span> <span class="o">-&gt;</span> <span class="kt">CInt</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="kt">CInt</span>
</code></pre></div></div>

<p>Now Haskell code can call <code class="language-plaintext highlighter-rouge">c_openat</code> to open a file.</p>

<p>The above code is, however, a bit too low-level for most practical purposes:</p>

<ul>
  <li>When <code class="language-plaintext highlighter-rouge">openat</code> fails, it returns <code class="language-plaintext highlighter-rouge">-1</code> and <code class="language-plaintext highlighter-rouge">errno</code> is set. Checking whether the
return value of the <code class="language-plaintext highlighter-rouge">c_openat</code> action is <code class="language-plaintext highlighter-rouge">-1</code> is not very Haskell’esque: this
is where we expect an exception to be thrown.</li>
  <li>The
<a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Foreign-C-Types.html#t:CInt"><code class="language-plaintext highlighter-rouge">CInt</code></a>
type is very generic. Instead, we’d like to use a type specific to
file-descriptors, so a corresponding <code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code> or <code class="language-plaintext highlighter-rouge">close</code> action will
take such type as an argument, not any arbitrary <code class="language-plaintext highlighter-rouge">CInt</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">c_openat</code> takes a
<a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Foreign-C-String.html#t:CString"><code class="language-plaintext highlighter-rouge">CString</code></a>
argument, which is a <code class="language-plaintext highlighter-rouge">Ptr CChar</code>. In high-level code, this is not a type we
regularly work with. An API using a less clumsy path type would be welcome.</li>
</ul>

<p>Luckily, there’s a popular library in the ecosystem which provides just that:
<a href="https://hackage.haskell.org/package/unix"><code class="language-plaintext highlighter-rouge">unix</code></a>. In its
<a href="https://hackage.haskell.org/package/unix-2.8.0.0/docs/System-Posix-IO.html"><code class="language-plaintext highlighter-rouge">System.Posix.IO</code></a>
module, it provides</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">openFdAt</span> <span class="o">::</span> <span class="kt">Maybe</span> <span class="kt">Fd</span> <span class="o">-&gt;</span> <span class="kt">FilePath</span> <span class="o">-&gt;</span> <span class="kt">OpenMode</span> <span class="o">-&gt;</span> <span class="kt">OpenFileFlags</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="kt">Fd</span>
</code></pre></div></div>

<p>which is a wrapper around <code class="language-plaintext highlighter-rouge">c_openat</code>. It’s using the <a href="https://hackage.haskell.org/package/base-4.14.1.0/docs/System-Posix-Types.html#t:Fd"><code class="language-plaintext highlighter-rouge">Fd</code></a>
type where applicable, it will throw an <a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Prelude.html#t:IOError"><code class="language-plaintext highlighter-rouge">IOError</code></a>
when the call fails using handy utility functions like</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">Foreign</span><span class="o">.</span><span class="kt">C</span><span class="o">.</span><span class="kt">Error</span><span class="o">.</span><span class="n">throwErrnoIfMinus1</span> <span class="o">::</span> <span class="p">(</span><span class="kt">Eq</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Num</span> <span class="n">a</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="kt">String</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="n">a</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="n">a</span>
</code></pre></div></div>
<p>and takes a
<a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Prelude.html#t:FilePath"><code class="language-plaintext highlighter-rouge">FilePath</code></a> (a.k.a. <code class="language-plaintext highlighter-rouge">String</code>) as argument, internally turning this into a
<code class="language-plaintext highlighter-rouge">CString</code> for the lifetime of the call to <code class="language-plaintext highlighter-rouge">c_openat</code> using</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">Foreign</span><span class="o">.</span><span class="kt">C</span><span class="o">.</span><span class="kt">String</span><span class="o">.</span><span class="n">withCString</span> <span class="o">::</span> <span class="kt">String</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">CString</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="n">a</span>
</code></pre></div></div>

<h2 id="some-problems-with-unix">Some problems with <code class="language-plaintext highlighter-rouge">unix</code></h2>
<p>The <code class="language-plaintext highlighter-rouge">unix</code> package has been serving the Haskell ecosystem well for many years
(and, without a doubt, for many years to come). However, it’s not without its
shortcomings:</p>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">FilePath</code> type (as used in, e.g., the <code class="language-plaintext highlighter-rouge">System.Posix.IO</code> module) being a
<code class="language-plaintext highlighter-rouge">String</code> comes with performance implications. Hence, the <code class="language-plaintext highlighter-rouge">System.Posix.IO</code>
module was cloned into
<a href="https://hackage.haskell.org/package/unix-2.8.0.0/docs/System-Posix-IO-ByteString.html"><code class="language-plaintext highlighter-rouge">System.Posix.IO.ByteString</code></a>
and reworked to use <code class="language-plaintext highlighter-rouge">ByteString</code> values as paths. This duplication requires
certain code changes to be applied in multiple modules.</li>
  <li>Neither <code class="language-plaintext highlighter-rouge">FilePath</code> nor <code class="language-plaintext highlighter-rouge">ByteString</code> are suitable types for paths, because of
encoding issues. Hence, new clones of applicable modules were created now
using
<a href="https://hackage.haskell.org/package/unix-2.8.0.0/docs/System-Posix-PosixString.html#t:PosixPath"><code class="language-plaintext highlighter-rouge">PosixPath</code></a>
values (e.g., <code class="language-plaintext highlighter-rouge">System.Posix.IO.PosixString</code>), further increasing
code-duplication.</li>
  <li>The <code class="language-plaintext highlighter-rouge">unix</code> library exposes functions that are not necessarily available on all
supported platforms, e.g., the
<a href="https://webassembly.org/">WASM</a>/<a href="https://wasi.dev/">WASI</a> platform lacks
some. Availability of library functions is checked using a <code class="language-plaintext highlighter-rouge">configure</code> script
at build time, but when some library function is not found, the corresponding
binding in <code class="language-plaintext highlighter-rouge">unix</code> is implemented, unconditionally, as
    <div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ioError</span> <span class="p">(</span><span class="n">ioeSetLocation</span> <span class="n">unsupportedOperation</span> <span class="s">"..."</span><span class="p">)</span>
</code></pre></div>    </div>
    <p>This breaks the “If it compiles, it works” mantra, since any call to the
function will most definitely not work.</p>
  </li>
  <li><code class="language-plaintext highlighter-rouge">unix</code> provides somewhat-high-level access the system functions, though one
can argue the wrappers are, sometimes, too high-level, and lower-level
interfaces are not made available. As an example, the <code class="language-plaintext highlighter-rouge">openAt</code> call above
takes an <a href="https://hackage.haskell.org/package/unix-2.8.0.0/docs/System-Posix-IO.html#t:OpenFileFlags"><code class="language-plaintext highlighter-rouge">OpenFileFlags</code></a>
argument which is a structure whose fields are mapped to bits in the <code class="language-plaintext highlighter-rouge">flags</code>
argument of <code class="language-plaintext highlighter-rouge">openat</code>. However, if one want to use a <em>flag</em> that’s not
available in <code class="language-plaintext highlighter-rouge">OpenFileFlags</code> (say, <code class="language-plaintext highlighter-rouge">O_PATH</code> on a Linux system), this is not
possible. This forced me to implement another <a href="https://github.com/NicolasT/landlock-hs/blob/b5638684869ad4f85bea53f10a3f0b921f000202/landlock/internal/System/Landlock/OpenPath.hsc">set of bindings for
<code class="language-plaintext highlighter-rouge">openat</code></a>
in <a href="https://github.com/NicolasT/landlock-hs"><code class="language-plaintext highlighter-rouge">landlock-hs</code></a>: not a lot of
effort, but duplication nonetheless.</li>
  <li>Most system functions are effectful (that’s why they exist in the first
place), so a big part of the <code class="language-plaintext highlighter-rouge">unix</code> API lives in <code class="language-plaintext highlighter-rouge">IO</code>. When working with monad
stacks layered on top of <code class="language-plaintext highlighter-rouge">IO</code>, this requires a lot of <code class="language-plaintext highlighter-rouge">liftIO</code>ing.</li>
</ul>

<h2 id="the-xinu-experiment">The <code class="language-plaintext highlighter-rouge">xinu</code> experiment</h2>
<p>To experiment with alternative implementation strategies to expose system
functions to Haskell code, I created the <a href="https://github.com/NicolasT/xinu"><code class="language-plaintext highlighter-rouge">xinu</code></a>
package. Actually, two packages:</p>

<ul>
  <li>
    <p><code class="language-plaintext highlighter-rouge">xinu-ffi</code>, which exposes FFI bindings to library functions, using a
<code class="language-plaintext highlighter-rouge">configure</code> script to detect system capabilities. If a library function is not
found at <code class="language-plaintext highlighter-rouge">configure</code> time, <code class="language-plaintext highlighter-rouge">xinu-ffi</code> will not provide a binding to it. Hence,
the library API can depend on the build environment. However, a <code class="language-plaintext highlighter-rouge">xinu-ffi.h</code>
header file is installed so dependent package can detect availability of
functions using the <code class="language-plaintext highlighter-rouge">CPP</code> language extension.</p>
  </li>
  <li>
    <p><code class="language-plaintext highlighter-rouge">xinu</code>, and a couple of internal libraries, which expose higher-level APIs to
a developer.</p>
  </li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">xinu</code> library, similar to <code class="language-plaintext highlighter-rouge">unix</code>, supports multiple path types. However,
unlike <code class="language-plaintext highlighter-rouge">unix</code>, this is not implemented by copying the modules. Instead, it
leverages GHC’s
<a href="https://gitlab.haskell.org/ghc/ghc/-/wikis/backpack"><em>Backpack</em></a> feature,
which brings ML module functor-like functionality to Haskell. Basically,
Backpack allows us to write code, abstracted over a module for which we only
provide the signature (i.e., the types and functions it must expose). Then, at
build time, we can specify one or more implementations of this signature and
create instanciations of the abstract module. Hence, without any code
duplication, there’s <code class="language-plaintext highlighter-rouge">System.Xinu.IO.FilePath</code> and <code class="language-plaintext highlighter-rouge">System.Xinu.IO.ByteString</code>,
both instanciations of <code class="language-plaintext highlighter-rouge">System.Xinu.IO.Abstract</code> (over
<code class="language-plaintext highlighter-rouge">System.Xinu.Path.FilePath</code> and <code class="language-plaintext highlighter-rouge">System.Xinu.Path.ByteString</code>). The latter are
two modules implementing a rather simple signature:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">signature</span> <span class="kt">System</span><span class="o">.</span><span class="kt">Xinu</span><span class="o">.</span><span class="kt">Path</span> <span class="p">(</span>
      <span class="kt">Path</span>
    <span class="p">,</span> <span class="n">toString</span>
    <span class="p">,</span> <span class="n">withPath</span>
    <span class="p">)</span> <span class="kr">where</span>

<span class="kr">import</span> <span class="nn">Control.Monad.Catch</span> <span class="p">(</span><span class="kt">MonadMask</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Control.Monad.IO.Class</span> <span class="p">(</span><span class="kt">MonadIO</span><span class="p">)</span>
<span class="kr">import</span> <span class="nn">Foreign.C.String</span> <span class="p">(</span><span class="kt">CString</span><span class="p">)</span>

<span class="kr">data</span> <span class="kt">Path</span>

<span class="c1">-- Execute an action, passing the given Path as a CString.</span>
<span class="n">withPath</span> <span class="o">::</span> <span class="p">(</span><span class="kt">MonadIO</span> <span class="n">m</span><span class="p">,</span> <span class="kt">MonadMask</span> <span class="n">m</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="kt">Path</span> <span class="o">-&gt;</span> <span class="p">(</span><span class="kt">CString</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">m</span> <span class="n">a</span>

<span class="c1">-- Used for error reporting.</span>
<span class="n">toString</span> <span class="o">::</span> <span class="kt">Path</span> <span class="o">-&gt;</span> <span class="kt">String</span>
</code></pre></div></div>

<p>Unlike the <code class="language-plaintext highlighter-rouge">unix</code> library <code class="language-plaintext highlighter-rouge">xinu</code> will expose a different API depending on
library function availability of the build environment (based on findings of
<code class="language-plaintext highlighter-rouge">xinu-ffi</code>’s <code class="language-plaintext highlighter-rouge">configure</code> script). Similar to <code class="language-plaintext highlighter-rouge">xinu-ffi</code>, it provides a <code class="language-plaintext highlighter-rouge">xinu.h</code>
header file, so dependents who care about availability of functions (e.g., to
provide different implementations based on what’s available) can use <code class="language-plaintext highlighter-rouge">CPP</code>.</p>

<p>Finally, <code class="language-plaintext highlighter-rouge">xinu</code> functions aren’t <code class="language-plaintext highlighter-rouge">IO</code> (though they’re <code class="language-plaintext highlighter-rouge">SPECIALIZE</code>d for it).
Instead, it relies on the <code class="language-plaintext highlighter-rouge">MonadIO</code> type-class to <code class="language-plaintext highlighter-rouge">liftIO</code> <code class="language-plaintext highlighter-rouge">xinu-ffi</code> functions
where necessary. Furthermore, errors are reported and (where applicable) safely
handled using the <code class="language-plaintext highlighter-rouge">MonadThrow</code> and <code class="language-plaintext highlighter-rouge">MonadMask</code> type-classes from the
<a href="https://hackage.haskell.org/package/exceptions"><code class="language-plaintext highlighter-rouge">exceptions</code></a> package. This
allows <code class="language-plaintext highlighter-rouge">xinu</code> functions to be used within arbitrary monad stacks (assuming an
instance of <code class="language-plaintext highlighter-rouge">MonadIO</code> and <code class="language-plaintext highlighter-rouge">MonadThrow</code>/<code class="language-plaintext highlighter-rouge">MonadMask</code> is present).</p>

<p>So, <code class="language-plaintext highlighter-rouge">xinu-ffi</code> exposes</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">System</span><span class="o">.</span><span class="kt">Xinu</span><span class="o">.</span><span class="kt">IO</span><span class="o">.</span><span class="kt">FFI</span><span class="o">.</span><span class="n">c_openat</span> <span class="o">::</span> <span class="kt">Int32</span> <span class="o">-&gt;</span> <span class="kt">CString</span> <span class="o">-&gt;</span> <span class="kt">Int32</span> <span class="o">-&gt;</span> <span class="kt">Word32</span> <span class="o">-&gt;</span> <span class="kt">IO</span> <span class="kt">Int32</span>
</code></pre></div></div>
<p>while <code class="language-plaintext highlighter-rouge">xinu</code> exposes, among others,</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">System</span><span class="o">.</span><span class="kt">Xinu</span><span class="o">.</span><span class="kt">IO</span><span class="o">.</span><span class="kt">FilePath</span><span class="o">.</span><span class="n">openat</span> <span class="o">::</span> <span class="p">(</span><span class="kt">MonadIO</span> <span class="n">m</span><span class="p">,</span> <span class="kt">MonadMask</span> <span class="n">m</span><span class="p">)</span>
                               <span class="o">=&gt;</span> <span class="kt">Maybe</span> <span class="kt">Int32</span>
                               <span class="o">-&gt;</span> <span class="kt">FilePath</span>
                               <span class="o">-&gt;</span> <span class="kt">Int32</span>
                               <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="kt">Word32</span>
                               <span class="o">-&gt;</span> <span class="n">m</span> <span class="kt">Int32</span>
</code></pre></div></div>
<p>and</p>
<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">System</span><span class="o">.</span><span class="kt">Xinu</span><span class="o">.</span><span class="kt">IO</span><span class="o">.</span><span class="kt">ByteString</span><span class="o">.</span><span class="n">openat</span> <span class="o">::</span> <span class="p">(</span><span class="kt">MonadIO</span> <span class="n">m</span><span class="p">,</span> <span class="kt">MonadMask</span> <span class="n">m</span><span class="p">)</span>
                                 <span class="o">=&gt;</span> <span class="kt">Maybe</span> <span class="kt">Int32</span>
                                 <span class="o">-&gt;</span> <span class="kt">ByteString</span>
                                 <span class="o">-&gt;</span> <span class="kt">Int32</span>
                                 <span class="o">-&gt;</span> <span class="kt">Maybe</span> <span class="kt">Word32</span>
                                 <span class="o">-&gt;</span> <span class="n">m</span> <span class="kt">Int32</span>
</code></pre></div></div>
<p>Of course, the intent is to use higher-level types (like <code class="language-plaintext highlighter-rouge">Fd</code>) instead. This
should be fairly simple to do, especially using
<a href="https://hackage.haskell.org/package/base-4.17.0.0/docs/Data-Coerce.html#v:coerce"><code class="language-plaintext highlighter-rouge">coerce</code></a>
since indeed, we expect (or rather, require) such <code class="language-plaintext highlighter-rouge">Fd</code> to be equal to an <code class="language-plaintext highlighter-rouge">Int32</code>
(at least on this platform).</p>

<h2 id="learnings-and-questions">Learnings and Questions</h2>
<p>It’s a bit too soon to know where this experiment could be heading. However,
some early experiences:</p>

<ul>
  <li>Backpack doesn’t work when a package has <code class="language-plaintext highlighter-rouge">Build-Type</code> <code class="language-plaintext highlighter-rouge">Configure</code>, which is a
bummer: it forces <code class="language-plaintext highlighter-rouge">xinu-ffi</code> to be a separate package, which increases
maintenance burden. If it could be a (public) internal library, this would
make things quite a bit easier.</li>
  <li>A multi-package repository (using <code class="language-plaintext highlighter-rouge">cabal.project</code>) and Backpack seems to
trigger a dependency resolution issue in Cabal, causing <a href="https://github.com/NicolasT/xinu/actions/runs/3060684207/jobs/4939496825#step:20:1"><code class="language-plaintext highlighter-rouge">cabal install
--dependencies-only all</code> to
fail</a>.</li>
  <li><code class="language-plaintext highlighter-rouge">stack</code> doesn’t support Backpack. This is a <a href="https://github.com/commercialhaskell/stack/issues/2540">known
issue</a>
but limits adoption of Backpack in the ecosystem, which is a shame, since
ML-style module functors are a great way to reduce code duplication without
incurring any runtime performance overhead.</li>
  <li>Haddock doesn’t like <code class="language-plaintext highlighter-rouge">Mixins</code>, internal libraries and <code class="language-plaintext highlighter-rouge">Reexported-Modules</code>.
Basically, no decent API documentation of <code class="language-plaintext highlighter-rouge">xinu</code> can be generated. There are
<a href="https://github.com/haskell/haddock/issues/563">several</a> <a href="https://github.com/haskell/haddock/issues/958">related</a>
<a href="https://github.com/haskell/cabal/issues/4905">issues</a>
<a href="https://github.com/haskell/cabal/issues/6035">filed</a> upstream.</li>
  <li>Given <a href="https://hasufell.github.io/posts/2022-06-29-fixing-haskell-filepaths.html">the new <code class="language-plaintext highlighter-rouge">OsPath</code> family of
types</a>,
does it make sense to keep providing <code class="language-plaintext highlighter-rouge">FilePath</code>, <code class="language-plaintext highlighter-rouge">ByteString</code> and other
implementations?</li>
  <li>More tests to ensure exception handling is working as desired are needed. How
is this code different from the
<a href="https://hackage.haskell.org/package/unliftio"><code class="language-plaintext highlighter-rouge">unliftio</code></a> package?</li>
</ul>

<h2 id="conclusion">Conclusion</h2>
<p>Even though <code class="language-plaintext highlighter-rouge">xinu</code> is in no way meant to be as extensive as <code class="language-plaintext highlighter-rouge">unix</code>, it’s always
interesting to explore different approaches to a given problem, especially when
new functionality can be leveraged which wasn’t available when the original
solution was coded.</p>

<p>I’d love to hear your feedback. Would a library like <code class="language-plaintext highlighter-rouge">xinu</code> be of any use to
you? What’s missing? Head to the repository’s
<a href="https://github.com/NicolasT/xinu/discussions">Discussions</a> section!</p>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Development" /><summary type="html"><![CDATA[Thanks to its extensive FFI support, Haskell is a great platform to develop system applications. The `unix` library exposes a large set of POSIX APIs to Haskell code. However, it comes with some drawbacks. In this article, we'll dive into some of them, and look at some experiments in the `xinu` package to alleviate them.]]></summary></entry><entry><title type="html">A Git Branching Model for Releases with Generated Files</title><link href="https://nicolast.be/development/a-git-branching-model-for-releases-with-generated-files/" rel="alternate" type="text/html" title="A Git Branching Model for Releases with Generated Files" /><published>2017-02-28T20:27:00+01:00</published><updated>2017-02-28T20:27:00+01:00</updated><id>https://nicolast.be/development/a-git-branching-model-for-releases-with-generated-files</id><content type="html" xml:base="https://nicolast.be/development/a-git-branching-model-for-releases-with-generated-files/"><![CDATA[<p>Common wisdom dictates not to track generated files under source-control, which
is good practice: they clutter diffs and pull-requests, one needs to ensure
they’re always updated whenever changes are made,… Some platforms or
build-systems require generated files to be part of distributed packages though,
and keeping record of what gets delivered to users is of utmost importance. I
recently adopted a release/branching scheme to bridge this gap.</p>

<p>Platforms which require machine-generated files to be part of release packages
include the JavaScript ecosystem, where often packed and/or minified versions
of a set of source files (generated by tools like <a href="http://gulpjs.com">Gulp</a> or <a href="https://webpack.js.org">Webpack</a>) are
bundled in a distribution, or build systems like the <a href="https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html">Autotools</a> toolchain
(which brings us the familiar <code class="language-plaintext highlighter-rouge">./configure</code>, <code class="language-plaintext highlighter-rouge">make</code>, <code class="language-plaintext highlighter-rouge">make install</code> procedure)
where files like <code class="language-plaintext highlighter-rouge">configure</code> and <code class="language-plaintext highlighter-rouge">Makefile.in</code> are generated from
<code class="language-plaintext highlighter-rouge">configure.ac</code> and <code class="language-plaintext highlighter-rouge">Makefile.am</code> (and other auxiliary files).</p>

<p>The traditional approach to generate release (source) packages for such projects
is to generate the files on a developer machine, or in some <a href="https://en.wikipedia.org/wiki/Continuous_integration">CI</a> environment,
create a tarball, and store this artifact in a safe location: if one loses this
file, it may be impossible to ever recreate an exact copy of the original
release. This could e.g. be caused by later versions of the build tools to
generate slightly different results for the same input, or these tools using
‘external’ values (including time, randomness,…) during generation.</p>

<h2 id="first-attempt">First Attempt</h2>

<p>If the content of these release files is so precious, it makes sense to keep
them alongside something which is at least as valuable: the source repository of
the codebase, which contains the all code and its history. Given this, one can
come up with a scheme like the following:</p>

<style scoped=""> @import url("https://nicolast.be/assets/css/gitgraph-1.8.3.css"); </style>

<script src="https://nicolast.be/assets/js/gitgraph-1.8.3.min.js"></script>

<canvas id="gitGraph1"></canvas>
<script>
var master = new GitGraph({
  elementId: 'gitGraph1',
  template: 'metro',
  orientation: 'vertical',
  author: 'Nicolas T.',
  mode: 'extended',
}).branch('master');

master.commit('Initialize repository');
master.commit('Implement crazy feature');

master.commit('Set version number to 1.0.0');
master.commit({
  message: 'Import generated files into repository',
  tag: 'package-1.0.0',
  sha1: 'ec4e927',
  dotColor: '#f1c109',
});

master.commit({
  message: 'Revert "Import generated files into repository"',
  sha1: '12c6685',
});

master.commit('Set version number to 1.0.1-pre');
master.commit('Fix bug in crazy feature');
</script>

<p>Whilst this repository now contains a tag to a released tree which contains all
generated files, this has a major drawback: it also introduces a subsequent
commit (<code class="language-plaintext highlighter-rouge">12c6685</code>) which explicitly removes all these generated files again,
immediately following the commit in which they were added. Furthermore, this
requires one more commit to bump the version number. This clutters the
repository history.</p>

<h2 id="second-attempt">Second Attempt</h2>

<p>To overcome the sequence of <code class="language-plaintext highlighter-rouge">Import generated files</code> and subsequent revert
commits, we can try an alternative approach, stashing the imports away in
a branch:</p>

<canvas id="gitGraph2"></canvas>
<script>
var master = new GitGraph({
  elementId: 'gitGraph2',
  template: 'metro',
  orientation: 'vertical',
  author: 'Nicolas T.',
  mode: 'extended',
}).branch('master');

master.commit('Initialize repository');
master.commit('Implement crazy feature');

var release100 = master.branch('release-1.0.0');
release100.commit('Set version number to 1.0.0');
release100.commit({
  message: 'Import generated files into repository',
  tag: 'package-1.0.0',
  dotColor: '#f1c109',
});

master.commit('Set version number to 1.0.1-pre');
master.commit('Fix bug in crazy feature');
</script>

<p>Whilst this approach doesn’t require any revert of <code class="language-plaintext highlighter-rouge">Import generated files</code>
commits, it has another drawback: the relation between tags and branches is
lost. As an example, running a command like <code class="language-plaintext highlighter-rouge">git describe --tags</code> on the
<code class="language-plaintext highlighter-rouge">master</code> branch will never result in any release tags to be part of the output.</p>

<h2 id="final-approach">Final Approach</h2>

<p>Fixing the limitations of the previous approach is trivial: we simply need to
reinstate a connection between the release tag, and the development branch
(<code class="language-plaintext highlighter-rouge">master</code> in this example). How does one create a link between two branches? By
merging, of course! Here’s how this works:</p>

<canvas id="gitGraph3"></canvas>
<script>
var graph = new GitGraph({
  elementId: 'gitGraph3',
  template: 'metro',
  orientation: 'vertical',
  author: 'Nicolas T.',
  mode: 'extended',
});

var master = graph.branch('master');
master.commit('Initialize repository');
master.commit({
  message: 'Implement crazy feature',
  sha1: '43d6bf6',
});

var release100 = master.branch('release-1.0.0');
release100.commit('Set version number to 1.0.0');
release100.commit({
  message: 'Import generated files into repository',
  tag: 'package-1.0.0',
  dotColor: '#f1c109',
});

release100.merge(master, {
  message: 'Merge tag \'package-1.0.0\' into master',
  dotColor: '#a42315',
  sha1: '49e527e',
});

master.commit('Fix bug in crazy feature');
</script>

<p>As-is, this wouldn’t yield the desired result: the merge-commit in <code class="language-plaintext highlighter-rouge">49e527e</code>
would result in a tree which contains the generated files (in this specific
case the tree at <code class="language-plaintext highlighter-rouge">49e527e</code> would be equal to the <code class="language-plaintext highlighter-rouge">package-1.0.0</code> tree,
actually), which is clearly <em>not</em> what we aimed for. Instead, we should run
<code class="language-plaintext highlighter-rouge">git merge --no-commit</code> when merging <code class="language-plaintext highlighter-rouge">package-1.0.0</code> into <code class="language-plaintext highlighter-rouge">master</code>, undo all
the changes made in the <code class="language-plaintext highlighter-rouge">release-1.0.0</code> branch (i.e. remove the generated
files and reset the version number), only then to <code class="language-plaintext highlighter-rouge">git commit</code> the resulting
merge. Also note the <em>tag</em> (<code class="language-plaintext highlighter-rouge">package-1.0.0</code>) gets merged into <code class="language-plaintext highlighter-rouge">master</code>, not the
<code class="language-plaintext highlighter-rouge">release-1.0.0</code> branch (which makes only a difference when the tag is annotated,
of course).</p>

<p>Aside: you may have noticed the schema above no longer contains a <code class="language-plaintext highlighter-rouge">Set version
number to 1.0.1-pre</code> commit: this is no longer required, because one may opt to
bump the version number as part of the merge commit (<code class="language-plaintext highlighter-rouge">49e527e</code>). Some may
object against this approach and still keep a separate commit to increase the
value. Others may use some specific number for <code class="language-plaintext highlighter-rouge">master</code> versions. All of these
have pros and cons, pick one and be consistent.</p>

<p>Whilst the approach described above may seem laborious, note it’s fairly easy
to automate the workflow. Also, when using Autotools, it’s now possible to
release the output of <code class="language-plaintext highlighter-rouge">git archive</code> of a release tag, instead of relying on
<code class="language-plaintext highlighter-rouge">make dist</code>. Validating whether <code class="language-plaintext highlighter-rouge">make distcheck</code> passes, and asserting the
content of a resulting distribution package resembles an archive generated by
Git, e.g. as part of a CI pipeline, is of course good practice!</p>

<p>Finally, this approach interacts nicely with the <a href="https://web.archive.org/web/20170707112140/http://www.scality.com/blog/continuous-integration-faster-releases-high-quality/">GitWaterFlow</a> branching model
we presented at <a href="http://releng.polymtl.ca/RELENG2016/html/index.html">RELENG’16</a>, but more about that later!</p>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Development" /><summary type="html"><![CDATA[Version Control Systems and generated files don't play nice together, though for some projects such files need to be included in release packages. This article introduces a release and branching scheme to get the best of both worlds.]]></summary></entry><entry><title type="html">Hello, world!</title><link href="https://nicolast.be/various/hello-world/" rel="alternate" type="text/html" title="Hello, world!" /><published>2017-01-31T01:39:00+01:00</published><updated>2017-01-31T01:39:00+01:00</updated><id>https://nicolast.be/various/hello-world</id><content type="html" xml:base="https://nicolast.be/various/hello-world/"><![CDATA[<p>After many years of inactivity (the last entry on <a href="http://eikke.com">eikke.com</a>
was written in 2010…) I decided to pick up blogging again. Nothing here yet,
expect more content soon!</p>

<p>For the curious: the picture above comes from <strong>The C Programming Language,
First Edition</strong> by Kernighan &amp; Ritchie, published in 1978
(<a href="https://archive.org">archive.org</a> maintains a
<a href="https://archive.org/details/TheCProgrammingLanguageFirstEdition">copy</a>, page
6). Using “Hello, world” as a textbook example for programming languages goes
way back.</p>]]></content><author><name>Nicolas T.</name><email>ikke@nicolast.be</email></author><category term="Various" /><summary type="html"><![CDATA[Every blog needs a first post...]]></summary></entry></feed>