<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <div class="markdown-here-wrapper" data-md-url="Thunderbird"
      style="font-family: Ubuntu,Cantarell,Deja Vu Sans,sans-serif;
      font-size: 10pt;">
      <p style="margin: 0px 0px 1.2em ! important;">I was writing a
        simple utility and I decided to use regexps to parse filenames.
        (I know, now I have two problems :-) )</p>
      <p style="margin: 0px 0px 1.2em ! important;">I was surprised at
        how slow it ran, so I did a profiling build. The profiled code
        runs reasonably quickly, and is 7x faster, which makes it a bit
        hard to figure out where the slowdown is happening in the
        non-profiled code. I’m wondering if I’m doing something wrong,
        or if there’s a bug in <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">regex-tdfa</code>
        or in ghc.</p>
      <p style="margin: 0px 0px 1.2em ! important;">I’ve pared my code
        down to just the following:</p>
      <pre style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;font-size: 1em; line-height: 1.2em;margin: 1.2em 0px;"><code class="hljs language-Haskell" style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;white-space: pre; overflow: auto; border-radius: 3px; border: 1px solid rgb(204, 204, 204); padding: 0.5em 0.7em; display: block ! important;display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); background: rgb(248, 248, 248) none repeat scroll 0% 0%; -moz-text-size-adjust: none;"><span class="hljs-import"><span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">import</span> Text.Regex.TDFA <span class="hljs-container">((=~)</span>)</span>

<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">main</span> :: <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">IO</span> ()
<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">main</span> = <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">do</span>
    entries <- map parseFilename . lines <$> getContents
    <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">let</span> check (<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Right</span> (_, t)) = last t == '<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Z'</span>
        check _ = <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">False</span>
    print $ all check entries

<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">parseFilename</span> :: <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">String</span> -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Either</span> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">String</span> (<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">String</span>, <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">String</span>)
<span class="hljs-title" style="color: rgb(153, 0, 0); font-weight: bold;">parseFilename</span> fn = <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">case</span> (fn =~ pattern :: [[<span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">String</span>]]) <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">of</span>
    [[_, full, _, time]] -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Right</span> $ (full, time)
    _ -> <span class="hljs-type" style="color: rgb(68, 85, 136); font-weight: bold;">Left</span> fn
  <span class="hljs-keyword" style="color: rgb(51, 51, 51); font-weight: bold;">where</span>
    pattern =
        <span class="hljs-string" style="color: rgb(221, 17, 68);">"^\\./duplicity-(full|inc|new)(-signatures)?\\.\
        \([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]Z)\\."</span>
</code></pre>
      <p style="margin: 0px 0px 1.2em ! important;">The relevant part of
        my <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">.cabal</code>
        file looks like this:</p>
      <pre style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;font-size: 1em; line-height: 1.2em;margin: 1.2em 0px;"><code class="hljs language-Cabal" style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;white-space: pre; overflow: auto; border-radius: 3px; border: 1px solid rgb(204, 204, 204); padding: 0.5em 0.7em; display: block ! important;display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); background: rgb(248, 248, 248) none repeat scroll 0% 0%; -moz-text-size-adjust: none;">executable DuplicityAnalyzer
    main-is: DuplicityAnalyzer.hs
    build-depends:
        base >=4.6 && <4.11,
        regex-tdfa >= 1.0 && <1.3
    default-language: Haskell2010
    ghc-options: -Wall -rtsopts
</code></pre>
      <p style="margin: 0px 0px 1.2em ! important;">To run the
        profiling, I do:</p>
      <pre style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;font-size: 1em; line-height: 1.2em;margin: 1.2em 0px;"><code class="hljs language-Bash" style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;white-space: pre; overflow: auto; border-radius: 3px; border: 1px solid rgb(204, 204, 204); padding: 0.5em 0.7em; display: block ! important;display: block; overflow-x: auto; padding: 0.5em; color: rgb(51, 51, 51); background: rgb(248, 248, 248) none repeat scroll 0% 0%; -moz-text-size-adjust: none;">cabal clean
cabal configure --enable-profiling
cabal build
dist/build/DuplicityAnalyzer/DuplicityAnalyzer <names.in +RTS -sprofiling-summary.out -p
</code></pre>
      <p style="margin: 0px 0px 1.2em ! important;">The <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">MUT</code>
        time in the non-profiling build is 7x bigger, and the <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">%GC</code>
        time goes from 8% to 21%. I’ve put the actual output in a <a
href="https://gist.github.com/neilmayhew/247a30738c0e294902e7c2830ca2c6f5">gist</a>.
        I’ve also put my test input file there, in case anyone wants to
        try this themselves.</p>
      <p style="margin: 0px 0px 1.2em ! important;">I’ve done my testing
        with NixOS (ghc 8.0.2) and Debian with the Haskell Platform (ghc
        8.2.1) and the results are basically the same. I even tried
        using Docker containers with Debian Jessie and Debian Stretch,
        just to eliminate any OS influence, and the results are still
        the same. I’ve tried it on an i5-2500K, i5-3317U and Xeon
        E5-1620.</p>
      <p style="margin: 0px 0px 1.2em ! important;">I also wrote a dummy
        implementation of <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">=~</code>
        that ignores the regex pattern and does a hard-coded manual
        parse, and that produces times just slightly better than the
        profiled ones. So I don’t think there’s a problem in my outer
        code that uses <code style="font-size: 0.95em; font-family: Consolas,Inconsolata,Deja Vu Sans Mono,Courier,monospace;margin: 0px 0.15em; padding: 0px 0.3em; white-space: pre-wrap; border: 1px solid rgb(234, 234, 234); background-color: rgb(248, 248, 248); border-radius: 3px; display: inline;">=~</code>.</p>
      <div
title="MDH:SSB3YXMgd3JpdGluZyBhIHNpbXBsZSB1dGlsaXR5IGFuZCBJIGRlY2lkZWQgdG8gdXNlIHJlZ2V4cHMgdG8gcGFyc2UgZmlsZW5hbWVzLiAoSSBrbm93LCBub3cgSSBoYXZlIHR3byBwcm9ibGVtcyA6
LSkgKTxicj48YnI+SSB3YXMgc3VycHJpc2VkIGF0IGhvdyBzbG93IGl0IHJhbiwgc28gSSBkaWQg
YSBwcm9maWxpbmcgYnVpbGQuIFRoZSBwcm9maWxlZCBjb2RlIHJ1bnMgcmVhc29uYWJseSBxdWlj
a2x5LCBhbmQgaXMgN3ggZmFzdGVyLCB3aGljaCBtYWtlcyBpdCBhIGJpdCBoYXJkIHRvIGZpZ3Vy
ZSBvdXQgd2hlcmUgdGhlIHNsb3dkb3duIGlzIGhhcHBlbmluZyBpbiB0aGUgbm9uLXByb2ZpbGVk
IGNvZGUuIEknbSB3b25kZXJpbmcgaWYgSSdtIGRvaW5nIHNvbWV0aGluZyB3cm9uZywgb3IgaWYg
dGhlcmUncyBhIGJ1ZyBpbiBgcmVnZXgtdGRmYWAgb3IgaW4gZ2hjLjxicj48YnI+SSd2ZSBwYXJl
ZCBteSBjb2RlIGRvd24gdG8ganVzdCB0aGUgZm9sbG93aW5nOjxicj48YnI+YGBgSGFza2VsbDxi
cj5pbXBvcnQgVGV4dC5SZWdleC5UREZBICgoPX4pKTxicj48YnI+bWFpbiA6OiBJTyAoKTxicj5t
YWluID0gZG88YnI+wqDCoMKgIGVudHJpZXMgJmx0Oy0gbWFwIHBhcnNlRmlsZW5hbWUgLiBsaW5l
cyAmbHQ7JCZndDsgZ2V0Q29udGVudHM8YnI+wqDCoMKgIGxldCBjaGVjayAoUmlnaHQgKF8sIHQp
KSA9IGxhc3QgdCA9PSAnWic8YnI+wqDCoMKgwqDCoMKgwqAgY2hlY2sgXyA9IEZhbHNlPGJyPsKg
wqDCoCBwcmludCAkIGFsbCBjaGVjayBlbnRyaWVzPGJyPjxicj5wYXJzZUZpbGVuYW1lIDo6IFN0
cmluZyAtJmd0OyBFaXRoZXIgU3RyaW5nIChTdHJpbmcsIFN0cmluZyk8YnI+cGFyc2VGaWxlbmFt
ZSBmbiA9IGNhc2UgKGZuID1+IHBhdHRlcm4gOjogW1tTdHJpbmddXSkgb2Y8YnI+wqDCoMKgIFtb
XywgZnVsbCwgXywgdGltZV1dIC0mZ3Q7IFJpZ2h0ICQgKGZ1bGwsIHRpbWUpPGJyPsKgwqDCoCBf
IC0mZ3Q7IExlZnQgZm48YnI+wqAgd2hlcmU8YnI+wqDCoMKgIHBhdHRlcm4gPTxicj7CoMKgwqDC
oMKgwqDCoCAiXlxcLi9kdXBsaWNpdHktKGZ1bGx8aW5jfG5ldykoLXNpZ25hdHVyZXMpP1xcLlw8
YnI+wqDCoMKgwqDCoMKgwqAgXChbMC05XVswLTldWzAtOV1bMC05XVswLTldWzAtOV1bMC05XVsw
LTldVFswLTldWzAtOV1bMC05XVswLTldWzAtOV1bMC05XVopXFwuIjxicj5gYGA8YnI+PGJyPlRo
ZSByZWxldmFudCBwYXJ0IG9mIG15IGAuY2FiYWxgIGZpbGUgbG9va3MgbGlrZSB0aGlzOjxicj48
YnI+YGBgQ2FiYWw8YnI+ZXhlY3V0YWJsZSBEdXBsaWNpdHlBbmFseXplcjxicj7CoMKgwqAgbWFp
bi1pczogRHVwbGljaXR5QW5hbHl6ZXIuaHM8YnI+wqDCoMKgIGJ1aWxkLWRlcGVuZHM6PGJyPsKg
wqDCoMKgwqDCoMKgIGJhc2UgJmd0Oz00LjYgJmFtcDsmYW1wOyAmbHQ7NC4xMSw8YnI+wqDCoMKg
wqDCoMKgwqAgcmVnZXgtdGRmYSAmZ3Q7PSAxLjAgJmFtcDsmYW1wOyAmbHQ7MS4zPGJyPsKgwqDC
oCBkZWZhdWx0LWxhbmd1YWdlOiBIYXNrZWxsMjAxMDxicj7CoMKgwqAgZ2hjLW9wdGlvbnM6IC1X
YWxsIC1ydHNvcHRzPGJyPmBgYDxicj48YnI+VG8gcnVuIHRoZSBwcm9maWxpbmcsIEkgZG86PGJy
Pjxicj5gYGBCYXNoPGJyPmNhYmFsIGNsZWFuPGJyPmNhYmFsIGNvbmZpZ3VyZSAtLWVuYWJsZS1w
cm9maWxpbmc8YnI+Y2FiYWwgYnVpbGQ8YnI+ZGlzdC9idWlsZC9EdXBsaWNpdHlBbmFseXplci9E
dXBsaWNpdHlBbmFseXplciAmbHQ7bmFtZXMuaW4gK1JUUyAtc3Byb2ZpbGluZy1zdW1tYXJ5Lm91
dCAtcDxicj5gYGA8YnI+PGJyPlRoZSBgTVVUYCB0aW1lIGluIHRoZSBub24tcHJvZmlsaW5nIGJ1
aWxkIGlzIDd4IGJpZ2dlciwgYW5kIHRoZSBgJUdDYCB0aW1lIGdvZXMgZnJvbSA4JSB0byAyMSUu
IEkndmUgcHV0IHRoZSBhY3R1YWwgb3V0cHV0IGluIGEgW2dpc3RdKGh0dHBzOi8vZ2lzdC5naXRo
dWIuY29tL25laWxtYXloZXcvMjQ3YTMwNzM4YzBlMjk0OTAyZTdjMjgzMGNhMmM2ZjUpLiBJJ3Zl
IGFsc28gcHV0IG15IHRlc3QgaW5wdXQgZmlsZSB0aGVyZSwgaW4gY2FzZSBhbnlvbmUgd2FudHMg
dG8gdHJ5IHRoaXMgdGhlbXNlbHZlcy48YnI+PGJyPkkndmUgZG9uZSBteSB0ZXN0aW5nIHdpdGgg
Tml4T1MgKGdoYyA4LjAuMikgYW5kIERlYmlhbiB3aXRoIHRoZSBIYXNrZWxsIFBsYXRmb3JtIChn
aGMgOC4yLjEpIGFuZCB0aGUgcmVzdWx0cyBhcmUgYmFzaWNhbGx5IHRoZSBzYW1lLiBJIGV2ZW4g
dHJpZWQgdXNpbmcgRG9ja2VyIGNvbnRhaW5lcnMgd2l0aCBEZWJpYW4gSmVzc2llIGFuZCBEZWJp
YW4gU3RyZXRjaCwganVzdCB0byBlbGltaW5hdGUgYW55IE9TIGluZmx1ZW5jZSwgYW5kIHRoZSBy
ZXN1bHRzIGFyZSBzdGlsbCB0aGUgc2FtZS4gSSd2ZSB0cmllZCBpdCBvbiBhbiBpNS0yNTAwSywg
aTUtMzMxN1UgYW5kIFhlb24gRTUtMTYyMC48YnI+PGJyPkkgYWxzbyB3cm90ZSBhIGR1bW15IGlt
cGxlbWVudGF0aW9uIG9mIGA9fmAgdGhhdCBpZ25vcmVzIHRoZSByZWdleCBwYXR0ZXJuIGFuZCBk
b2VzIGEgaGFyZC1jb2RlZCBtYW51YWwgcGFyc2UsIGFuZCB0aGF0IHByb2R1Y2VzIHRpbWVzIGp1
c3Qgc2xpZ2h0bHkgYmV0dGVyIHRoYW4gdGhlIHByb2ZpbGVkIG9uZXMuIFNvIEkgZG9uJ3QgdGhp
bmsgdGhlcmUncyBhIHByb2JsZW0gaW4gbXkgb3V0ZXIgY29kZSB0aGF0IHVzZXMgYD1+YC48YnI+"
style="height:0;width:0;max-height:0;max-width:0;overflow:hidden;font-size:0em;padding:0;margin:0;">​</div>
    </div>
  </body>
</html>