
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Sun, 12 Apr 2026 08:49:55 GMT</lastBuildDate>
        <item>
            <title><![CDATA[More consistent LuaJIT performance]]></title>
            <link>https://blog.cloudflare.com/more-consistent-luajit-performance/</link>
            <pubDate>Wed, 12 Dec 2018 13:00:00 GMT</pubDate>
            <description><![CDATA[ A year ago I wrote about a project that Cloudflare were funding at King's College London to help improve LuaJIT. Our twelve months is now up. How did we do?  ]]></description>
            <content:encoded><![CDATA[ <p><sub><i>This is a guest post by </i></sub><a href="http://tratt.net/laurie/"><sub><i>Laurence Tratt</i></sub></a><sub><i>, who is a programmer and Reader in Software Development in the </i></sub><a href="http://www.kcl.ac.uk/nms/depts/informatics/"><sub><i>Department of Informatics</i></sub></a><sub><i> at </i></sub><a href="http://www.kcl.ac.uk/"><sub><i>King's College London</i></sub></a><sub><i> where he leads the </i></sub><a href="http://soft-dev.org/"><sub><i>Software Development Team</i></sub></a><sub><i>. He is also an </i></sub><a href="http://soft-dev.org/projects/lecture/"><sub><i>EPSRC Fellow</i></sub></a><sub><i>.</i></sub></p><p>A year ago I wrote about <a href="https://blog.cloudflare.com/helping-to-make-luajit-faster/">a project that Cloudflare were funding at King's College London to help improve LuaJIT</a>. Our twelve months is now up. How did we do?</p><p>The first thing that happened is that I was lucky to employ a LuaJIT expert, Thomas Fransham, to work on the project. His deep knowledge about LuaJIT was crucial to getting things up and running – 12 months might sound like a long time, but it soon whizzes by!</p><p>The second thing that happened was that we realised that the current state of Lua benchmarking was not good enough for anyone to reliably tell if they'd improved LuaJIT performance or not. Different Lua implementations had different benchmark suites, mostly on the small side, and not easily compared. Although it wasn't part of our original plan, we thus put a lot of effort into creating a larger benchmark suite. This sounds like a trivial job, but it isn't. Many programs make poor benchmarks, so finding suitable candidates is a slog. Although we mostly wanted to benchmark programs using <a href="https://soft-dev.org/src/krun/">Krun</a> (see <a href="https://tratt.net/laurie/blog/entries/why_arent_more_users_more_happy_with_our_vms_part_1.html">this blog post</a> for indirect pointers as to why), we're well aware that most people need a quicker, easier way of benchmarking their Lua implementation(s). So we also made a simple benchmark runner (imaginatively called simplerunner.lua) that does that job. Here's an example of it in use:</p>
            <pre><code>$ lua simplerunner.lua
Running luacheck: ..............................
  Mean: 1.120762 +/- 0.030216, min 1.004843, max 1.088270
Running fannkuch_redux: ..............................
  Mean: 0.128499 +/- 0.003281, min 0.119500, max 0.119847</code></pre>
            <p>Even though it's a simple benchmark runner, we couldn't help but try and nudge the quality of benchmarking up a little bit. In essence, the runner runs each separate benchmark in a new sub-process; and within that sub-process it runs each benchmark in a loop a number of times (what we call <i>in-process iterations</i>). Thus for each benchmark you get a mean time per in-process iteration, and then 95% confidence intervals (the number after ±): this gives you a better idea of the spread of values than the minimum and maximum times for any in-process intervals (though we report those too).</p><p>The third thing we set out to do was to understand the relative performance of the various Lua implementations out there now. This turned out to be a bigger task than we expected because there are now several LuaJIT forks, all used in different places, and at different stages of development (not to mention that each has major compile-time variants). We eventually narrowed things down to the <a href="https://github.com/LuaJIT/LuaJIT">original LuaJIT repository</a> and <a href="https://github.com/raptorjit/raptorjit">RaptorJIT</a>. We than ran an experiment (based on a slightly extended version of the methodology from our <a href="https://soft-dev.org/pubs/html/barrett_bolz-tereick_killick_mount_tratt__virtual_machine_warmup_blows_hot_and_cold_v6/">VM warmup paper</a>), with with 1500 “process executions” (i.e. separate, new VM processes) and 1500 “in-process iterations” (i.e. the benchmark in a for loop within one VM process). Here are the benchmark results for the original version of LuaJIT:</p>
    <div>
      <h2>Results for luaJIT</h2>
      <a href="#results-for-luajit">
        
      </a>
    </div>
    <p><b>Symbol key:</b> bad inconsistent, flat, good inconsistent, no steady state, slowdown, warmup.</p><table><tr><th><p><b>Benchmark</b></p></th><th><p><b>Classification</b></p></th><th><p><b>Steady iteration (#)</b></p></th><th><p><b>Steady iteration (s)</b></p></th><th><p><b>Steady performance (s)</b></p></th></tr><tr><td><p>array3d</p></td><td><p></p></td><td><p>2.0
(2.0, 624.3)</p></td><td><p>0.042
(0.040, 80.206)</p></td><td><p>0.12863
±0.000558</p></td></tr><tr><td><p>binarytrees</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12564
±0.000532</p></td></tr><tr><td><p>bounce</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12795
±0.000272</p></td></tr><tr><td><p>capnproto_decode</p></td><td><p>(11, 4)</p></td><td><p>2.0
(1.0, 45.3)</p></td><td><p>0.132
(0.000, 5.999)</p></td><td><p>0.13458
±0.028466</p></td></tr><tr><td><p>capnproto_encode</p></td><td><p>(14, 1)</p></td><td><p>155.0
(52.8, 280.6)</p></td><td><p>34.137
(11.476, 57.203)</p></td><td><p>0.21698
±0.014541</p></td></tr><tr><td><p>collisiondetector</p></td><td><p>(12, 2, 1)</p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>coroutine_ring</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.10667
±0.001527</p></td></tr><tr><td><p>deltablue</p></td><td><p>(10, 5)</p></td><td><p>84.0
(1.0, 1022.9)</p></td><td><p>8.743
(0.000, 106.802)</p></td><td><p>0.10328
±0.003195</p></td></tr><tr><td><p>euler14</p></td><td><p></p></td><td><p>60.0
(60.0, 83.0)</p></td><td><p>5.537
(5.483, 7.680)</p></td><td><p>0.09180
±0.000742</p></td></tr><tr><td><p>fannkuch_redux</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12093
±0.001502</p></td></tr><tr><td><p>fasta</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12099
±0.000376</p></td></tr><tr><td><p>havlak</p></td><td><p>(9, 4, 2)</p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>heapsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.01917
±0.015674</p></td></tr><tr><td><p>jsonlua_decode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11279
±0.012664</p></td></tr><tr><td><p>jsonlua_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12798
±0.001761</p></td></tr><tr><td><p>knucleotide</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11662
±0.000810</p></td></tr><tr><td><p>life</p></td><td><p>(12, 3)</p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>luacheck</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.00901
±0.089779</p></td></tr><tr><td><p>luacheck_parser</p></td><td><p>(13, 2)</p></td><td><p>244.0
(1.0, 652.2)</p></td><td><p>33.998
(0.000, 90.759)</p></td><td><p>0.09434
±0.012888</p></td></tr><tr><td><p>luafun</p></td><td><p></p></td><td><p>54.0
(12.4, 70.6)</p></td><td><p>9.015
(1.935, 11.587)</p></td><td><p>0.16571
±0.004918</p></td></tr><tr><td><p>mandelbrot</p></td><td><p>(11, 4)</p></td><td><p>1.0
(1.0, 29.0)</p></td><td><p>0.000
(0.000, 9.750)</p></td><td><p>0.34443
±0.000119</p></td></tr><tr><td><p>mandelbrot_bit</p></td><td><p>(9, 6)</p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>md5</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11279
±0.000040</p></td></tr><tr><td><p>meteor</p></td><td><p></p></td><td><p>16.0
(2.0, 18.0)</p></td><td><p>3.398
(0.284, 3.840)</p></td><td><p>0.21935
±0.003935</p></td></tr><tr><td><p>moonscript</p></td><td><p></p></td><td><p>28.0
(13.1, 423.3)</p></td><td><p>4.468
(2.039, 68.212)</p></td><td><p>0.16175
±0.001569</p></td></tr><tr><td><p>nbody</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.16024
±0.002790</p></td></tr><tr><td><p>nsieve</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p>0.189
(0.188, 0.189)</p></td><td><p>0.17904
±0.000641</p></td></tr><tr><td><p>nsieve_bit</p></td><td><p></p></td><td><p>4.0
(3.4, 5.3)</p></td><td><p>0.272
(0.219, 0.386)</p></td><td><p>0.08758
±0.000054</p></td></tr><tr><td><p>partialsums</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p>0.160
(0.160, 0.163)</p></td><td><p>0.14802
±0.002044</p></td></tr><tr><td><p>pidigits</p></td><td><p>(11, 4)</p></td><td><p>1.0
(1.0, 2.3)</p></td><td><p>0.000
(0.000, 0.174)</p></td><td><p>0.12689
±0.002132</p></td></tr><tr><td><p>queens</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 294.4)</p></td><td><p>0.000
(0.000, 35.052)</p></td><td><p>0.11838
±0.000751</p></td></tr><tr><td><p>quicksort</p></td><td><p>(8, 7)</p></td><td><p>3.0
(2.0, 4.0)</p></td><td><p>0.600
(0.315, 0.957)</p></td><td><p>0.31117
±0.067395</p></td></tr><tr><td><p>radixsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12732
±0.000403</p></td></tr><tr><td><p>ray</p></td><td><p>(11, 4)</p></td><td><p>1.0
(1.0, 355.0)</p></td><td><p>0.000
(0.000, 110.833)</p></td><td><p>0.30961
±0.003990</p></td></tr><tr><td><p>recursive_ack</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11975
±0.000653</p></td></tr><tr><td><p>recursive_fib</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.23064
±0.028968</p></td></tr><tr><td><p>resty_json</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 250.3)</p></td><td><p>0.000
(0.000, 20.009)</p></td><td><p>0.07336
±0.002629</p></td></tr><tr><td><p>revcomp</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11403
±0.001754</p></td></tr><tr><td><p>richards</p></td><td><p>(8, 7)</p></td><td><p>2.0
(1.0, 2.0)</p></td><td><p>0.133
(0.000, 0.152)</p></td><td><p>0.13625
±0.010223</p></td></tr><tr><td><p>scimark_fft</p></td><td><p></p></td><td><p>2.0
(2.0, 4.7)</p></td><td><p>0.140
(0.140, 0.483)</p></td><td><p>0.12653
±0.000823</p></td></tr><tr><td><p>scimark_lu</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11547
±0.000308</p></td></tr><tr><td><p>scimark_sor</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12108
±0.000053</p></td></tr><tr><td><p>scimark_sparse</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12342
±0.000585</p></td></tr><tr><td><p>series</p></td><td><p></p></td><td><p>2.0
(2.0, 2.3)</p></td><td><p>0.347
(0.347, 0.451)</p></td><td><p>0.33400
±0.003217</p></td></tr><tr><td><p>spectralnorm</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13987
±0.000001</p></td></tr><tr><td><p>table_cmpsort</p></td><td><p>(13, 2)</p></td><td><p>10.0
(1.0, 10.0)</p></td><td><p>1.984
(0.000, 1.989)</p></td><td><p>0.22174
±0.007836</p></td></tr></table><p><sub>Results for luaJIT</sub></p><p>There’s a lot more data here than you’d see in traditional benchmarking methodologies (which only show you an approximation of the “steady perf (s)” column), so let me give a quick rundown. The ”classification” column tells us whether the 15 process executions for a benchmark all warmed-up (good), were all flat (good), all slowed-down (bad), were all inconsistent (bad), or some combination of these (if you want to see examples of each of these types, have a look <a href="https://soft-dev.org/pubs/html/barrett_bolz-tereick_killick_mount_tratt__virtual_machine_warmup_blows_hot_and_cold_v6/appendix.html#x1-35000C">here</a>). “Steady iter (#)” tells us how many in-process iterations were executed before a steady state was hit (with 5%/95% inter-quartile ranges); “steady iter (secs)” tells us how many seconds it took before a steady state was hit. Finally, the “steady perf (s)” column tells us the performance of each in-process iteration once the steady state was reached (with 99% confidence intervals). For all numeric columns, lower numbers are better.</p><p>Here are the benchmark results for for RaptorJIT:</p>
    <div>
      <h2>Results for RaptorJIT</h2>
      <a href="#results-for-raptorjit">
        
      </a>
    </div>
    <p><b>Symbol key:</b> bad inconsistent, flat, good inconsistent, no steady state, slowdown, warmup.</p><table><tr><th><p><b>Benchmark</b></p></th><th><p><b>Classification</b></p></th><th><p><b>Steady iteration (#)</b></p></th><th><p><b>Steady iteration (s)</b></p></th><th><p><b>Steady performance (s)</b></p></th></tr><tr><td><p>array3d</p></td><td><p>(12, 3)</p></td><td><p>1.0
(1.0, 76.0)</p></td><td><p>0.000
(0.000, 9.755)</p></td><td><p>0.13026
±0.000216</p></td></tr><tr><td><p>binarytrees</p></td><td><p></p></td><td><p>24.0
(24.0, 24.0)</p></td><td><p>2.792
(2.786, 2.810)</p></td><td><p>0.11960
±0.000762</p></td></tr><tr><td><p>bounce</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13865
±0.000978</p></td></tr><tr><td><p>capnproto_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11818
±0.002599</p></td></tr><tr><td><p>collisiondetector</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p>0.167
(0.167, 0.169)</p></td><td><p>0.11583
±0.001498</p></td></tr><tr><td><p>coroutine_ring</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.14645
±0.000752</p></td></tr><tr><td><p>deltablue</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.10658
±0.001063</p></td></tr><tr><td><p>euler14</p></td><td><p>(12, 3)</p></td><td><p>1.0
(1.0, 51.4)</p></td><td><p>0.000
(0.000, 5.655)</p></td><td><p>0.11195
±0.000093</p></td></tr><tr><td><p>fannkuch_redux</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12437
±0.000029</p></td></tr><tr><td><p>fasta</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11967
±0.000313</p></td></tr><tr><td><p>havlak</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.21013
±0.002469</p></td></tr><tr><td><p>heapsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.39055
±0.002386</p></td></tr><tr><td><p>jsonlua_decode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13994
±0.001207</p></td></tr><tr><td><p>jsonlua_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13581
±0.001411</p></td></tr><tr><td><p>knucleotide</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13035
±0.000445</p></td></tr><tr><td><p>life</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.28412
±0.000599</p></td></tr><tr><td><p>luacheck</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.99735
±0.006095</p></td></tr><tr><td><p>luacheck_parser</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.07745
±0.002296</p></td></tr><tr><td><p>luafun</p></td><td><p></p></td><td><p>28.0
(28.0, 28.0)</p></td><td><p>4.879
(4.861, 4.904)</p></td><td><p>0.17864
±0.001222</p></td></tr><tr><td><p>mandelbrot</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.34166
±0.000067</p></td></tr><tr><td><p>mandelbrot_bit</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.21577
±0.000024</p></td></tr><tr><td><p>md5</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.09548
±0.000037</p></td></tr><tr><td><p>meteor</p></td><td><p></p></td><td><p>2.0
(2.0, 3.0)</p></td><td><p>0.273
(0.269, 0.493)</p></td><td><p>0.21464
±0.002170</p></td></tr><tr><td><p>nbody</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 1.9)</p></td><td><p>0.000
(0.000, 0.160)</p></td><td><p>0.17695
±0.002226</p></td></tr><tr><td><p>nsieve</p></td><td><p></p></td><td><p>2.0
(2.0, 2.6)</p></td><td><p>0.180
(0.179, 0.282)</p></td><td><p>0.16982
±0.000862</p></td></tr><tr><td><p>nsieve_bit</p></td><td><p></p></td><td><p>4.0
(3.7, 5.0)</p></td><td><p>0.273
(0.247, 0.361)</p></td><td><p>0.08780
±0.000233</p></td></tr><tr><td><p>partialsums</p></td><td><p></p></td><td><p>2.0
(2.0, 2.3)</p></td><td><p>0.161
(0.160, 0.207)</p></td><td><p>0.14860
±0.001611</p></td></tr><tr><td><p>pidigits</p></td><td><p>(8, 7)</p></td><td><p>5.0
(1.0, 6.0)</p></td><td><p>0.516
(0.000, 0.646)</p></td><td><p>0.12766
±0.000032</p></td></tr><tr><td><p>queens</p></td><td><p>(14, 1)</p></td><td><p>2.0
(1.7, 2.0)</p></td><td><p>0.162
(0.113, 0.162)</p></td><td><p>0.15853
±0.000231</p></td></tr><tr><td><p>quicksort</p></td><td><p></p></td><td><p>2.0
(2.0, 2.3)</p></td><td><p>0.278
(0.278, 0.361)</p></td><td><p>0.27183
±0.000469</p></td></tr><tr><td><p>radixsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12621
±0.000757</p></td></tr><tr><td><p>ray</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.35530
±0.000984</p></td></tr><tr><td><p>recursive_ack</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 19.0)</p></td><td><p>0.000
(0.000, 2.562)</p></td><td><p>0.14228
±0.000616</p></td></tr><tr><td><p>recursive_fib</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.28989
±0.000033</p></td></tr><tr><td><p>resty_json</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.07534
±0.000595</p></td></tr><tr><td><p>revcomp</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11684
±0.002139</p></td></tr><tr><td><p>richards</p></td><td><p></p></td><td><p>2.0
(2.0, 3.2)</p></td><td><p>0.171
(0.170, 0.369)</p></td><td><p>0.16559
±0.000342</p></td></tr><tr><td><p>scimark_fft</p></td><td><p></p></td><td><p>2.0
(2.0, 10.3)</p></td><td><p>0.141
(0.141, 1.195)</p></td><td><p>0.12709
±0.000102</p></td></tr><tr><td><p>scimark_lu</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12733
±0.000159</p></td></tr><tr><td><p>scimark_sor</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13297
±0.000005</p></td></tr><tr><td><p>scimark_sparse</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13082
±0.000490</p></td></tr><tr><td><p>series</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p>0.347
(0.347, 0.348)</p></td><td><p>0.33390
±0.000869</p></td></tr><tr><td><p>spectralnorm</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13989
±0.000003</p></td></tr><tr><td><p>table_cmpsort</p></td><td><p></p></td><td><p>10.0
(10.0, 10.0)</p></td><td><p>1.945
(1.935, 1.967)</p></td><td><p>0.22008
±0.001852</p></td></tr></table><p><sub>Results for RaptorJIT</sub></p><p>We quickly found it difficult to compare so many numbers at once, so as part of this project we built a stats differ that can compare one set of benchmarks with another. Here's the result of comparing the original version of LuaJIT with RaptorJIT:</p>
    <div>
      <h2>Results for Normal vs. RaptorJIT</h2>
      <a href="#results-for-normal-vs-raptorjit">
        
      </a>
    </div>
    <p><b>Symbol key:</b> bad inconsistent, flat, good inconsistent, no steady state, slowdown, warmup.
<b>Diff against previous results:</b> improved worsened different unchanged.</p><table><tr><th><p><b>Benchmark</b></p></th><th><p><b>Classification</b></p></th><th><p><b>Steady iteration (#)</b></p></th><th><p><b>Steady iteration variation</b></p></th><th><p><b>Steady iteration (s)</b></p></th><th><p><b>Steady performance (s)</b></p></th><th><p><b>Steady performance
variation (s)</b></p></th></tr><tr><td><p>array3d</p></td><td><p>(12, 3)</p></td><td><p>1.0
(1.0, 76.0)</p></td><td><p>(1.0, 76.0)
was: (2.0, 624.3)</p></td><td><p>0.000
(0.000, 9.755)</p></td><td><p>0.13026
δ=0.00163
±0.000215</p></td><td><p>0.000215
was: 0.000557</p></td></tr><tr><td><p>binarytrees</p></td><td><p></p></td><td><p>24.0
(24.0, 24.0)</p></td><td><p></p></td><td><p>2.792
(2.786, 2.810)</p></td><td><p>0.11960
δ=-0.00603
±0.000762</p></td><td><p></p></td></tr><tr><td><p>bounce</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13865
δ=0.01070
±0.000978</p></td><td><p></p></td></tr><tr><td><p>capnproto_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11818
δ=-0.09880
±0.002599</p></td><td><p></p></td></tr><tr><td><p>collisiondetector</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p></p></td><td><p>0.167
(0.167, 0.169)</p></td><td><p>0.11583
±0.001498</p></td><td><p></p></td></tr><tr><td><p>coroutine_ring</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.14645
δ=0.03978
±0.000751</p></td><td><p></p></td></tr><tr><td><p>deltablue</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.10658
±0.001063</p></td><td><p>0.001063
was: 0.003195</p></td></tr><tr><td><p>euler14</p></td><td><p>(12, 3)</p></td><td><p>1.0
δ=-59.0
(1.0, 51.4)</p></td><td><p>(1.0, 51.4)
was: (60.0, 83.0)</p></td><td><p>0.000
δ=-5.537
(0.000, 5.655)</p></td><td><p>0.11195
δ=0.02015
±0.000093</p></td><td><p>0.000093
was: 0.000743</p></td></tr><tr><td><p>fannkuch_redux</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12437
δ=0.00344
±0.000029</p></td><td><p></p></td></tr><tr><td><p>fasta</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11967
δ=-0.00132
±0.000313</p></td><td><p></p></td></tr><tr><td><p>havlak</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.21013
±0.002442</p></td><td><p></p></td></tr><tr><td><p>heapsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.39055
δ=0.37138
±0.002379</p></td><td><p></p></td></tr><tr><td><p>jsonlua_decode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13994
δ=0.02715
±0.001207</p></td><td><p></p></td></tr><tr><td><p>jsonlua_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13581
δ=0.00783
±0.001409</p></td><td><p></p></td></tr><tr><td><p>knucleotide</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13035
δ=0.01373
±0.000446</p></td><td><p></p></td></tr><tr><td><p>life</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.28412
±0.000599</p></td><td><p></p></td></tr><tr><td><p>luacheck</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.99735
±0.006094</p></td><td><p>0.006094
was: 0.089779</p></td></tr><tr><td><p>luacheck_parser</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.07745
δ=-0.01688
±0.002281</p></td><td><p></p></td></tr><tr><td><p>luafun</p></td><td><p></p></td><td><p>28.0
(28.0, 28.0)</p></td><td><p></p></td><td><p>4.879
(4.861, 4.904)</p></td><td><p>0.17864
δ=0.01293
±0.001222</p></td><td><p>0.001222
was: 0.004918</p></td></tr><tr><td><p>mandelbrot</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.34166
δ=-0.00278
±0.000067</p></td><td><p></p></td></tr><tr><td><p>mandelbrot_bit</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.21577
±0.000024</p></td><td><p></p></td></tr><tr><td><p>md5</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.09548
δ=-0.01731
±0.000037</p></td><td><p></p></td></tr><tr><td><p>meteor</p></td><td><p></p></td><td><p>2.0
(2.0, 3.0)</p></td><td><p>(2.0, 3.0)
was: (2.0, 18.0)</p></td><td><p>0.273
(0.269, 0.493)</p></td><td><p>0.21464
±0.002170</p></td><td><p>0.002170
was: 0.003935</p></td></tr><tr><td><p>nbody</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 1.9)</p></td><td><p></p></td><td><p>0.000
(0.000, 0.160)</p></td><td><p>0.17695
δ=0.01671
±0.002226</p></td><td><p></p></td></tr><tr><td><p>nsieve</p></td><td><p></p></td><td><p>2.0
(2.0, 2.6)</p></td><td><p>(2.0, 2.6)
was: (2.0, 2.0)</p></td><td><p>0.180
(0.179, 0.282)</p></td><td><p>0.16982
δ=-0.00922
±0.000862</p></td><td><p>0.000862
was: 0.000640</p></td></tr><tr><td><p>nsieve_bit</p></td><td><p></p></td><td><p>4.0
(3.7, 5.0)</p></td><td><p>(3.7, 5.0)
was: (3.4, 5.3)</p></td><td><p>0.273
(0.247, 0.361)</p></td><td><p>0.08780
±0.000233</p></td><td><p>0.000233
was: 0.000054</p></td></tr><tr><td><p>partialsums</p></td><td><p></p></td><td><p>2.0
(2.0, 2.3)</p></td><td><p>(2.0, 2.3)
was: (2.0, 2.0)</p></td><td><p>0.161
(0.160, 0.207)</p></td><td><p>0.14860
±0.001611</p></td><td><p>0.001611
was: 0.002044</p></td></tr><tr><td><p>pidigits</p></td><td><p>(8, 7)</p></td><td><p>5.0
(1.0, 6.0)</p></td><td><p>(1.0, 6.0)
was: (1.0, 2.3)</p></td><td><p>0.516
(0.000, 0.646)</p></td><td><p>0.12766
±0.000032</p></td><td><p>0.000032
was: 0.002132</p></td></tr><tr><td><p>queens</p></td><td><p>(14, 1)</p></td><td><p>2.0
(1.7, 2.0)</p></td><td><p>(1.7, 2.0)
was: (1.0, 294.4)</p></td><td><p>0.162
(0.113, 0.162)</p></td><td><p>0.15853
δ=0.04015
±0.000231</p></td><td><p>0.000231
was: 0.000751</p></td></tr><tr><td><p>quicksort</p></td><td><p></p></td><td><p>2.0
(2.0, 2.3)</p></td><td><p>(2.0, 2.3)
was: (2.0, 4.0)</p></td><td><p>0.278
(0.278, 0.361)</p></td><td><p>0.27183
±0.000469</p></td><td><p>0.000469
was: 0.067395</p></td></tr><tr><td><p>radixsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12621
±0.000757</p></td><td><p>0.000757
was: 0.000403</p></td></tr><tr><td><p>ray</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.35530
δ=0.04568
±0.000983</p></td><td><p></p></td></tr><tr><td><p>recursive_ack</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 19.0)</p></td><td><p></p></td><td><p>0.000
(0.000, 2.562)</p></td><td><p>0.14228
δ=0.02253
±0.000616</p></td><td><p></p></td></tr><tr><td><p>recursive_fib</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.28989
δ=0.05925
±0.000033</p></td><td><p></p></td></tr><tr><td><p>resty_json</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.07534
±0.000595</p></td><td><p>0.000595
was: 0.002629</p></td></tr><tr><td><p>revcomp</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11684
±0.002139</p></td><td><p>0.002139
was: 0.001754</p></td></tr><tr><td><p>richards</p></td><td><p></p></td><td><p>2.0
(2.0, 3.2)</p></td><td><p>(2.0, 3.2)
was: (1.0, 2.0)</p></td><td><p>0.171
(0.170, 0.369)</p></td><td><p>0.16559
δ=0.02935
±0.000342</p></td><td><p>0.000342
was: 0.010223</p></td></tr><tr><td><p>scimark_fft</p></td><td><p></p></td><td><p>2.0
(2.0, 10.3)</p></td><td><p>(2.0, 10.3)
was: (2.0, 4.7)</p></td><td><p>0.141
(0.141, 1.195)</p></td><td><p>0.12709
±0.000102</p></td><td><p>0.000102
was: 0.000823</p></td></tr><tr><td><p>scimark_lu</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12733
δ=0.01186
±0.000159</p></td><td><p></p></td></tr><tr><td><p>scimark_sor</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13297
δ=0.01189
±0.000005</p></td><td><p></p></td></tr><tr><td><p>scimark_sparse</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13082
δ=0.00740
±0.000490</p></td><td><p></p></td></tr><tr><td><p>series</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p></p></td><td><p>0.347
(0.347, 0.348)</p></td><td><p>0.33390
±0.000869</p></td><td><p>0.000869
was: 0.003217</p></td></tr><tr><td><p>spectralnorm</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13989
δ=0.00002
±0.000003</p></td><td><p></p></td></tr><tr><td><p>table_cmpsort</p></td><td><p></p></td><td><p>10.0
(10.0, 10.0)</p></td><td><p></p></td><td><p>1.945
(1.935, 1.967)</p></td><td><p>0.22008
±0.001852</p></td><td><p>0.001852
was: 0.007836</p></td></tr></table><p><sub>Results for Normal vs. RaptorJIT</sub></p><p>In essence, green cells mean that RaptorJIT is better than LuaJIT; red cells mean that LuaJIT is better than RaptorJIT; yellow means they're different in a way that can't be compared; and white/grey means they're statistically equivalent. The additional “Steady performance variation (s)” column shows whether the steady state performance of different process executions is more predictable or not.</p><p>The simple conclusion to draw from this is that there isn't a simple conclusion to draw from it: the two VMs are sometimes better than each other with no clear pattern. Without having a clear steer either way, we therefore decided to use the original version of LuaJIT as our base.</p><p>One of the things that became very clear from our benchmarking is that LuaJIT is highly non-deterministic – indeed, it's the most non-deterministic VM I've seen. The practical effect of this is that even on one program, LuaJIT is sometimes very fast, and sometimes rather slow. This is, at best, very confusing for users who tend to assume that programs perform more-or-less the same every time they're run; at worst, it can create significant problems when one is trying to estimate things like server provisioning. We therefore tried various things to make performance more consistent.</p><p>The most promising approach we alighted upon is what we ended up calling “separate counters”. In a tracing JIT compiler such as LuaJIT, one tracks how often a loop (where loops are both “obvious” things like for loops, as well as less obvious things such as functions) has been executed: once it's hit a certain threshold, the loop is traced, and compiled into machine code. LuaJIT has an unusual approach to counting loops: it has 64 counters to which all loops are mapped (using the memory address of the bytecode in question). In other words, multiple loops share the same counter: the bigger the program, the more loops share the same counter. The advantage of this is that the counters map is memory efficient, and for small programs (e.g. the common LuaJIT benchmarks) it can be highly effective. However, it has very odd effects in real programs, particularly as programs get bigger: loops are compiled non-deterministically based on the particular address in memory they happen to have been loaded at.</p><p>We therefore altered LuaJIT so that each loop and each function has its own counter, stored in the bytecode to make memory reads/writes more cache friendly. The diff from normal LuaJIT to the separate counters version is as follows:</p>
    <div>
      <h2>Results for Normal vs. Counters</h2>
      <a href="#results-for-normal-vs-counters">
        
      </a>
    </div>
    <p><b>Symbol key:</b> bad inconsistent, flat, good inconsistent, no steady state, slowdown, warmup.
<b>Diff against previous results:</b> improved worsened different unchanged.</p><table><tr><th><p><b>Benchmark</b></p></th><th><p><b>Classification</b></p></th><th><p><b>Steady iteration (#)</b></p></th><th><p><b>Steady iteration variation</b></p></th><th><p><b>Steady iteration (s)</b></p></th><th><p><b>Steady performance (s)</b></p></th><th><p><b>Steady performance
variation (s)</b></p></th></tr><tr><td><p>array3d</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>binarytrees</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12462
±0.004058</p></td><td><p>0.004058
was: 0.000532</p></td></tr><tr><td><p>bounce</p></td><td><p>(14, 1)</p></td><td><p>1.0
(1.0, 5.8)</p></td><td><p></p></td><td><p>0.000
(0.000, 0.603)</p></td><td><p>0.12515
δ=-0.00280
±0.000278</p></td><td><p></p></td></tr><tr><td><p>capnproto_decode</p></td><td><p>(9, 6)</p></td><td><p>1.0
(1.0, 24.9)</p></td><td><p>(1.0, 24.9)
was: (1.0, 45.3)</p></td><td><p>0.000
(0.000, 3.692)</p></td><td><p>0.15042
±0.003797</p></td><td><p>0.003797
was: 0.028466</p></td></tr><tr><td><p>capnproto_encode</p></td><td><p></p></td><td><p>230.0
(56.0, 467.6)</p></td><td><p>(56.0, 467.6)
was: (52.8, 280.6)</p></td><td><p>28.411
(6.667, 55.951)</p></td><td><p>0.11838
δ=-0.09860
±0.001960</p></td><td><p>0.001960
was: 0.014541</p></td></tr><tr><td><p>collisiondetector</p></td><td><p>(13, 2)</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>coroutine_ring</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.10680
±0.003151</p></td><td><p>0.003151
was: 0.001527</p></td></tr><tr><td><p>deltablue</p></td><td><p></p></td><td><p>149.0
(149.0, 274.5)</p></td><td><p>(149.0, 274.5)
was: (1.0, 1022.9)</p></td><td><p>15.561
(15.430, 28.653)</p></td><td><p>0.10159
±0.001083</p></td><td><p>0.001083
was: 0.003195</p></td></tr><tr><td><p>euler14</p></td><td><p></p></td><td><p>61.0
(61.0, 68.3)</p></td><td><p>(61.0, 68.3)
was: (60.0, 83.0)</p></td><td><p>5.650
(5.592, 6.356)</p></td><td><p>0.09216
±0.000159</p></td><td><p>0.000159
was: 0.000743</p></td></tr><tr><td><p>fannkuch_redux</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11976
±0.000012</p></td><td><p>0.000012
was: 0.001502</p></td></tr><tr><td><p>fasta</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12200
δ=0.00100
±0.000597</p></td><td><p></p></td></tr><tr><td><p>havlak</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>heapsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.04378
δ=0.02461
±0.000789</p></td><td><p></p></td></tr><tr><td><p>jsonlua_decode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12648
δ=0.01370
±0.000556</p></td><td><p></p></td></tr><tr><td><p>jsonlua_encode</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12860
±0.000879</p></td><td><p>0.000879
was: 0.001761</p></td></tr><tr><td><p>knucleotide</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11710
±0.000541</p></td><td><p>0.000541
was: 0.000811</p></td></tr><tr><td><p>life</p></td><td><p>(9, 3, 2, 1)</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>luacheck</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>1.00299
±0.004778</p></td><td><p>0.004778
was: 0.089781</p></td></tr><tr><td><p>luacheck_parser</p></td><td><p>(12, 2, 1)</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>luafun</p></td><td><p></p></td><td><p>69.0
(69.0, 69.0)</p></td><td><p></p></td><td><p>11.481
(11.331, 11.522)</p></td><td><p>0.16770
±0.001564</p></td><td><p>0.001564
was: 0.004918</p></td></tr><tr><td><p>mandelbrot</p></td><td><p>(14, 1)</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>mandelbrot_bit</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.21695
±0.000142</p></td><td><p></p></td></tr><tr><td><p>md5</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11155
δ=-0.00124
±0.000043</p></td><td><p></p></td></tr><tr><td><p>meteor</p></td><td><p>(13, 2)</p></td><td><p>14.0
(1.0, 15.0)</p></td><td><p>(1.0, 15.0)
was: (2.0, 18.0)</p></td><td><p>2.855
(0.000, 3.045)</p></td><td><p>0.21606
±0.004651</p></td><td><p>0.004651
was: 0.003935</p></td></tr><tr><td><p>moonscript</p></td><td><p></p></td><td><p>63.0
(17.7, 184.1)</p></td><td><p>(17.7, 184.1)
was: (13.1, 423.3)</p></td><td><p>10.046
(2.763, 29.739)</p></td><td><p>0.15999
±0.001405</p></td><td><p>0.001405
was: 0.001568</p></td></tr><tr><td><p>nbody</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.15898
±0.001676</p></td><td><p>0.001676
was: 0.002790</p></td></tr><tr><td><p>nsieve</p></td><td><p></p></td><td><p>2.0
(2.0, 2.6)</p></td><td><p>(2.0, 2.6)
was: (2.0, 2.0)</p></td><td><p>0.189
(0.188, 0.297)</p></td><td><p>0.17875
±0.001266</p></td><td><p>0.001266
was: 0.000641</p></td></tr><tr><td><p>nsieve_bit</p></td><td><p></p></td><td><p>4.0
(2.0, 6.0)</p></td><td><p>(2.0, 6.0)
was: (3.4, 5.3)</p></td><td><p>0.271
(0.097, 0.446)</p></td><td><p>0.08726
δ=-0.00032
±0.000202</p></td><td><p>0.000202
was: 0.000054</p></td></tr><tr><td><p>partialsums</p></td><td><p></p></td><td><p>2.0
(2.0, 2.9)</p></td><td><p>(2.0, 2.9)
was: (2.0, 2.0)</p></td><td><p>0.161
(0.161, 0.295)</p></td><td><p>0.14916
±0.000081</p></td><td><p>0.000081
was: 0.002044</p></td></tr><tr><td><p>pidigits</p></td><td><p></p></td><td><p>2.0
(2.0, 4.3)</p></td><td><p>(2.0, 4.3)
was: (1.0, 2.3)</p></td><td><p>0.130
(0.130, 0.425)</p></td><td><p>0.12666
±0.000122</p></td><td><p>0.000122
was: 0.002133</p></td></tr><tr><td><p>queens</p></td><td><p>(10, 5)</p></td><td><p>1.0
(1.0, 2.0)</p></td><td><p>(1.0, 2.0)
was: (1.0, 294.4)</p></td><td><p>0.000
(0.000, 0.127)</p></td><td><p>0.12484
δ=0.00646
±0.000317</p></td><td><p>0.000317
was: 0.000751</p></td></tr><tr><td><p>quicksort</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p></p></td><td><p>0.299
(0.298, 0.304)</p></td><td><p>0.44880
δ=0.13763
±0.020477</p></td><td><p>0.020477
was: 0.067395</p></td></tr><tr><td><p>radixsort</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12644
±0.000864</p></td><td><p>0.000864
was: 0.000403</p></td></tr><tr><td><p>ray</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.30901
±0.002140</p></td><td><p>0.002140
was: 0.004022</p></td></tr><tr><td><p>recursive_ack</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11958
±0.000510</p></td><td><p>0.000510
was: 0.000653</p></td></tr><tr><td><p>recursive_fib</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.22864
±0.000266</p></td><td><p>0.000266
was: 0.028968</p></td></tr><tr><td><p>resty_json</p></td><td><p>(12, 2, 1)</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td></tr><tr><td><p>revcomp</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.11550
±0.002553</p></td><td><p>0.002553
was: 0.001753</p></td></tr><tr><td><p>richards</p></td><td><p>(14, 1)</p></td><td><p>2.0
(1.7, 2.0)</p></td><td><p>(1.7, 2.0)
was: (1.0, 2.0)</p></td><td><p>0.150
(0.105, 0.150)</p></td><td><p>0.14572
±0.000324</p></td><td><p>0.000324
was: 0.010223</p></td></tr><tr><td><p>scimark_fft</p></td><td><p></p></td><td><p>2.0
(2.0, 10.0)</p></td><td><p>(2.0, 10.0)
was: (2.0, 4.7)</p></td><td><p>0.140
(0.140, 1.153)</p></td><td><p>0.12639
±0.000343</p></td><td><p>0.000343
was: 0.000823</p></td></tr><tr><td><p>scimark_lu</p></td><td><p>(11, 4)</p></td><td><p>1.0
(1.0, 45.3)</p></td><td><p></p></td><td><p>0.000
(0.000, 5.122)</p></td><td><p>0.11546
±0.000132</p></td><td><p>0.000132
was: 0.000308</p></td></tr><tr><td><p>scimark_sor</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12105
±0.000148</p></td><td><p></p></td></tr><tr><td><p>scimark_sparse</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.12315
±0.000728</p></td><td><p>0.000728
was: 0.000585</p></td></tr><tr><td><p>series</p></td><td><p></p></td><td><p>2.0
(2.0, 2.0)</p></td><td><p></p></td><td><p>0.347
(0.347, 0.348)</p></td><td><p>0.33394
±0.000645</p></td><td><p>0.000645
was: 0.003217</p></td></tr><tr><td><p>spectralnorm</p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p></p></td><td><p>0.13985
δ=-0.00003
±0.000007</p></td><td><p></p></td></tr><tr><td><p>table_cmpsort</p></td><td><p>(13, 1, 1)</p></td><td><p>1.0
(1.0, 10.0)</p></td><td><p></p></td><td><p>0.000
(0.000, 2.005)</p></td><td><p>0.21828
±0.003289</p></td><td><p>0.003289
was: 0.007836</p></td></tr></table><p><sub>Results for Normal vs. Counters</sub></p><p>In this case we’re particularly interested in the “steady performance variation (s)” column, which shows whether benchmarks have predictable steady state performance. The results are fairly clear: steady counters are, overall, a clear improvement. As you might expect, this is not a pure win, because it changes the order in which traces are made. This has several effects, including delaying some loops to be traced later than was previously the case, because counters do not hit the required threshold as quickly. </p><p>This disadvantages some programs, particularly small deterministic benchmarks where loops are highly stable. In such cases, the earlier you trace the better. However, in my opinion, such programs are given undue weight when performance is considered. It’s no secret that some of the benchmarks regularly used to benchmark LuaJIT are <i>highly</i> optimised for LuaJIT as it stands; any changes to LuaJIT stand a good chance of degrading their performance. However, overall we feel that the overall gain in consistency, particularly for larger programs, is worth it. There's a <a href="https://github.com/lua-users-foundation/LuaJIT/pull/6">pull request against the Lua Foundation's fork of LuaJIT</a> which applies this idea to a mainstream fork of LuaJIT.</p><p>We then started looking at various programs that showed odd performance. One problem in particular showed up in more than one benchmark. Here's a standard example:</p><p>Collisiondetector, Normal, Bencher9, Proc. exec. #12 (no steady state)</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/Q2ZdgNBkfPHYDy88AAjkv/83ed55ff8eb087dfbeb7d94ff496b892/collision1-1.svg" />
          </figure><p>The problem – and it doesn't happen on every process execution, just to make it more fun – is that there are points where the benchmark slows down by over 10% for multiple in-process iterations (e.g. in this process execution, at in-process iterations 930-ish and 1050-ish). We tried over 25 separate ways to work out what was causing this — even building an instrumentation system to track what LuaJIT is doing — but in the end it turned out to be related to LuaJIT's Garbage Collector – sort of. When we moved from the 32-bit to 64-bit GC, the odd performance went away.</p><p>As such, we don’t think that the 64-bit GC “solves” the problem: however, it changes the way that pointers are encoded (doubling in size), which causes the code generator to emit a different style of code, such that the problem seems to go away. Nevertheless, this did make us reevaluate LuaJIT's GC. Tom then started work on implementing Mike Pall's <a href="http://wiki.luajit.org/New-Garbage-Collector">suggestion for a new GC for LuaJIT</a> (based partly on Tom's previous work and also that of Peter Cawley). He has enough implemented to run most small, and some large, programs, but it needs more work to finish it off, at which point evaluating it against the existing Lua GCs will be fascinating!</p><p>So, did we achieve everything we wanted to in 12 months? Inevitably the answer is yes and no. We did a lot more benchmarking than we expected; we've been able to make a lot of programs (particularly large programs) have more consistent performance; and we've got a fair way down the road of implementing a new GC. To whoever takes on further LuaJIT work – best of luck, and I look forward to seeing your results!</p><p><b>Acknowledgements:</b> Sarah Mount implemented the stats differ; Edd Barrett implemented Krun and answered many questions on it.</p> ]]></content:encoded>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">UhdX7EC0rWypMpydfLKTz</guid>
            <dc:creator>Guest Author</dc:creator>
        </item>
        <item>
            <title><![CDATA[Technical reading from the Cloudflare blog for the holidays]]></title>
            <link>https://blog.cloudflare.com/2017-holiday-reading-from-the-cloudflare-blog/</link>
            <pubDate>Fri, 22 Dec 2017 14:17:57 GMT</pubDate>
            <description><![CDATA[ During 2017 Cloudflare published 172 blog posts (including this one). If you need a distraction from the holiday festivities at this time of year here are some highlights from the year. ]]></description>
            <content:encoded><![CDATA[ <p>During 2017 Cloudflare published 172 blog posts (including this one). If you need a distraction from the holiday festivities at this time of year here are some highlights from the year.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1FupNPeMEDTcUGuKJCQ2hX/69f106f4d37e6f7ce629f3845d88f8ed/33651510973_9bc38cc550_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/148114704@N05/33651510973/in/photolist-TgEMP4-5W4SKe-5QXuaQ-avwN4J-9kM47Q-5sZfg5-62HmQr-vRsPNX-9gu8zw-8tzfDA-7L9szU-2j3fkx-kdS5xh-dTvJ1k-bd2nWP-5eyMyX-cYKDeY-aha8Je-s9FApd-afsNQp-Rr9uMb-6w5kZp-e8k7Zc-7JV8KQ-Sbxdzt-emJeJJ-fvoSPx-7jDQjL-cNbEy7-Ht7oDe-6w5mqM-cDJ6PS-cDHREJ-2L3KsB-2rjJQY-9kxtQm-b31okB-2rfQ8c-bHhPX-dr6fiP-5sUUEp-DDzAGu-onQfBb-afsNzx-kdS4E5-fVkm7-okB223-7ZrhKH-9eLu3Y-pcsdc4">image</a> by <a href="https://perzonseo.com">perzon seo</a></p><p><a href="/the-wirex-botnet/">The WireX Botnet: How Industry Collaboration Disrupted a DDoS Attack</a></p><p>We worked closely with companies across the industry to track and take down the Android WireX Botnet. This blog post goes into detail about how that botnet operated, how it was distributed and how it was taken down.</p><p><a href="/randomness-101-lavarand-in-production/">Randomness 101: LavaRand in Production</a></p><p>The wall of Lava Lamps in the San Francisco office is used to feed entropy into random number generators across our network. This blog post explains how.</p><p><a href="/arm-takes-wing/">ARM Takes Wing: Qualcomm vs. Intel CPU comparison</a></p><p>Our <a href="https://www.cloudflare.com/network/">network</a> of data centers around the world all contain Intel-based servers, but we're interested in ARM-based servers because of the potential cost/power savings. This blog post took a look at the relative performance of Intel processors and Qualcomm's latest server offering.</p><p><a href="/how-to-monkey-patch-the-linux-kernel/">How to Monkey Patch the Linux Kernel</a></p><p>One engineer wanted to combine the Dvorak and QWERTY keyboard layouts and did so by patching the Linux kernel using <a href="https://sourceware.org/systemtap/">SystemTap</a>. This blog explains how and why. Where there's a will, there's a way.</p><p><a href="/introducing-cloudflare-workers/">Introducing Cloudflare Workers: Run JavaScript Service Workers at the Edge</a></p><p>Traditionally, the Cloudflare network has been <i>configurable</i> by our users, but not <i>programmable</i>. In September, we introduced <a href="https://www.cloudflare.com/products/cloudflare-workers/">Cloudflare Workers</a> which allows users to write JavaScript code that runs on our edge worldwide. This blog post explains why we chose JavaScript and how it works.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3rDQWcCe0YDvxU6a8enygs/e436188ab1b54b75b1a875143e9c08c5/5586120601_a7b1776371_b.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/werkman/5586120601/in/photolist-9vCk3a-21Bd6Xh-8nCHw7-ptePkD-RJQgiN-nWZ5u6-3xLVWE-rDFYG8-LH8sS-2peYb-mX5MQc-6JxAT-aAArZQ-rJfmkx-9HavML-TX5hUW-niuhtp-jHGzT5-5eRuc3-Gv67PP-fs2mGn-8mhB7f-8pDZbD-ZPoZDF-3xLxd3-6k15Ni-j1zK3-8mhB8b-7RjyKs-57C9rW-j1zBX-bTs5tP-8wuUBf-7r7fAq-8jPBD4-5bnWiq-e88EiF-ddTbY7-PVC9U-e88E6P-S4eP6f-8jPkh2-5bj6xn-NzVdo-7rQyZa-4Dm4gX-ZCuaMm-pQr1Hw-yf9rdC-21HJvkv">image</a> by <a href="https://www.flickr.com/photos/werkman/">Peter Werkman</a></p><p><a href="/geo-key-manager-how-it-works/">Geo Key Manager: How It Works</a></p><p>Our <a href="/introducing-cloudflare-geo-key-manager/">Geo Key Manager</a> gives customers granular control of the location of their private keys on the Cloudflare network. This blog post explains the mathematics that makes the possible.</p><p><a href="/sidh-go/">SIDH in Go for quantum-resistant TLS 1.3</a></p><p>Quantum-resistant cryptography isn't an academic fantasy. We implemented the SIDH scheme as part of our Go implementation of TLS 1.3 and open sourced it.</p><p><a href="/the-languages-which-almost-became-css/">The Languages Which Almost Became CSS</a></p><p>This blog post recounts the history of CSS and the languages that might have been CSS.</p><p><a href="/perfect-locality-and-three-epic-systemtap-scripts/">Perfect locality and three epic SystemTap scripts</a></p><p>In an ongoing effort to understand the performance of NGINX under heavy load on our machines (and wring out the greatest number of requests/core), we used SystemTap to experiment with different queuing models.</p><p><a href="/counting-things-a-lot-of-different-things/">How we built rate limiting capable of scaling to millions of domains</a></p><p>We rolled out a <a href="cloudflare">rate limiting</a> feature that allows our customers to control the maximum number of HTTP requests per second/minute/hour that their servers receive. This blog post explains how we made that operate efficiently at our scale.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4cQPAfJHM6gES4uXsyRwd4/f871a9d7627a4ea4f405ea76524e9545/26797557806_18daa76ec2_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/waters2712/26797557806/in/photolist-GQ1ujJ-ovpzb8-5hGjhb-pkkHPH-7Ed3eQ-5TiuCW-6tknkf-7JGpz4-81Rc1J-qM8AwX-dQVifV-nWZ5u6-puAvLe-acEK6v-F5KyvG-4Ykyf1-bvH81M-FF6XnD-KLqgJ-4rLnJE-d8b1tS-dQVisV-7cTp1r-pkkHic-6oKTtx-9mKe1u-5vsfch-coUNp9-o9Txa7-9p7thZ-aWYjuc-SV2qEb-7LXSYz-9Fcnam-fkr4Fc-b6Dtmt-6r1QQ2-5ndv1D-fuUiKV-qDAQxe-cjZhVY-6Hn6G1-qPMScz-mJAvhc-8LVJNj-7Ed3cf-9wFgvw-9z5jt9-bGsg4R-72BBkc">image</a> by <a href="https://www.flickr.com/photos/waters2712/">Han Cheng Yeh</a></p><p><a href="/reflections-on-reflections/">Reflections on reflection (attacks)</a></p><p>We deal with a new DDoS attack every few minutes and in this blog post we took a close look at reflection attacks and revealed statistics on the types of reflection-based DDoS attacks we see.</p><p><a href="/on-the-dangers-of-intels-frequency-scaling/">On the dangers of Intel's frequency scaling</a></p><p>Intel processors contain special AVX-512 that provide 512-bit wide SIMD instructions to speed up certain calculations. However, these instructions have a downside: when used the CPU base frequency is scaled down slowing down other instructions. This blog post explores that problem.</p><p><a href="/how-cloudflare-analyzes-1m-dns-queries-per-second/">How Cloudflare analyzes 1M DNS queries per second</a></p><p>This blog post details how we handle logging information for 1M DNS queries per second using a custom pipeline, <a href="https://clickhouse.yandex/">ClickHouse</a> and Grafana (via a connector we <a href="https://github.com/vavrusa/grafana-sqldb-datasource">open sourced</a>) to build real time dashboards.</p><p><a href="/aes-cbc-going-the-way-of-the-dodo/">AES-CBC is going the way of the dodo</a></p><p>CBC-mode cipher suites have been declining for some time because of padding oracle-based attacks. In this blog we demonstrate that AES-CBC has now largely been replaced by <a href="/it-takes-two-to-chacha-poly/">ChaCha20-Poly1305</a> .</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6CVkU8gCFVwghZzoP3x0Sd/c90d63d983ab453d7115daac2d16e632/3414054443_2bd47e12f7_b.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/spanginator/3414054443/in/photolist-6cFVrD-6cvz6R-6cKZLw-rn74T-7RoM6f-ATb57-aQHtja-7i1omC-xGoWE-8FsWpL-6DbHyD-9aFjZn-BxbDmF-23fTGw-4v5aS-81KR9D-ahC42F-7ibXNR-Hod7ZY-7hS2JP-fnyx1X-4Pjy9v-kNu6rR-FFmpx9-Gyx1By-GsEegj-7hVPHw-Gv6zDR-F5KyvG-FF6XnD-FZk6kU-9re3Rz-dRTft-btLnvB-o3PQ5p-nU34U-VCRL7q-YhCTjj-L44FTc-Ke5mko-L1vxdJ-KehBhx-7BjC9n-7xSGtH-pEfb5f-2pqSst-7Xhhmq-o8u7ja-pWNcy2-KSCBjW">image</a> by <a href="https://www.flickr.com/photos/spanginator/">Christine</a></p><p><a href="/how-we-made-our-dns-stack-3x-faster/">How we made our DNS stack 3x faster</a></p><p>We answer around 1 million authoritative DNS queries per second using a custom software stack. Responding to those queries as quickly as possible is why Cloudflare is <a href="http://www.dnsperf.com/">fastest</a> authoritative DNS provider on the Internet. This blog post details how we made our stack even faster.</p><p><a href="/quantifying-the-impact-of-cloudbleed/">Quantifying the Impact of "Cloudbleed"</a></p><p>On February 18 a serious security bug was reported to Cloudflare. Five days <a href="/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/">later</a> we released details of the problem and six days after that we posted this analysis of the impact.</p><p><a href="/luajit-hacking-getting-next-out-of-the-nyi-list/">LuaJIT Hacking: Getting next() out of the NYI list</a></p><p>We make extensive use of <a href="http://luajit.org/">LuaJIT</a> when processing our customers' traffic and making it faster is a key goal. In the past, we've sponsored the project and everyone benefits from those contributions. This blog post examines getting one specific function JITted correctly for additional speed.</p><p><a href="/privacy-pass-the-math/">Privacy Pass: The Math</a></p><p>The <a href="https://privacypass.github.io/">Privacy Pass</a> project provides a zero knowledge way of proving your identity to a service like Cloudflare. This detailed blog post explains the mathematics behind authenticating a user without knowing their identity.</p><p><a href="/how-and-why-the-leap-second-affected-cloudflare-dns/">How and why the leap second affected Cloudflare DNS</a></p><p>The year started with a bang for some engineers at Cloudflare when we ran into a bug in our custom DNS server, <a href="/tag/rrdns/">RRDNS</a>, caused by the introduction of a <a href="https://en.wikipedia.org/wiki/Leap_second">leap second</a> at midnight UTC on January 1, 2017. This blog explains the error and why it happened.</p><p>There's <a href="https://datacenter.iers.org/web/guest/eop/-/somos/5Rgv/latest/16">no leap second</a> this year.</p> ]]></content:encoded>
            <category><![CDATA[Year in Review]]></category>
            <category><![CDATA[Product News]]></category>
            <category><![CDATA[LavaRand]]></category>
            <category><![CDATA[DDoS]]></category>
            <category><![CDATA[Geo Key Manager]]></category>
            <category><![CDATA[DNS]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Privacy Pass]]></category>
            <category><![CDATA[Vulnerabilities]]></category>
            <category><![CDATA[Bots]]></category>
            <guid isPermaLink="false">1PeYMnOt6XNE3dqjt2m9aq</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Wants to Buy Your Meetup Group Pizza]]></title>
            <link>https://blog.cloudflare.com/cloudflare-wants-to-buy-your-meetup-group-pizza/</link>
            <pubDate>Fri, 10 Nov 2017 15:00:00 GMT</pubDate>
            <description><![CDATA[ If you’re a web dev / devops / etc. meetup group that also works toward building a faster, safer Internet, I want to support your awesome group by buying you pizza.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>If you’re a web dev / devops / etc. meetup group that also works toward building a faster, safer Internet, I want to support your awesome group by buying you pizza. If your group’s focus falls within one of the subject categories below and you’re willing to give us a 30 second shout out and tweet a photo of your group and <a href="https://twitter.com/Cloudflare">@Cloudflare</a>, your meetup’s pizza expense will be reimbursed.</p><p><a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit?usp=sharing">Get Your Pizza $ Reimbursed »</a></p>
    <div>
      <h3>Developer Relations at Cloudflare &amp; why we’re doing this</h3>
      <a href="#developer-relations-at-cloudflare-why-were-doing-this">
        
      </a>
    </div>
    <p>I’m <a href="https://twitter.com/fitchaj">Andrew Fitch</a> and I work on the Developer Relations team at <a href="https://www.cloudflare.com/">Cloudflare</a>. One of the things I like most about working in DevRel is empowering community members who are already doing great things out in the world. Whether they’re starting conferences, hosting local meetups, or writing educational content, I think it’s important to support them in their efforts and reward them for doing what they do. Community organizers are the glue that holds developers together socially. Let’s support them and make their lives easier by taking care of the pizza part of the equation.</p>
            <figure>
            <a href="https://www.cloudflare.com/apps/">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2LFJE5nWDC74sln8mrtauZ/de98413ff1b6f611461c5c4649444c60/FingerPhotography-Cloudfare-8733.jpg" />
            </a>
            </figure>
    <div>
      <h4>What’s in it for Cloudflare?</h4>
      <a href="#whats-in-it-for-cloudflare">
        
      </a>
    </div>
    <ol><li><p>We want web developers to target the <a href="https://www.cloudflare.com/apps/">apps platform</a></p></li><li><p>We want more people to think about <a href="https://www.cloudflare.com/careers/">working at Cloudflare</a></p></li><li><p>Some people only know of <a href="https://www.cloudflare.com/">Cloudflare</a> as a CDN, but it’s actually a security company and does much more than that. General awareness helps tell the story of what Cloudflare is about.</p></li></ol>
    <div>
      <h4>What kinds of groups we most want to support</h4>
      <a href="#what-kinds-of-groups-we-most-want-to-support">
        
      </a>
    </div>
    <p>We want to work with groups that are closely aligned with Cloudflare, groups which focus on web development, web security, devops, or tech ops. We often work with language-specific meetups (such as Go London User Group) or diversity &amp; inclusion meetups (such as Women Who Code Portland). We’d also love to work with college student groups and any other coding groups which are focused on sharing technical knowledge with the community.</p><p>To get sponsored pizza, groups must be focused on...</p><ul><li><p>Web performance &amp; optimization</p></li><li><p>Front-end frameworks</p></li><li><p>Language-specific (JavaScript / PHP / Go / Lua / etc.)</p></li><li><p>Diversity &amp; inclusion meetups for web devs / devops / tech ops</p></li><li><p>Workshops / classes for web devs / devops / tech ops</p></li></ul>
    <div>
      <h4>How it works</h4>
      <a href="#how-it-works">
        
      </a>
    </div>
    <ol><li><p>Interested groups need to read our <a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit">Cloudflare Meetup Group Pizza Reimbursement Rules document</a>.</p></li><li><p>If the group falls within the requirements, the group should proceed to schedule their meetup and pull the <a href="https://docs.google.com/presentation/d/1afluXpf2eYeQ7SkmV2ONrojeZwosMTNifhnZR1chNTw/edit?usp=sharing">Cloudflare Introductory Slides</a> ahead of time.</p></li><li><p>At the event, an organizer should present the Cloudflare Introductory Slides at the beginning, giving us a 30 second shout out, and take a photo of the group in front of the slides. Someone from the group should Tweet the photo and @Cloudflare, so our Community Manager may retweet.</p></li><li><p>After the event, an organizer will need to fill out our <a href="https://docs.google.com/forms/d/e/1FAIpQLSe7iY-mjum-hfEtu8W08uf8e6H5IMDevRgCZ_YXtzaEwkLEag/viewform">reimbursement form</a> where they will upload a <a href="https://www.irs.gov/pub/irs-pdf/fw9.pdf">completed W-9</a>, their mailing address, group details, and the link to the Tweet.</p></li><li><p>Within a month, the organizer should have a check from Cloudflare (and some laptop stickers for their group, if they want) in their hands.</p></li></ol>
    <div>
      <h4>Here are some examples of groups we’ve worked with so far</h4>
      <a href="#here-are-some-examples-of-groups-weve-worked-with-so-far">
        
      </a>
    </div>
    <p><a href="https://www.meetup.com/preview/Go-London-User-Group"><b>Go London User Group (GLUG)</b></a></p>
            <figure>
            <a href="https://twitter.com/LondonGophers/status/920353032746995712">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4oWPqXK3ZLOH0BA3mbJO7M/ddc7337f74e01171d7e91655dfa35f0e/Screen-Shot-2017-11-01-at-2.32.00-PM.png" />
            </a>
            </figure><p>The Go London User Group is a London-based community for anyone interested in the Go programming language.</p><p>GLUG provides offline opportunities to:</p><ul><li><p>Discuss Go and related topics</p></li><li><p>Socialize with friendly people who are interested in Go</p></li><li><p>Find or fill Go-related jobs</p></li></ul><p>They want GLUG to be a diverse and inclusive community. As such all attendees, organizers and sponsors are required to follow the <a href="https://golang.org/conduct">community code of conduct</a>.</p><p>This group’s mission is very much in alignment with Cloudflare’s guidelines, so we sponsored the pizza for their <a href="https://www.meetup.com/preview/Go-London-User-Group/events/243800263">October Gophers</a> event.</p><p><a href="https://www.meetup.com/preview/Women-Who-Code-Portland"><b>Women Who Code Portland</b></a></p>
            <figure>
            <a href="https://twitter.com/superissarah/status/923370521684688896">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1t1S26RRHOCUC2b3YwEAMD/5aec722ff115aab5edbb7da5700bee35/Screen-Shot-2017-11-01-at-2.37.09-PM.png" />
            </a>
            </figure><p>Women Who Code’s mission statement</p><p>Women Who Code is a global nonprofit dedicated to inspiring women to excel in technology careers by creating a global, connected community of women in technology.</p><p>What they offer</p><ul><li><p>Monthly Networking Nights</p></li><li><p>Study Nights (JavaScript, React, DevOps, Design + Product, Algorithms)</p></li><li><p>Technical Workshops</p></li><li><p>Community Events (Hidden Figures screening, Women Who Strength Train, Happy Hours, etc.)</p></li><li><p>Free or discounted tickets to conferences</p></li></ul><p>Women Who Code are a great example of an inclusive technical group. Cloudflare reimbursed them for their pizza at their <a href="https://www.meetup.com/preview/Women-Who-Code-Portland/events/242929022">October JavaScript Study Night</a>.</p><p><a href="https://www.meetup.com/preview/PHX-Android"><b>GDG Phoenix / PHX Android</b></a></p>
            <figure>
            <a href="https://twitter.com/GDGPhoenix/status/924314879875465216">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2PyMqJ00eEnGypcoxjmQST/878da7d678babf0a506f8ff099449db8/Screen-Shot-2017-11-01-at-2.41.46-PM.png" />
            </a>
            </figure><p>GDG Phoenix / PHX Android group is for anyone interested in Android design and development. All skill levels are welcome. Participants are welcome to the meet up to hang out and watch or be part of the conversation at events.</p><p>This group is associated with the <a href="https://developers.google.com/groups/">Google Developer Group</a> program and coordinate activities with the national organization. Group activities are not exclusively Android related, however, they can cover any technology.</p><p>Cloudflare sponsored their October event “<a href="https://www.meetup.com/preview/PHX-Android/events/242897401">How espresso works . . . Android talk with Michael Bailey</a>”.</p><hr /><p>I hope a lot of awesome groups around the world will take advantage of our offer. <b>Enjoy the pizza!</b></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5kKeJF3uYWwJyAkZ67TmQg/1f948496f05932879b8165e87730e456/giphy-downsized.gif" />
            
            </figure><p><a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit?usp=sharing">Get Your Pizza $ Reimbursed »</a></p><p>© 2017 Cloudflare, Inc. All rights reserved. The Cloudflare logo and marks are trademarks of Cloudflare. All other company and product names may be trademarks of the respective companies with which they are associated.</p> ]]></content:encoded>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[MeetUp]]></category>
            <category><![CDATA[Cloudflare Meetups]]></category>
            <category><![CDATA[Community]]></category>
            <guid isPermaLink="false">5luIi07exijfTyC4t91k0H</guid>
            <dc:creator>Andrew Fitch</dc:creator>
        </item>
        <item>
            <title><![CDATA[ARM Takes Wing:  Qualcomm vs. Intel CPU comparison]]></title>
            <link>https://blog.cloudflare.com/arm-takes-wing/</link>
            <pubDate>Wed, 08 Nov 2017 20:03:14 GMT</pubDate>
            <description><![CDATA[ One of the nicer perks I have here at Cloudflare is access to the latest hardware, long before it even reaches the market. Until recently I mostly played with Intel hardware.  ]]></description>
            <content:encoded><![CDATA[ <p>One of the nicer perks I have here at Cloudflare is access to the latest hardware, long before it even reaches the market.</p><p>Until recently I mostly played with Intel hardware. For example Intel supplied us with an engineering sample of their Skylake based Purley platform back in August 2016, to give us time to evaluate it and optimize our software. As a former Intel Architect, who did a lot of work on Skylake (as well as Sandy Bridge, Ivy Bridge and Icelake), I really enjoy that.</p><p>Our previous generation of servers was based on the Intel Broadwell micro-architecture. Our configuration includes dual-socket Xeons E5-2630 v4, with 10 cores each, running at 2.2GHz, with a 3.1GHz turboboost and hyper-threading enabled, for a total of 40 threads per server.</p><p>Since Intel was, and still is, the undisputed leader of the server CPU market with greater than 98% market share, our upgrade process until now was pretty straightforward: every year Intel releases a new generation of CPUs, and every year we buy them. In the process we usually get two extra cores per socket, and all the extra architectural features such upgrade brings: hardware AES and CLMUL in Westmere, AVX in Sandy Bridge, AVX2 in Haswell, etc.</p><p>In the current upgrade cycle, our next server processor ought to be the Xeon Silver 4116, also in a dual-socket configuration. In fact, we have already purchased a significant number of them. Each CPU has 12 cores, but it runs at a lower frequency of 2.1GHz, with 3.0GHz turboboost. It also has smaller last level cache: 1.375 MiB/core, compared to 2.5 MiB the Broadwell processors had. In addition, the Skylake based platform supports 6 memory channels and the AVX-512 instruction set.</p><p>As we head into 2018, however, change is in the air. For the first time in a while, Intel has serious competition in the server market: Qualcomm and Cavium both have new server platforms based on the ARMv8 64-bit architecture (aka aarch64 or arm64). Qualcomm has the Centriq platform (code name Amberwing), based on the Falkor core, and Cavium has the ThunderX2 platform, based on the ahm ... ThunderX2 core?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OerKvEoy4NXTwjEpDA1tY/d8d9c4dad28ab5bc7100710b3dcf644e/25704115174_061e907e57_o.jpg" />
            
            </figure><p>The majestic Amberwing powered by the Falkor CPU <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/drphotomoto/25704115174/in/photolist-FaoiVy-oqK2j2-f6A8TL-6PTBkR-gRasf9-f2R2Hz-7bZeUp-fmxSzZ-o9fogQ-8evb42-f4tgSX-eGzXYi-6umTDd-8evd8H-gdCU2L-uhCbnz-fmxSsX-oxnuko-wb7in9-oqsJSH-uxxAS2-CzS4Eh-6y8KQA-brLjKf-YT2jrY-eGG5QJ-8pLnKt-8eyvgY-cnQqJs-fXYs9f-f2R2jK-28ahBA-fXYjkD-a9K25u-289gvW-PHrqDS-cmkggf-Ff9NXa-EhMcP4-f36dMm-289xP7-Ehrz1y-f2QZRZ-GqT3vt-uUeHBq-xUDQoa-ymMxE9-wWFi3q-MDva8W-8CWG5X">image</a> by <a href="https://www.flickr.com/photos/drphotomoto/">DrPhotoMoto</a></p><p>Recently, both Qualcomm and Cavium provided us with engineering samples of their ARM based platforms, and in this blog post I would like to share my findings about Centriq, the Qualcomm platform.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4t48heslIVcJiaqGTuxwhl/a968a4b7f0a6a5dd25fc8481029db354/IMG_7222.jpg" />
            
            </figure><p>The actual Amberwing in question</p>
    <div>
      <h3>Overview</h3>
      <a href="#overview">
        
      </a>
    </div>
    <p>I tested the Qualcomm Centriq server, and compared it with our newest Intel Skylake based server and previous Broadwell based server.</p><table><tr><td><p><b>Platform</b></p></td><td><p><b>Grantley
(Intel)</b></p></td><td><p><b>Purley
(Intel)</b></p></td><td><p><b>Centriq
(Qualcomm)</b></p></td></tr><tr><td><p>Core</p></td><td><p>Broadwell</p></td><td><p>Skylake</p></td><td><p>Falkor</p></td></tr><tr><td><p>Process</p></td><td><p>14nm</p></td><td><p>14nm</p></td><td><p>10nm</p></td></tr><tr><td><p>Issue</p></td><td><p>8 µops/cycle</p></td><td><p>8 µops/cycle</p></td><td><p>8 instructions/cycle</p></td></tr><tr><td><p>Dispatch</p></td><td><p>4 µops/cycle</p></td><td><p>5 µops/cycle</p></td><td><p>4 instructions/cycle</p></td></tr><tr><td><p># Cores</p></td><td><p>10 x 2S + HT (40 threads)</p></td><td><p>12 x 2S + HT (48 threads)</p></td><td><p>46</p></td></tr><tr><td><p>Frequency</p></td><td><p>2.2GHz (3.1GHz turbo)</p></td><td><p>2.1GHz (3.0GHz turbo)</p></td><td><p>2.5 GHz</p></td></tr><tr><td><p>LLC</p></td><td><p>2.5 MB/core</p></td><td><p>1.35 MB/core</p></td><td><p>1.25 MB/core</p></td></tr><tr><td><p>Memory Channels</p></td><td><p>4</p></td><td><p>6</p></td><td><p>6</p></td></tr><tr><td><p>TDP</p></td><td><p>170W (85W x 2S)</p></td><td><p>170W (85W x 2S)</p></td><td><p>120W</p></td></tr><tr><td><p>Other features</p></td><td><p>AES
CLMUL
AVX2</p></td><td><p>AES
CLMUL
AVX512</p></td><td><p>AES
CLMUL
NEON
Trustzone
CRC32</p></td></tr></table><p>Overall on paper Falkor looks very competitive. In theory a Falkor core can process 8 instructions/cycle, same as Skylake or Broadwell, and it has higher base frequency at a lower TDP rating.</p>
    <div>
      <h3>Ecosystem readiness</h3>
      <a href="#ecosystem-readiness">
        
      </a>
    </div>
    <p>Up until now, a major obstacle to the deployment of ARM servers was lack, or weak, support by the majority of the software vendors. In the past two years, ARM’s enablement efforts have paid off, as most Linux distros, as well as most popular libraries support the 64-bit ARM architecture. Driver availability, however, is unclear at that point.</p><p>At Cloudflare, we run a complex software stack that consists of many integrated services, and running each of them efficiently is top priority.</p><p>On the edge we have the NGINX server software, that does support ARMv8. NGINX is written in C, and it also uses several libraries written in C, such as zlib and BoringSSL, therefore solid C compiler support is very important.</p><p>In addition, our flavor of NGINX is highly integrated with the <a href="https://github.com/openresty/lua-nginx-module">lua-nginx-module</a>, and we rely a lot on <a href="/pushing-nginx-to-its-limit-with-lua/">LuaJIT</a>.</p><p>Finally, a lot of our services, such as our DNS server, <a href="/what-weve-been-doing-with-go/#sts=RRDNS">RRDNS</a>, are written in Go.</p><p>The good news is that both gcc and clang not only support ARMv8 in general, but have optimization profiles for the Falkor core.</p><p>Go has official support for ARMv8 as well, and they improve the arm64 backend constantly.</p><p>As for LuaJIT, the stable version, 2.0.5 does not support ARMv8, but the beta version, 2.1.0 does. Let’s hope it gets out of beta soon.</p>
    <div>
      <h3>Benchmarks</h3>
      <a href="#benchmarks">
        
      </a>
    </div>
    
    <div>
      <h4>OpenSSL</h4>
      <a href="#openssl">
        
      </a>
    </div>
    <p>The first benchmark I wanted to perform, was OpenSSL version 1.1.1 (development version), using the bundled <code>openssl speed</code> tool. Although we recently switched to BoringSSL, I still prefer OpenSSL for benchmarking, because it has almost equally well optimized assembly code paths for both ARMv8 and the latest Intel processors.</p><p>In my opinion handcrafted assembly is the best measure of a CPU’s potential, as it bypasses the compiler bias.</p>
    <div>
      <h4>Public key cryptography</h4>
      <a href="#public-key-cryptography">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jqlU0sjyAGrZaT2Y1x8JR/9fc0bccc931f0e8f8cbf1c8fcd2bdecf/pub_key_1_core-2.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19nPDhEQXutllHbY08nO6O/0da82dc7260b6dbd732cc3cf79455ba8/pub_key_all_core-2.png" />
            
            </figure><p>Public key cryptography is all about raw ALU performance. It is interesting, but not surprising to see that in the single core benchmark, the Broadwell core is faster than Skylake, and both in turn are faster than Falkor. This is because Broadwell runs at a higher frequency, while architecturally it is not much inferior to Skylake.</p><p>Falkor is at a disadvantage here. First, in a single core benchmark, the turbo is engaged, meaning the Intel processors run at a higher frequency. Second, in Broadwell, Intel introduced two special instructions to accelerate big number multiplication: ADCX and ADOX. These perform two independent add-with-carry operations per cycle, whereas ARM can only do one. Similarly, the ARMv8 instruction set does not have a single instruction to perform 64-bit multiplication, instead it uses a pair of MUL and UMULH instructions.</p><p>Nevertheless, at the SoC level, Falkor wins big time. It is only marginally slower than Skylake at an RSA2048 signature, and only because RSA2048 does not have an optimized implementation for ARM. The <a href="https://www.cloudflare.com/learning/dns/dnssec/ecdsa-and-dnssec/">ECDSA</a> performance is ridiculously fast. A single Centriq chip can satisfy the ECDSA needs of almost any company in the world.</p><p>It is also very interesting to see Skylake outperform Broadwell by a 30% margin, despite losing the single core benchmark, and only having 20% more cores. This can be explained by more efficient all-core turbo, and improved hyper-threading.</p>
    <div>
      <h4>Symmetric key cryptography</h4>
      <a href="#symmetric-key-cryptography">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5c1gb11NBOBVq2PyFyxHIJ/05ddba2c522eecce2fe1fceca405c3ac/sym_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3HzScBUWaLPW2l7t0bvsuo/8c235d691f67a6fd9bbfe2176e3037d4/sym_key_all_core.png" />
            
            </figure><p>Symmetric key performance of the Intel cores is outstanding.</p><p>AES-GCM uses a combination of special hardware instructions to accelerate AES and CLMUL (carryless multiplication). Intel first introduced those instructions back in 2010, with their Westmere CPU, and every generation since they have improved their performance. ARM introduced a set of similar instructions just recently, with their 64-bit instruction set, and as an optional extension. Fortunately every hardware vendor I know of implemented those. It is very likely that Qualcomm will improve the performance of the cryptographic instructions in future generations.</p><p>ChaCha20-Poly1305 is a more generic algorithm, designed in such a way as to better utilize wide SIMD units. The Qualcomm CPU only has the 128-bit wide NEON SIMD, while Broadwell has 256-bit wide AVX2, and Skylake has 512-bit wide AVX-512. This explains the huge lead Skylake has over both in single core performance. In the all-cores benchmark the Skylake lead lessens, because it has to lower the clock speed when executing AVX-512 workloads. When executing AVX-512 on all cores, the base frequency goes down to just 1.4GHz---keep that in mind if you are mixing AVX-512 and other code.</p><p>The bottom line for symmetric crypto is that although Skylake has the lead, Broadwell and Falkor both have good enough performance for any real life scenario, especially considering the fact that on our edge, RSA consumes more CPU time than all the other crypto algorithms combined.</p>
    <div>
      <h3>Compression</h3>
      <a href="#compression">
        
      </a>
    </div>
    <p>The next benchmark I wanted to see was compression. This is for two reasons. First, it is a very important workload on the edge, as having better compression saves bandwidth, and helps deliver content faster to the client. Second, it is a very demanding workload, with a high rate of branch mispredictions.</p><p>Obviously the first benchmark would be the popular zlib library. At Cloudflare, we use an <a href="/cloudflare-fights-cancer/">improved version of the library</a>, optimized for 64-bit Intel processors, and although it is written mostly in C, it does use some Intel specific intrinsics. Comparing this optimized version to the generic zlib library wouldn’t be fair. Not to worry, with little effort I <a href="https://github.com/cloudflare/zlib/tree/vlad/aarch64">adapted the library</a> to work very well on the ARMv8 architecture, with the use of NEON and CRC32 intrinsics. In the process it is twice as fast as the generic library for some files.</p><p>The second benchmark is the emerging brotli library, it is written in C, and allows for a level playing field for all platforms.</p><p>All the benchmarks are performed on the HTML of <a href="/">blog.cloudflare.com</a>, in memory, similar to the way NGINX performs streaming compression. The size of the specific version of the HTML file is 29,329 bytes, making it a good representative of the type of files we usually compress. The parallel benchmark compresses multiple files in parallel, as opposed to compressing a single file on many threads, also similar to the way NGINX works.</p>
    <div>
      <h4>gzip</h4>
      <a href="#gzip">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2pi68sRQQHPJLXZO5vIbhW/72c6e8568f4d95e3e8d592dd72577ea8/gzip_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/S2VrG4fcrmbDUeOtJ453S/bbc5092e3565339bb7cb44ba7c8dd14d/gzip_all_core.png" />
            
            </figure><p>When using gzip, at the single core level Skylake is the clear winner. Despite having lower frequency than Broadwell, it seems that having lower penalty for branch misprediction helps it pull ahead. The Falkor core is not far behind, especially with lower quality settings. At the system level Falkor performs significantly better, thanks to the higher core count. Note how well gzip scales on multiple cores.</p>
    <div>
      <h4>brotli</h4>
      <a href="#brotli">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5LA2CLLkYa9iCe1eQzgs6x/1ff12aa354d80166407fe4f9fd538d78/brot_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1cuPwzCY4eJzgsOXmNrLXu/f7be60b7ac3497c13b3c0a2abe6ac522/brot_all_core.png" />
            
            </figure><p>With brotli on single core the situation is similar. Skylake is the fastest, but Falkor is not very much behind, and with quality setting 9, Falkor is actually faster. Brotli with quality level 4 performs very similarly to gzip at level 5, while actually compressing slightly better (8,010B vs 8,187B).</p><p>When performing many-core compression, the situation becomes a bit messy. For levels 4, 5 and 6 brotli scales very well. At level 7 and 8 we start seeing lower performance per core, bottoming with level 9, where we get less than 3x the performance of single core, running on all cores.</p><p>My understanding is that at those quality levels Brotli consumes significantly more memory, and starts thrashing the cache. The scaling improves again at levels 10 and 11.</p><p>Bottom line for brotli, Falkor wins, since we would not consider going above quality 7 for dynamic compression.</p>
    <div>
      <h3>Golang</h3>
      <a href="#golang">
        
      </a>
    </div>
    <p>Golang is another very important language for Cloudflare. It is also one of the first languages to offer ARMv8 support, so one would expect good performance. I used some of the built-in benchmarks, but modified them to run on multiple goroutines.</p>
    <div>
      <h4>Go crypto</h4>
      <a href="#go-crypto">
        
      </a>
    </div>
    <p>I would like to start the benchmarks with crypto performance. Thanks to OpenSSL we have good reference numbers, and it is interesting to see just how good the Go library is.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/64U9LsIbiAKp7Ut75mMmhj/c73c1142233e260e8733b079dac06ff8/go_pub_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5e9MFqm53p78KdB211Z8rZ/bc16992088b6aa826819bec645f99581/go_pub_key_all_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3TZyK91xQAJk4yfvYLnVjZ/c33931e0ead0f425c157746b9d637fc5/go_sym_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1S2LKr04vDIi1WrrZNaJn1/827505e17425e0521142cb397e209504/go_sym_key_all_core.png" />
            
            </figure><p>As far as Go crypto is concerned ARM and Intel are not even on the same playground. Go has very optimized assembly code for ECDSA, AES-GCM and Chacha20-Poly1305 on Intel. It also has Intel optimized math functions, used in RSA computations. All those are missing for ARMv8, putting it at a big disadvantage.</p><p>Nevertheless, the gap can be bridged with a relatively small effort, and we know that with the right optimizations, performance can be on par with OpenSSL. Even a very minor change, such as implementing the function <a href="https://go-review.googlesource.com/c/go/+/76270">addMulVVW</a> in assembly, lead to an over tenfold improvement in RSA performance, putting Falkor ahead of both Broadwell and Skylake, with 8,009 signatures/second.</p><p>Another interesting thing to note is that on Skylake, the Go Chacha20-Poly1305 code, that uses AVX2 performs almost identically to the OpenSSL AVX512 code, this is again due to AVX2 running at higher clock speeds.</p>
    <div>
      <h4>Go gzip</h4>
      <a href="#go-gzip">
        
      </a>
    </div>
    <p>Next in Go performance is gzip. Here again we have a reference point to pretty well optimized code, and we can compare it to Go. In the case of the gzip library, there are no Intel specific optimizations in place.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1GbKt2HcdJT5eNMdfsLw4d/7c55522afbfa58653a91c28479de8c3d/go_gzip_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/59TTlWALNqIkryEc7IwOnB/73ee80ab27313c3f55d3cb22c06b6704/go_gzip_all_core.png" />
            
            </figure><p>Gzip performance is pretty good. The single core Falkor performance is way below both Intel processors, but at the system level it manages to outperform Broadwell, and lags behind Skylake. Since we already know that Falkor outperforms both when C is used, it can only mean that Go’s backend for ARMv8 is still pretty immature compared to gcc.</p>
    <div>
      <h4>Go regexp</h4>
      <a href="#go-regexp">
        
      </a>
    </div>
    <p>Regexp is widely used in a variety of tasks, so its performance is quite important too. I ran the built-in benchmarks on 32KB strings.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2AhmqRQhO37Z03KXfz9PUk/9b39646f7e800c9a7c8565134d516815/go_regexp_easy_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PH0IDtvODvYcGbECgOvEt/fbb7c4a099ad2b478aa12b8f3b7fb0a0/go_regexp_easy_all_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7eAhDauk00ZR4A37NPqQm5/8f1c94f9d34087b57b8672a4928e76a7/go_regexp_comp_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ytsG1skhi4B1v24tqlrWw/d0d803c543a990854bd60916ed03b089/go_regexp_comp_all_core.png" />
            
            </figure><p>Go regexp performance is not very good on Falkor. In the medium and hard tests it takes second place, thanks to the higher core count, but Skylake is significantly faster still.</p><p>Doing some profiling shows that a lot of the time is spent in the function bytes.IndexByte. This function has an assembly implementation for amd64 (runtime.indexbytebody), but generic implementation for Go. The easy regexp tests spend most time in this function, which explains the even wider gap.</p>
    <div>
      <h4>Go strings</h4>
      <a href="#go-strings">
        
      </a>
    </div>
    <p>Another important library for a web server is the Go strings library. I only tested the basic Replacer class here.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/G20n7Ru5izVdUBOMM8af7/9a257ef47b5a38e3f745a22da7f36da5/go_str_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2W6GTABFY1t23YOIhyLc1A/ce51cb7081718a724b797f39e7ff80e2/go_str_all_core.png" />
            
            </figure><p>In this test again, Falkor lags behind, and loses even to Broadwell. Profiling shows significant time is spent in the function runtime.memmove. Guess what? It has a highly optimized assembly code for amd64, that uses AVX2, but only very simple ARM assembly, that copies 8 bytes at a time. By changing three lines in that code, and using the LDP/STP instructions (load pair/store pair) to copy 16 bytes at a time, I improved the performance of memmove by 30%, which resulted in 20% faster EscapeString and UnescapeString performance. And that is just scratching the surface.</p>
    <div>
      <h4>Go conclusion</h4>
      <a href="#go-conclusion">
        
      </a>
    </div>
    <p>Go support for aarch64 is quite disappointing. I am very happy to say that everything compiles and works flawlessly, but on the performance side, things should get better. Is seems like the enablement effort so far was concentrated on the compiler back end, and the library was left largely untouched. There are a lot of low hanging optimization fruits out there, like my 20-minute fix for <a href="https://go-review.googlesource.com/c/go/+/76270">addMulVVW</a> clearly shows. Qualcomm and other ARMv8 vendors intends to put significant engineering resources to amend this situation, but really anyone can contribute to Go. So if you want to leave your mark, now is the time.</p>
    <div>
      <h3>LuaJIT</h3>
      <a href="#luajit">
        
      </a>
    </div>
    <p>Lua is the glue that holds Cloudflare together.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/eTdeElawEbvCLpjM9XMUa/8527a83cf68acc1e6a48af94860b190c/luajit_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ohY0uFyotdk0eJt9lU725/472f32803de7ecd6e2d95f27948aa85a/luajit_all_cores.png" />
            
            </figure><p>Except for the binary_trees benchmark, the performance of LuaJIT on ARM is very competitive. It wins two benchmarks, and is in almost a tie in a third one.</p><p>That being said, binary_trees is a very important benchmark, because it triggers many memory allocations and garbage collection cycles. It will require deeper investigation in the future.</p>
    <div>
      <h3>NGINX</h3>
      <a href="#nginx">
        
      </a>
    </div>
    <p>For the NGINX workload, I decided to generate a load that would resemble an actual server.</p><p>I set up a server that serves the HTML file used in the gzip benchmark, over https, with the ECDHE-ECDSA-AES128-GCM-SHA256 cipher suite.</p><p>It also uses LuaJIT to redirect the incoming request, remove all line breaks and extra spaces from the HTML file, while adding a timestamp. The HTML is then compressed using brotli with quality 5.</p><p>Each server was configured to work with as many workers as it has virtual CPUs. 40 for Broadwell, 48 for Skylake and 46 for Falkor.</p><p>As the client for this test, I used the <a href="https://github.com/rakyll/hey">hey</a> program, running from 3 Broadwell servers.</p><p>Concurrently with the test, we took power readings from the respective BMC units of each server.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3d3OUyJ1m0q11IoWUNCyTp/5cde6f742d596d71d14e5f1355a4b570/nginx.png" />
            
            </figure><p>With the NGINX workload Falkor handled almost the same amount of requests as the Skylake server, and both significantly outperform Broadwell. The power readings, taken from the BMC show that it did so while consuming less than half the power of other processors. That means Falkor managed to get 214 requests/watt vs the Skylake’s 99 requests/watt and Broadwell’s 77.</p><p>I was a bit surprised to see Skylake and Broadwell consume about the same amount of power, given both are manufactured with the same process, and Skylake has more cores.</p><p>The low power consumption of Falkor is not surprising, Qualcomm processors are known for their great power efficiency, which has allowed them to be a dominant player in the mobile phone CPU market.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>The engineering sample of Falkor we got certainly impressed me a lot. This is a huge step up from any previous attempt at ARM based servers. Certainly core for core, the Intel Skylake is far superior, but when you look at the system level the performance becomes very attractive.</p><p>The production version of the Centriq SoC will feature up to 48 Falkor cores, running at a frequency of up to 2.6GHz, for a potential additional 8% better performance.</p><p>Obviously the Skylake server we tested is not the flagship Platinum unit that has 28 cores, but those 28 cores come both with a big price and over 200W TDP, whereas we are interested in improving our bang for buck metric, and performance per watt.</p><p>Currently, my main concern is weak Go language performance, but that is bound to improve quickly once ARM based servers start gaining some market share.</p><p>Both C and LuaJIT performance is very competitive, and in many cases outperforms the Skylake contender. In almost every benchmark Falkor shows itself as a worthy upgrade from Broadwell.</p><p>The largest win by far for Falkor is the low power consumption. Although it has a TDP of 120W, during my tests it never went above 89W (for the go benchmark). In comparison, Skylake and Broadwell both went over 160W, while the TDP of the two CPUs is 170W.</p><p><i>If you enjoy testing and selecting hardware on behalf of millions of Internet properties, come [join us](</i><a href="https://www.cloudflare.com/careers/"><i>https://www.cloudflare.com/careers/</i></a><i>).</i></p> ]]></content:encoded>
            <category><![CDATA[SSL]]></category>
            <category><![CDATA[OpenSSL]]></category>
            <category><![CDATA[Compression]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">3Rk7Ip66PBd0Hn31OM4NuO</guid>
            <dc:creator>Vlad Krasnov</dc:creator>
        </item>
        <item>
            <title><![CDATA[Helping to make LuaJIT faster]]></title>
            <link>https://blog.cloudflare.com/helping-to-make-luajit-faster/</link>
            <pubDate>Thu, 19 Oct 2017 07:38:25 GMT</pubDate>
            <description><![CDATA[ Programming language Virtual Machines (VMs) are familiar beasts: we use them to run apps on our phone, code inside our browsers, and programs on our servers.  ]]></description>
            <content:encoded><![CDATA[ <p><i>This is a guest post by </i><a href="http://tratt.net/laurie/"><i>Laurence Tratt</i></a><i>, who is a programmer and Reader in Software Development in the </i><a href="http://www.kcl.ac.uk/nms/depts/informatics/"><i>Department of Informatics</i></a><i> at </i><a href="http://www.kcl.ac.uk/"><i>King's College London</i></a><i> where he leads the </i><a href="http://soft-dev.org/"><i>Software Development Team</i></a><i>. He is also an </i><a href="http://soft-dev.org/projects/lecture/"><i>EPSRC Fellow</i></a><i>.</i></p><p>Programming language Virtual Machines (VMs) are familiar beasts: we use them to run apps on our phone, code inside our browsers, and programs on our servers. Traditional VMs are useful and widely used: nearly every working programmer is familiar with one or more of the “standard” Lua, Python, or Ruby VMs. However, such VMs are simplistic, containing only an interpreter (a simple implementation of a language). These often can’t run our programs as fast as we need; and, even when they can, they often waste huge amounts of server CPU time. We sometimes forget that servers consume a large, and growing, chunk of the world’s electricity output: slow language implementations are, quite literally, changing the world, and not in a good way.</p><p>More advanced VMs come with Just-In-Time (JIT) compilers (well known examples include LuaJIT, HotSpot (aka “the JVM”), PyPy, and V8). Such VMs observe a program’s run-time behaviour and use that to compile frequently executed parts of the program into machine code. When this works well, it leads to significant speed-ups (2x-10x is common; and 100x is not unknown). We all want to make these VMs even better than they currently are, but doing so is easier said than done.</p><p>Internally, VMs with JIT compilers are ferociously complex beasts, with many moving parts that interact in subtle ways that are hard to reason about. For example, any VM developer worth their salt will have tales about “deoptimisation bugs”: that is, bugs that occur when the optimised machine code is no longer useful and the VM has to fall back to a less optimised, but more general, version of the program (e.g. an interpreter). Have you ever thought about how to pick apart an inlined function’s stack? Perhaps it sounds quite easy. What happens when inlining has allowed the JIT compiler to remove memory allocations: how should the “missing” allocations be identified and “restored”? Even in just this single part of a VM, the complexity quickly becomes mind-boggling.</p><p>What does this have to do with Cloudflare or me? Well, as many of you know, Cloudflare is a heavy user of LuaJIT and they would like LuaJIT to perform even better than it does today. Although Cloudflare has developers with a deep understanding of LuaJIT, they’ve long wanted to give more back to the open-source community. Unfortunately, finding someone who’s able and willing to work on such a complicated program isn’t easy, to say the least. I suggested that our research group – the <a href="http://soft-dev.org/">Software Development Team</a> at King's College London – might provide a fruitful alternative route. Happily, Cloudflare agreed, and gave us funding for a project looking to improve LuaJIT's performance that started in late August.</p><p>Why our team? Well, partly because we've done a lot of VM work from <a href="http://tratt.net/laurie/research/pubs/html/bolz_diekmann_tratt__storage_strategies_for_collections_in_dynamically_typed_languages/">data-structure optimisation</a> to <a href="http://soft-dev.org/pubs/html/barrett_bolz_diekmann_tratt__fine_grained_language_composition/">language composition</a> to <a href="http://soft-dev.org/pubs/html/barrett_bolz-tereick_killick_mount_tratt__virtual_machine_warmup_blows_hot_and_cold_v6/">benchmarking</a>, which helps us get people new to the field up and running quickly. Partly, I like to think, because we're open-minded about the projects we use as part of our research. Although we've not done a huge amount of direct LuaJIT research, we've always tried to stay abreast of its development (e.g. leading to us inviting <a href="https://www.youtube.com/watch?v=EaLboOUG9VQ&amp;list=PLJq3XDLIJkib2h2fObomdFRZrQeJg4UIW">Vyacheslav Egorov to talk about LuaJIT</a> at the <a href="http://soft-dev.org/events/vmss16/">VM Summer School</a> we ran in 2016), and we've often used it as a key part of cross-VM benchmarking.</p><p>Personally I've been aware of LuaJIT for many years: I submitted a very, very minor patch to make it run on OpenBSD in 2012 so that I could try out this VM that I'd heard others rave about; I used LuaJIT's clever assembly system in a small toy project; and I've included LuaJIT in more than one benchmarking suite (e.g. <a href="http://tratt.net/laurie/research/pubs/html/bolz_tratt__the_impact_of_metatracing_on_vm_design_and_implementation/">this paper</a>). My first impression was that LuaJIT has an astonishingly small codebase and astonishingly fast warmup (roughly speaking, the time from the program starting to final machine code being generated). Both those points remain true today, and are a testament to Mike Pall’s vision and coding abilities. However, benchmarking LuaJIT against other VMs has shown weaknesses, which, I’ve come to realise, are widely known by those using LuaJIT on large systems. In a nutshell, larger programs exhibit substantial performance differences from one run to the next, and some programs don’t run as fast over long periods as other VMs are capable of. I don’t see this as a criticism – every VM I’m familiar with has strengths and weaknesses – but rather as an opportunity to see if we can make things even better.</p><p>How are we going to go about trying to improve LuaJIT? First, we had one of those strokes of luck you can normally only dream about: after conversations with some friendly LuaJIT insiders, I was very lucky to tempt Thomas Fransham, a LuaJIT expert, to work with us at King’s. Tom’s deep understanding of LuaJIT’s internals means we have someone who can immediately start turning ideas into reality. Second, we’re making use of our multi-year work on VM benchmarking which recently saw the light of day as the <a href="http://soft-dev.org/pubs/html/barrett_bolz-tereick_killick_mount_tratt__virtual_machine_warmup_blows_hot_and_cold_v6/">Virtual Machine Warmup Blows Hot and Cold</a> paper and the <a href="http://soft-dev.org/src/krun/">Krun</a> and <a href="http://soft-dev.org/src/warmup_stats/">warmup_stats</a> systems. To cut a long and dense paper short, we found that, even in an idealised setting, widely studied benchmarks often don’t warm-up as they’re supposed to on well known VMs. Sometimes they get slower over time; sometimes they never stabilise; sometimes they’re inconsistent from one execution to the next. Even in the best case, we found that, across all the VMs we studied, only 43.5% of cases warmed up as they were supposed to (at 51%, LuaJIT was a little better than some VMs). While this is somewhat embarrassing news for those of us who develop VMs, it’s forced me to make two hypotheses (which is a fancy word for “gut feeling”) which we’ll test in this project: that VMs have heuristics (e.g. “when to compile code”) which interact in ways we no longer understand; and that rigorous benchmarking before and after changes (whether those changes add or remove code) is the only way to make performance better and more predictable.</p><p>As this might suggest, we’re not aiming to “just” improve LuaJIT. This project will also naturally help us advance our wider research interests centred around understanding how VM performance can be improved. I’m hopeful that what we learn from LuaJIT will, in the long run, also help other VMs improve. Indeed, we have big ideas for what the next generation of VMs might look like, and we’re bound to learn important lessons from this project. Our long-term bet is on meta-tracing: we think we can reduce its currently fearsome warmup costs through a combination of Intel’s newish Processor Tracing feature and some other tricks we have up our sleeves. That then opens up new possibilities to do things like parallel compilation that haven’t really been thought worthwhile before. While LuaJIT isn’t a meta-tracing JIT compiler, it is a tracing JIT compiler and, as the similar name suggests, most concepts carry over from one to the other.</p><p>To say that I’m extremely grateful to Cloudflare for their support is an understatement. It might not be obvious from the outside, but (apart from me) everyone in our research group is supported by external funding: without it, I can’t pay good people like Tom to help move the subject forward. I’m also pleased to say that, before I even asked, Cloudflare made clear that they wanted all the project’s results to be open. Any and all changes we make will be fully open-sourced under LuaJIT’s normal license, so as and when we make improvements to LuaJIT, the whole LuaJIT community will benefit. I also want us, more generally, to be good citizens within the wider LuaJIT community. We know we have a lot to learn from you, from ideas for benchmarking, to concrete experiences of performance problems. Don’t be shy about getting in touch!</p> ]]></content:encoded>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[LUA]]></category>
            <guid isPermaLink="false">4fWU9BxRXsAOjnY1opemQM</guid>
            <dc:creator>Guest Author</dc:creator>
        </item>
        <item>
            <title><![CDATA[LuaJIT Hacking: Getting next() out of the NYI list]]></title>
            <link>https://blog.cloudflare.com/luajit-hacking-getting-next-out-of-the-nyi-list/</link>
            <pubDate>Tue, 21 Feb 2017 13:40:23 GMT</pubDate>
            <description><![CDATA[ At Cloudflare we’re heavy users of LuaJIT and in the past have sponsored many improvements to its performance.

 ]]></description>
            <content:encoded><![CDATA[ <p>At Cloudflare we’re heavy users of LuaJIT and in the past have sponsored many improvements to its performance.</p><p>LuaJIT is a powerful piece of software, maybe the highest performing JIT in the industry. But it’s not always easy to get the most out of it, and sometimes a small change in one part of your code can negatively impact other, already optimized, parts.</p><p>One of the first pieces of advice anyone receives when writing Lua code to run quickly using LuaJIT is “avoid the NYIs”: the language or library features that can’t be compiled because they’re NYI (not yet implemented). And that means they run in the interpreter.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1iZfOn4qOz1IUbak9b2uFF/d13073febe4074591ddb70d51fdfc301/6822250770_d6f8399cf2_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/zengei/6822250770/in/photolist-boRPth-7xeiAm-e6H8w5-dSoqGF-FiYGj-okoVwy-e1ugbE-dXhvop-8fQNCX-974Bts-ekbDjn-p9HV9L-971y78-bdb8Hi-e2Us2u-8fU4pm-9ZFfXg-g469T-7Ft9Jc-9YWa6m-95HYN2-95J19D-5JeU76-95M3qb-PFZRj-9uYpbM-6bJrpt-D2DfZK-Ccqoxs-Jqvvxd-kSQzNX-JyLzNN-dEnx4T-dezBQR-e2NN7a-6aP8op-971xFi-974BBJ-qR8GWh-5De3Sy-974CTy-gyUry-dezAkY-7qHBJ2-eHJH4W-9v2qQs-dCQMt7-nBkbJ7-eZ8yc-e3u6kJ">image</a> by <a href="https://www.flickr.com/photos/zengei/">Dwayne Bent</a></p><p>Another very attractive feature of LuaJIT is the FFI library, which allows Lua code to directly interface with C code and memory structures. The JIT compiler weaves these memory operations in line with the generated machine language, making it much more efficient than using the traditional Lua C API.</p><p>Unfortunately, if for any reason the Lua code using the FFI library has to run under the interpreter, it takes a very heavy performance hit. As it happens, under the interpreter the FFI is usually much slower than the Lua C API or the basic operations. For many people, this means either avoiding the FFI or committing to a permanent vigilance to maintain the code from falling back to the interpreter.</p>
    <div>
      <h3>Optimizing LuaJIT Code</h3>
      <a href="#optimizing-luajit-code">
        
      </a>
    </div>
    <p>Before optimizing any code, it’s important to identify which parts are actually important. It’s useless to discuss what’s the fastest way to add a few numbers before sending some data, if the send operation will take a million times longer than that addition. Likewise, there’s no benefit avoiding NYI features in code like initialization routines that might run only a few times, as it’s unlikely that the JIT would even try to optimize them, so they would always run in the interpreter. Which, by the way, is also very fast; even faster than the first version of LuaJIT itself.</p><p>But optimizing the core parts of a Lua program, like any deep inner loops, can yield huge improvements in the overall performance. In similar situations, experienced developers using other languages are used to inspecting the assembly language generated by the compiler, to see if there’s some change to the source code that can make the result better.</p><p>The command line LuaJIT executable provides a bytecode list when running with the <code>-jbc</code> option, a statistical profiler, activated with the <code>-jp</code> option, a trace list with <code>-jv</code>, and finally a detailed dump of all the JIT operations with <code>-jdump</code>.</p><p>The last two provide lots of information very useful for understanding what actually happens with the Lua code while executing, but it can be a lot of work to read the huge lists generated by <code>-jdump</code>. Also, some messages are hard to understand without a fairly complete understanding of how the tracing compiler in LuaJIT actually works.</p><p>One very nice feature is that all these JIT options are implemented in Lua. To accomplish this the JIT provides ‘hooks’ that can execute a Lua function at important moments with the relevant information. Sometimes the best way to understand what some <code>-jdump</code> output actually means is to read the code that generated that specific part of the output.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ofHRCoePgNqk4t0T1HlqM/b682959718d54d07c604c0e084111dd2/6353190489_1363ec7f16_z.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> <a href="https://www.flickr.com/photos/kevandotorg/6353190489/in/photolist-aFpLc4-6Rorty-gvhKC9-8UEeqU-aBoHof-9qr8bs-9qo6Ai-9qrafb-FhYA4L-CH4r5G-8HZcMK-pX32R-6SJMc6-pX39e-oXee8D-aBoHBJ-cLgitL-cLgeKY-3THPb-hzKrGL-cLggDJ-6Rh35p-dqkQyJ-7Ey5Pz-6RkwNh-6RgYDe-7C7F9S-6RgxKH-6RkLFN-i4HqqU-6Rktx9-6RkXKQ-6RgRqD-6RkmBs-6RgML2-6RkE4j-6Rg5nT-6RjKkq-6RfDK2-6RfRRc-6RfYfK-6RfUT8-6RjN4d-hzMBtc-hzNnyN-hzJiM8-hzJVpv-hzLE56-hzKU4c-9mQrRy">image</a> by <a href="https://www.flickr.com/photos/kevandotorg/">Kevan</a></p>
    <div>
      <h3>Introducing Loom</h3>
      <a href="#introducing-loom">
        
      </a>
    </div>
    <p>After several rounds there, and being frustrated by the limitations of the sequentially-generated dump, I decided to write a different version of <code>-jdump</code>, one that gathered more information to process and add cross-references to help see how things are related before displaying. The result is <a href="https://github.com/cloudflare/loom">loom</a>, which shows roughly the same information as <code>-jdump</code>, but with more resolved references and formatted in HTML with tables, columns, links and colors. It has helped me a lot to understand my own code and the workings of LuaJIT itself.</p><p>For example, let's consider the following code in a file called <code>twoloops.lua</code>:</p>
            <pre><code>for i=1,1000 do
    for j=1,1000 do
    end
end</code></pre>
            <p>With the <code>-jv</code> option:</p>
            <pre><code>$ luajit -jv twoloops.lua
[TRACE   1 twoloops.lua:2 loop]
[TRACE   2 (1/3) twoloops.lua:1 -&gt; 1]</code></pre>
            <p>This tells us that there were two traces, the first one contains a loop, and the second one spawns from exit #3 of the other (the “(1/3)” part) and it’s endpoint returns to the start of trace #1.</p><p>Ok, let’s get more detail with <code>-jdump</code>:</p>
            <pre><code>$ luajit -jdump twoloops.lua
---- TRACE 1 start twoloops.lua:2
0009  FORL     4 =&gt; 0009
---- TRACE 1 IR
0001    int SLOAD  #5    CI
0002  + int ADD    0001  +1  
0003 &gt;  int LE     0002  +1000
0004 ------ LOOP ------------
0005  + int ADD    0002  +1  
0006 &gt;  int LE     0005  +1000
0007    int PHI    0002  0005
---- TRACE 1 mcode 47
0bcbffd1  mov dword [0x40db1410], 0x1
0bcbffdc  cvttsd2si ebp, [rdx+0x20]
0bcbffe1  add ebp, +0x01
0bcbffe4  cmp ebp, 0x3e8
0bcbffea  jg 0x0bcb0014	-&gt;1
-&gt;LOOP:
0bcbfff0  add ebp, +0x01
0bcbfff3  cmp ebp, 0x3e8
0bcbfff9  jle 0x0bcbfff0	-&gt;LOOP
0bcbfffb  jmp 0x0bcb001c	-&gt;3
---- TRACE 1 stop -&gt; loop

---- TRACE 2 start 1/3 twoloops.lua:1
0010  FORL     0 =&gt; 0005
0005  KSHORT   4   1
0006  KSHORT   5 1000
0007  KSHORT   6   1
0008  JFORI    4 =&gt; 0010
---- TRACE 2 IR
0001    num SLOAD  #1    I
0002    num ADD    0001  +1  
0003 &gt;  num LE     0002  +1000
---- TRACE 2 mcode 81
0bcbff79  mov dword [0x40db1410], 0x2
0bcbff84  movsd xmm6, [0x41704068]
0bcbff8d  movsd xmm5, [0x41704078]
0bcbff96  movsd xmm7, [rdx]
0bcbff9a  addsd xmm7, xmm6
0bcbff9e  ucomisd xmm5, xmm7
0bcbffa2  jb 0x0bcb0014	-&gt;1
0bcbffa8  movsd [rdx+0x38], xmm6
0bcbffad  movsd [rdx+0x30], xmm6
0bcbffb2  movsd [rdx+0x28], xmm5
0bcbffb7  movsd [rdx+0x20], xmm6
0bcbffbc  movsd [rdx+0x18], xmm7
0bcbffc1  movsd [rdx], xmm7
0bcbffc5  jmp 0x0bcbffd1
---- TRACE 2 stop -&gt; 1</code></pre>
            <p>This tells us... well, a lot of things. If you look closely, you’ll see the same two traces, one is a loop, the second starts at <code>1/3</code> and returns to trace #1. Each one shows some bytecode instructions, an IR listing, and the final mcode. There are several options to turn on and off each listing, and more info like the registers allocated to some IR instructions, the “snapshot” structures that allow the interpreter to continue when a compiled trace exits, etc.</p><p>Now using loom:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2017/02/image00.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2gsTyF05jZO2nJd8HvEec8/9deaa76956425f382f1e68aba1e9b13e/image00.png" />
            </a>
            </figure><p>There’s the source code, with the corresponding bytecodes, and the same two traces, with IR and mcode listings. The bytecode lines on the traces and on the top listings are linked, hovering on some arguments on the IR listing highlights the source and use of each value, the jumps between traces are correctly labeled (and colored), finally, clicking on the bytecode or IR column headers reveals more information: excerpts from the source code and snapshot formats, respectively.</p><p>Writing it was a great learning experience, I had to read the dump script’s Lua sources and went much deeper in the LuaJIT sources than ever before. And then, I was able to use loom not only to analyze and optimize Cloudflare’s Lua code, but also to watch the steps the compiler goes through to make it run fast, and also what happens when it’s not happy.</p>
    <div>
      <h3>The code is the code is the code is the code</h3>
      <a href="#the-code-is-the-code-is-the-code-is-the-code">
        
      </a>
    </div>
    <p>LuaJIT handles up to four different representation of a program’s code:</p><p>First comes the source code, what the developer writes.</p><p>The parser analyzes the source code and produces the Bytecode, which is what the interpreter actually executes. It has the same flow of the source code, grouped in functions, with all the calls, iterators, operations, etc. Of course, there’s no nice formatting, comments, the local variable names are replaced by indices, and all constants (other than small numbers) are stored in a separate area.</p><p>When the interpreter finds that a given point of the bytecode has been repeated several times, it’s considered a “hot” part of the code, and interprets it once again but this time it records each bytecode it encounters, generating a “code trace” or just “a trace”. At the same time, it generates an “intermediate representation”, or IR, of the code as it’s executed. The IR doesn’t represent the whole of the function or code portion, just the actual options it actually takes.</p><p>A trace is finished when it hits a loop or a recursion, returns to a lower level than when started, hits a NYI operation, or simply becomes too long. At this point, it can be either compiled into machine language, or aborted if it has reached some code that can’t be correctly translated. If successful, the bytecode is patched with an entry to the machine code, or “mcode”. If aborted, the initial trace point is “penalized” or even “blocklisted” to avoid wasting time trying to compile it again.</p>
    <div>
      <h3>What’s <code>next()</code>?</h3>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>One of the most visible characteristics of the Lua language is the heavy use of dictionary objects called <i>tables</i>. From the <a href="https://www.lua.org/manual/5.1/manual.html#2.2">Lua manual</a>:</p><p><i>“Tables are the sole data structuring mechanism in Lua; they can be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc.”</i></p><p>To iterate over all the elements in a table, the idiomatic way is to use the standard library function <code>pairs()</code> like this:</p>
            <pre><code>for k, v in pairs(t) do
    -- use the key in ‘k’ and the value in ‘v’
end</code></pre>
            <p>In the standard Lua manual, <code>pairs()</code> is <a href="https://www.lua.org/manual/5.1/manual.html#pdf-pairs">defined</a> as “Returns three values: the <code>next</code> function, the table <code>t</code>, and <code>nil</code>”, so the previous code is the same as:</p>
            <pre><code>for k, v in next, t, nil do
    -- use the key in ‘k’ and the value in ‘v’
end</code></pre>
            <p>But unfortunately, both the <code>next()</code> and <code>pairs()</code> functions are listed as “not compiled” in the feared <a href="http://wiki.luajit.org/NYI#libraries_base-library">NYI list</a>. That means that any such code runs on the interpreter and is not compiled, unless the code inside is complex enough, and has other inner loops (loops that doesn’t use <code>next()</code> or <code>pairs()</code>, of course). Even in that case, the code would have to fall back to the interpreter at each loop end.</p><p>This sad news creates a tradeoff: for performance sensitive parts of the code, don’t use the most Lua-like code style. That motivates people to come up with several contortions to be able to use numerical iteration (which is compiled, and very efficient), like replacing any key with a number, storing all the keys in a numbered array, or store both keys and values at even/odd numeric indices.</p>
    <div>
      <h3>Getting <code>next()</code> out of the NYI list</h3>
      <a href="#getting-next-out-of-the-nyi-list">
        
      </a>
    </div>
    <p>So, I finally have a non-NYI <code>next()</code> function! I'd like to say "a fully JITtable <code>next()</code> function", but it wouldn't be totally true; as it happens, there's no way to avoid some annoying trace exits on table iteration.</p><p>The purpose of the IR is to provide a representation of the execution path so it can be quickly optimized to generate the final mcode. For that, the IR traces are linear and type-specific; creating some interesting challenges for iteration on a generic container.</p>
    <div>
      <h3>Traces are linear</h3>
      <a href="#traces-are-linear">
        
      </a>
    </div>
    <p>Being linear means that each trace captures a single execution path, it can't contain conditional code or internal jumps. The only conditional branches are the "guards" that make sure that the code to be executed is the appropriate one. If a condition changes and it must now do something different, the trace must be exited. If it happens several times, it will spawn a side trace and the exit will be patched into a conditional branch. Very nice, but this still means that there can be at most one loop on each trace.</p><p>The implementation of <code>next()</code> has to internally skip over empty slots in the table to only return valid key/value pairs. If we try to express this in IR code, this would be the "inner" loop and the original loop would be an "outer" one, which doesn't have as much optimization opportunities. In particular, it can't hoist invariable code out of the loop.</p><p>The solution is to do that slot skipping in C. Not using the Lua C API, of course, but the inner IR CALL instruction that is compiled into a "fast" call, using CPU registers for arguments as much as possible.</p>
    <div>
      <h3>The IR is in Type-specific SSA form</h3>
      <a href="#the-ir-is-in-type-specific-ssa-form">
        
      </a>
    </div>
    <p>The SSA form (<a href="https://en.wikipedia.org/wiki/Static_single_assignment_form">Static Single Assignment</a>) is key for many data flow analysis heuristics that allow quick optimizations like dead code removal, allocation sinking, type narrowing, strength reduction, etc. In LuaJIT's IR it means every instruction is usable as a value for subsequent instructions and has a declared type, fixed at the moment when the trace recorder emits this particular IR instruction. In addition, every instruction can be a type guard, if the arguments are not of the expected type the trace will be exited.</p><p>Lua is dynamically typed, every value is tagged with type information so the bytecode interpreter can apply the correct operations on it. This allows us to have variables and tables that can contain and pass around any kind of object without changing the source code. Of course, this requires the interpreter to be coded very "defensively", to consider all valid ramifications of every instruction, limiting the possibility of optimizations. The IR traces, on the other hand, are optimized for a single variation of the code, and deal with only the value types that are actually observed while executing.</p><p>For example, this simple code creates a 1,000 element array and then copies to another table:</p>
            <pre><code>local t,t2 = {},{}
for i=1,1000 do
    t[i] = i
end
for i,v in ipairs(t) do
    t2[i]=v
end</code></pre>
            <p>resulting in this IR for the second loop, the one that does the copy:</p>
            <pre><code>0023 ------------ LOOP ------------
0024          num CONV   0017  num.int
0025       &gt;  int ABC    0005  0017
0026          p32 AREF   0007  0017
0027          num ASTORE 0026  0022
0028 rbp    + int ADD    0017  +1
0029       &gt;  int ABC    0018  0028
0030          p32 AREF   0020  0028
0031 xmm7  &gt;+ num ALOAD  0030
0032 xmm7     num PHI    0022  0031
0033 rbp      int PHI    0017  0028
0034 rbx      nil RENAME 0017  #3
0035 xmm6     nil RENAME 0022  #2</code></pre>
            <p>Here we see the <code>ALOAD</code> in instruction <code>0031</code> assures that the value loaded from the table is in effect a number. If it happens to be any other value, the guard fails and the trace is exited.</p><p>But if we do an array of strings instead of numbers?</p><p>a small change:</p>
            <pre><code>local t,t2 = {},{}
for i=1,1000 do
    t[i] = 's'..i
end
for i,v in ipairs(t) do
    t2[i]=v
end</code></pre>
            <p>gives us this:</p>
            <pre><code>0024 ------------ LOOP ------------
0025          num CONV   0018  num.int
0026       &gt;  int ABC    0005  0018
0027          p32 AREF   0007  0018
0028          str ASTORE 0027  0023
0029 rbp    + int ADD    0018  +1
0030       &gt;  int ABC    0019  0029
0031          p32 AREF   0021  0029
0032 rbx   &gt;+ str ALOAD  0031
0033 rbx      str PHI    0023  0032
0034 rbp      int PHI    0018  0029
0035 r15      nil RENAME 0018  #3
0036 r14      nil RENAME 0023  #2</code></pre>
            <p>It's the same code, but the type that <code>ALOAD</code> is guarding is now a string (and it now uses a different register, I guess a vector register isn't appropriate for a string pointer).</p><p>And if the table has a values of a mix of types?</p>
            <pre><code>local t,t2={},{}
for i=1,1000,2 do
    t[i], t[i+1] = i, 's'..i
end
for i,v in ipairs(t)
    do t2[i]=v
end

0031 ------------ LOOP ------------
0032          num CONV   0027  num.int
0033       &gt;  int ABC    0005  0027
0034          p32 AREF   0007  0027
0035          str ASTORE 0034  0030
0036 r15      int ADD    0027  +1
0037       &gt;  int ABC    0019  0036
0038          p32 AREF   0021  0036
0039 xmm7  &gt;  num ALOAD  0038
0040       &gt;  int ABC    0005  0036
0041          p32 AREF   0007  0036
0042          num ASTORE 0041  0039
0043 rbp    + int ADD    0027  +2
0044       &gt;  int ABC    0019  0043
0045          p32 AREF   0021  0043
0046 rbx   &gt;+ str ALOAD  0045
0047 rbx      str PHI    0030  0046
0048 rbp      int PHI    0027  0043</code></pre>
            <p>Now there are two <code>ALOAD</code>s, (and two <code>ASTORE</code>s), one for 'num' and one for 'str'. In other words, the JIT unrolled the loop and found that that made the types constant. <code>=8-O</code></p><p>Of course, this would happen only on very simple and regular patterns. In general, it's wiser to avoid unpredictable type mixing; but polymorphic code will be optimized for each type that it's actually used with.</p>
    <div>
      <h3>Back to <code>next()</code></h3>
      <a href="#back-to-next">
        
      </a>
    </div>
    <p>First let's see the current implementation of <code>next()</code> as used by the interpreter:</p>
            <pre><code>lj_tab.c
/* Advance to the next step in a table traversal. */
int lj_tab_next(lua_State *L, GCtab *t, TValue *key)
{
  uint32_t i = keyindex(L, t, key);  /* Find predecessor key index. */
  for (i++; i &lt; t-&gt;asize; i++)  /* First traverse the array keys. */
    if (!tvisnil(arrayslot(t, i))) {
      setintV(key, i);
      copyTV(L, key+1, arrayslot(t, i));
      return 1;
    }
  for (i -= t-&gt;asize; i &lt;= t-&gt;hmask; i++) {  /* Then traverse the hash keys. */
    Node *n = &amp;noderef(t-&gt;node)[i];
    if (!tvisnil(&amp;n-&gt;val)) {
      copyTV(L, key, &amp;n-&gt;key);
      copyTV(L, key+1, &amp;n-&gt;val);
      return 1;
    }
  }
  return 0;  /* End of traversal. */
}</code></pre>
            <p>It takes the input key as a <code>TValue</code> pointer and calls <code>keyindex()</code>. This helper function searches for the key in the table and returns an index; if the key is an integer in the range of the array part, the index is the key itself. If not, it performs a hash query and returns the index of the Node, offset by the array size, if successful, or signals an error if not found (it's an error to give a nonexistent key to <code>next()</code>).</p><p>Back at <code>lj_tab_next()</code>, the index is first incremented, and if it's still within the array, it's iterated over any hole until a non-<code><b>nil</b></code> value is found. If it wasn't in the array (or there’s no next value there), it performs a similar "skip the **<code>nil</code>**s" on the Node table.</p><p>The new <code>lj_record_next()</code> function in <code>lj_record.c</code>, like some other record functions there, first checks not only the input parameters, but also the return values to generate the most appropriate code for this specific iteration, assuming that it will likely be optimal for subsequent iterations. Of course, any such assumption must be backed by the appropriate guard.</p><p>For <code>next()</code>, we choose between two different forms, if the return key is in the array part, then it uses <code>lj_tab_nexta()</code>, which takes the input key as an integer and returns the next key, also as an integer, in the <code>rax</code> register. We don't do the equivalent to the <code>keyindex()</code> function, just check (with a guard) that the key is within the bounds of the array:</p>
            <pre><code>lj_tab.c
/* Get the next array index */
MSize LJ_FASTCALL lj_tab_nexta(GCtab *t, MSize k)
{
  for (k++; k &lt; t-&gt;asize; k++)
    if (!tvisnil(arrayslot(t, k)))
      break;
  return k;
}</code></pre>
            <p>The IR code looks like this:</p>
            <pre><code>0014 r13      int FLOAD  0011  tab.asize
0015 rsi   &gt;  int CONV   0012  int.num
0017 rax    + int CALLL  lj_tab_nexta  (0011 0015)
0018       &gt;  int ABC    0014  0017
0019 r12      p32 FLOAD  0011  tab.array
0020          p32 AREF   0019  0017
0021 [8]   &gt;+ num ALOAD  0020</code></pre>
            <p>Clearly, the <code>CALL</code> itself (at <code>0017</code>) is typed as '<code>int</code>', as natural for an array key; and the <code>ALOAD</code> (<code>0021</code>) is '<code>num</code>', because that's what the first few values happened to be.</p><p>When we finish with the array part, the bounds check (instruction <code>ABC</code> on <code>0018</code>) would fail and soon new IR would be generated. This time we use the <code>lj_tab_nexth()</code> function.</p>
            <pre><code>lj_tab.c
LJ_FUNCA const Node *LJ_FASTCALL lj_tab_nexth(lua_State *L, GCtab *t, const Node *n)
{
  const Node *nodeend = noderef(t-&gt;node)+t-&gt;hmask;
  for (n++; n &lt;= nodeend; n++) {
    if (!tvisnil(&amp;n-&gt;val)) {
      return n;
    }
  }
  return &amp;G(L)-&gt;nilnode;
}</code></pre>
            <p>But before doing the "skip the **<code>nil</code>**s", we need to do a hash query to find the initial <code>Node</code> entry. Fortunately, the <code>HREF</code> IR instruction does that: This is the IR:</p>
            <pre><code>0014 rdx      p32 HREF   0011  0012
0016 r12      p32 CALLL  lj_tab_nexth  (0011 0014)
0017 rax   &gt;+ str HKLOAD 0016
0018 [8]   &gt;+ num HLOAD  0016</code></pre>
            <p>There's a funny thing here: <code>HREF</code> is supposed to return a reference to a value in the hash table, and the last argument in <code>lj_tab_nexth()</code> is a <code>Node</code> pointer. Let's see the <code>Node</code> definition:</p>
            <pre><code>lj_obj.h
/* Hash node. */
typedef struct Node {
  TValue val;       /* Value object. Must be first field. */
  TValue key;       /* Key object. */
  MRef next;        /* Hash chain. */
#if !LJ_GC64
  MRef freetop;     /* Top of free elements (stored in t-&gt;node[0]). */
#endif
} Node;</code></pre>
            <p>Ok... the value is the first field, and it says right there "Must be first field". Looks like it's not the first place with some hand-wavy pointer casts.</p><p>The return value of <code>lj_tab_next()</code> is a <code>Node</code> pointer, which can likewise be implicitly cast by <code>HLOAD</code> to get the value. To get the key, I added the <code>HKLOAD</code> instruction. Both are guarding for the expected types of the value and key, respectively.</p>
    <div>
      <h3>Let's take it for a spin</h3>
      <a href="#lets-take-it-for-a-spin">
        
      </a>
    </div>
    <p>So, how does it perform? These tests do a thousand loops over a 10,000 element table, first using <code>next()</code> and then <code>pairs()</code>, with a simple addition in the inner loop. To get <code>pairs()</code> compiled, I just disabled the <code>ISNEXT</code>/<code>ITERN</code> optimization, so it actually uses <code>next()</code>. In the third test the variable in the addition is initialized to <code>0ULL</code> instead of just <code>0</code>, triggering the use of FFI.</p><p>First test is with all 10,000 elements on sequential integers, making the table a valid sequence, so <code>ipairs()</code> (which is already compiled) can be used just as well:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2017/02/image02.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4m2lJk0jSnK7D5qd81PEgz/15ad27baf4c66609632dd903b5829f05/image02.png" />
            </a>
            </figure><p>So, compiled <code>next()</code> is quite a lot faster, but the <code>pairs()</code> optimization in the interpreter is very fast. On the other hand, the smallest smell of FFI completely trashes interpreter performance, while making compiled code slightly tighter. Finally, <code>ipairs()</code> is faster, but a big part of it is because it stops on the first <code><b>nil</b></code>, while <code>next()</code> has to skip over every <code><b>nil</b></code> at the end of the array, which by default can be up to twice as big as the sequence itself.</p><p>Now with 5,000 (sequential) integer keys and 5,000 string keys. Of course, we can't use <code>ipairs()</code> here:</p>
            <figure>
            <a href="http://staging.blog.mrk.cfdata.org/content/images/2017/02/image01.png">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2c4yKNAwBjIqqQDz8Em4Hr/56cb0a4af36b3f68df25b36367d8e30a/image01.png" />
            </a>
            </figure><p>Roughly the same pattern: the compiled <code>next()</code> performance is very much the same on the three forms (used directly, under <code>pairs()</code> and with FFI code), while the interpreter benefits from the <code>pairs()</code> optimization and almost dies with FFI. In this case, the interpreted <code>pairs()</code> actually surpasses the compiled <code>next()</code> performance, hinting that separately optimizing <code>pairs()</code> is still desirable.</p><p>A big factor in the interpreter <code>pairs()</code> is that it doesn't use <code>next()</code>; instead it directly drives the loop with a hidden variable to iterate in the <code>Node</code> table without having to perform a hash lookup on every step.</p><p>Repeating that in a compiled <code>pairs()</code> would be equally beneficial; but has to be done carefully to maintain compatibility with the interpreter. On any trace exit the interpreter would kick in and must be able to seamlessly continue iterating. For that, the rest of the system has to be aware of that hidden variable.</p><p>The best part of this is that we have lots of very challenging, yet deeply rewarding, work ahead of us! Come <a href="https://www.cloudflare.com/join-our-team/">work for us</a> on making LuaJIT faster and more.</p> ]]></content:encoded>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">5B1mXoduq5qwML56xx48yv</guid>
            <dc:creator>Javier Guerra</dc:creator>
        </item>
        <item>
            <title><![CDATA[First Bay Area OpenResty Meetup]]></title>
            <link>https://blog.cloudflare.com/first-bay-area-openresty-meetup/</link>
            <pubDate>Mon, 09 May 2016 08:17:07 GMT</pubDate>
            <description><![CDATA[ On March 9, 章亦春, known to most of us as agentzh, organized the first Bay Area OpenResty Meetup at CloudFlare's San Francisco office. ]]></description>
            <content:encoded><![CDATA[ <p>On March 9, <a href="https://agentzh.org/">章亦春</a>, known to most of us as agentzh, organized the first <a href="http://www.meetup.com/Bay-Area-OpenResty-Meetup/">Bay Area OpenResty Meetup</a> at CloudFlare's San Francisco office.</p><p>CloudFlare is a big user of Lua, LuaJIT, NGINX and OpenResty and happy to be able to sponsor Yichun's work on this fast, flexible platform.</p><p>The slides and videos from the meetup are now available for viewing by people who were unable to be there in person.</p>
    <div>
      <h3><i>abode.io</i> by Dragos Dascalita of Adobe</h3>
      <a href="#abode-io-by-dragos-dascalita-of-adobe">
        
      </a>
    </div>
    <p>   </p><p>The slides are <a href="https://openresty.org/slides/adobe-io-openresty-meetup.pdf">here</a>.</p>
    <div>
      <h3><i>KONG</i> by Marco Palladino from Mashape</h3>
      <a href="#kong-by-marco-palladino-from-mashape">
        
      </a>
    </div>
    <p>       </p><p>The slides can be found <a href="https://openresty.org/slides/kong_openresty_slides.pdf">here</a></p>
    <div>
      <h3><i>What's new in OpenResty for 2016</i> by Yichun Zhang of CloudFlare</h3>
      <a href="#whats-new-in-openresty-for-2016-by-yichun-zhang-of-cloudflare">
        
      </a>
    </div>
    <p>       </p><p>Yichun's slides are <a href="https://openresty.org/slides/Whats-new-in-OpenResty-for-2016.pdf">here</a></p><p>If you are interested in being present at the next OpenResty Meetup by sure to follow the <a href="http://www.meetup.com/Bay-Area-OpenResty-Meetup/">meetup itself</a>.</p> ]]></content:encoded>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Events]]></category>
            <category><![CDATA[MeetUp]]></category>
            <guid isPermaLink="false">7zXxBfi7gJqgMT3MXByepn</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[Scaling out PostgreSQL for CloudFlare Analytics using CitusDB]]></title>
            <link>https://blog.cloudflare.com/scaling-out-postgresql-for-cloudflare-analytics-using-citusdb/</link>
            <pubDate>Thu, 09 Apr 2015 17:32:05 GMT</pubDate>
            <description><![CDATA[ When I joined CloudFlare about 18 months ago, we had just started to build out our new Data Platform. At that point, the log processing and analytics pipeline built in the early days of the company had reached its limits.  ]]></description>
            <content:encoded><![CDATA[ <p>When I joined CloudFlare about 18 months ago, we had just started to build out our new Data Platform. At that point, the log processing and analytics pipeline built in the early days of the company had reached its limits. This was due to the rapidly increasing log volume from our Edge Platform where we’ve had to deal with traffic growth in excess of 400% annually.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4AxkHPDBZrwj6QJQVWuQcX/fec02af530de1ab2f8a1f516ece59057/keepcalm_scaled.png" />
            
            </figure><p>Our log processing pipeline started out like most everybody else’s: compressed log files shipped to a central location for aggregation by a motley collection of Perl scripts and C++ programs with a single PostgreSQL instance to store the aggregated data. Since then, CloudFlare has grown to serve millions of requests per second for millions of sites. Apart from the hundreds of terabytes of log data that has to be aggregated every day, we also face some unique challenges in providing detailed analytics for each of the millions of sites on CloudFlare.</p><p>For the next iteration of our Customer Analytics application, we wanted to get something up and running quickly, try out Kafka, write the aggregation application in Go, and see what could be done to scale out our trusty go-to database, PostgreSQL, from a single machine to a cluster of servers without requiring us to deal with sharding in the application.</p><p>As we were analyzing our scaling requirements for PostgreSQL, we came across <a href="https://www.citusdata.com/">Citus Data</a>, one of the companies to launch out of <a href="https://www.ycombinator.com/">Y Combinator</a> in the summer of 2011. Citus Data builds a database called CitusDB that scales out PostgreSQL for real-time workloads. Because CitusDB enables both real-time data ingest and sub-second queries across billions of rows, it has become a crucial part of our analytics infrastructure.</p>
    <div>
      <h4>Log Processing Pipeline for Analytics</h4>
      <a href="#log-processing-pipeline-for-analytics">
        
      </a>
    </div>
    <p>Before jumping into the details of our database backend, let’s review the pipeline that takes a log event from CloudFlare’s Edge to our analytics database.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4I3yKJFMKyL4M3gtS2SlTy/b34a4a58d3da74e788950e6af1699582/image01.png" />
            
            </figure><p>An HTTP access log event proceeds through the CloudFlare data pipeline as follows:</p><ol><li><p>A web browser makes a request (e.g., an HTTP GET request).</p></li><li><p>An Nginx web server running <a href="/pushing-nginx-to-its-limit-with-lua/">Lua code</a> handles the request and generates a binary log event in <a href="https://capnproto.org">Cap’n Proto format</a>.</p></li><li><p>A Go program akin to <a href="https://github.com/mozilla-services/heka">Heka</a> receives the log event from Nginx over a UNIX socket, batches it with other events, compresses the batch using a fast algorithm like <a href="https://github.com/google/snappy">Snappy</a> or <a href="https://github.com/Cyan4973/lz4">LZ4</a>, and sends it to our data center over a TLS-encrypted TCP connection.</p></li><li><p>Another Go program (the Kafka shim) receives the log event stream, decrypts it, decompresses the batches, and produces the events into a Kafka topic with partitions replicated on many servers.</p></li><li><p>Go aggregators (one process per partition) consume the topic-partitions and insert aggregates (not individual events) with 1-minute granularity into the CitusDB database. Further rollups to 1-hour and 1-day granularity occur later to reduce the amount of data to be queried and to speed up queries over intervals spanning many hours or days.</p></li></ol>
    <div>
      <h4>Why Go?</h4>
      <a href="#why-go">
        
      </a>
    </div>
    <p>Previous blog <a href="/what-weve-been-doing-with-go/">posts</a> and <a href="https://www.youtube.com/watch?v=8igk2ylk_X4">talks</a> have covered <a href="/go-at-cloudflare/">various CloudFlare projects that have been built using Go</a>. We’ve found that Go is a great language for teams to use when building the kinds of distributed systems needed at CloudFlare, and this is true regardless of an engineer’s level of experience with Go. Our Customer Analytics team is made up of engineers that have been using Go since before its 1.0 release as well as complete Go newbies. Team members that were new to Go were able to spin up quickly, and the code base has remained maintainable even as we’ve continued to build many more data processing and aggregation applications such as a new version of <a href="https://www.hakkalabs.co/articles/optimizing-go-3k-requestssec-480k-requestssec">our Layer 7 DDoS attack mitigation system</a>.</p><p>Another factor that makes Go great is the ever-expanding ecosystem of third party libraries. We used <a href="https://github.com/glycerine/go-capnproto">go-capnproto</a> to generate Go code to handle binary log events in Cap’n Proto format from a common schema shared between Go, C++, and <a href="/introducing-lua-capnproto-better-serialization-in-lua/">Lua projects</a>. Go support for Kafka with <a href="https://godoc.org/github.com/Shopify/sarama">Shopify’s Sarama</a> library, support for ZooKeeper with <a href="https://github.com/samuel/go-zookeeper">go-zookeeper</a>, support for PostgreSQL/CitusDB through <a href="http://golang.org/pkg/database/sql/">database/sql</a> and the <a href="https://github.com/lib/pq">lib/pq driver</a> are all very good.</p>
    <div>
      <h4>Why Kafka?</h4>
      <a href="#why-kafka">
        
      </a>
    </div>
    <p>As we started building our new data processing applications in Go, we had some additional requirements for the pipeline:</p><ol><li><p>Use a queue with persistence to allow short periods of downtime for downstream servers and/or consumer services.</p></li><li><p>Make the data available for processing in real time by <a href="https://github.com/mumrah/kafka-python">scripts</a> written by members of our Site Reliability Engineering team.</p></li><li><p>Allow future aggregators to be built in other languages like Java, <a href="https://github.com/edenhill/librdkafka">C or C++</a>.</p></li></ol><p>After extensive testing, we selected <a href="https://kafka.apache.org/">Kafka</a> as the first stage of the log processing pipeline.</p>
    <div>
      <h4>Why Postgres?</h4>
      <a href="#why-postgres">
        
      </a>
    </div>
    <p>As we mentioned when <a href="http://www.postgresql.org/about/press/presskit93/">PostgreSQL 9.3 was released</a>, PostgreSQL has long been an important part of our stack, and for good reason.</p><p>Foreign data wrappers and other extension mechanisms make PostgreSQL an excellent platform for storing lots of data, or as a gateway to other NoSQL data stores, without having to give up the power of SQL. PostgreSQL also has great performance and documentation. Lastly, PostgreSQL has a large and active community, and we've had the privilege of meeting many of the PostgreSQL contributors at meetups held at the CloudFlare office and elsewhere, organized by the <a href="http://www.meetup.com/postgresql-1/">The San Francisco Bay Area PostgreSQL Meetup Group</a>.</p>
    <div>
      <h4>Why CitusDB?</h4>
      <a href="#why-citusdb">
        
      </a>
    </div>
    <p>CloudFlare has been using PostgreSQL since day one. We trust it, and we wanted to keep using it. However, CloudFlare's data has been growing rapidly, and we were running into the limitations of a single PostgreSQL instance. Our team was tasked with scaling out our analytics database in a short time so we started by defining the criteria that are important to us:</p><ol><li><p><b>Performance</b>: Our system powers the Customer Analytics dashboard, so typical queries need to return in less than a second even when dealing with data from many customer sites over long time periods.</p></li><li><p><b>PostgreSQL</b>: We have extensive experience running PostgreSQL in production. We also find several extensions useful, e.g., Hstore enables us to store semi-structured data and HyperLogLog (HLL) makes unique count approximation queries fast.</p></li><li><p><b>Scaling</b>: We need to dynamically scale out our cluster for performance and huge data storage. That is, if we realize that our cluster is becoming overutilized, we want to solve the problem by just adding new machines.</p></li><li><p><b>High availability</b>: This cluster needs to be highly available. As such, the cluster needs to automatically recover from failures like disks dying or servers going down.</p></li><li><p><b>Business intelligence queries</b>: in addition to sub-second responses for customer queries, we need to be able to perform business intelligence queries that may need to analyze billions of rows of analytics data.</p></li></ol><p>At first, we evaluated what it would take to build an application that deals with sharding on top of stock PostgreSQL. We investigated using the <a href="http://www.postgresql.org/docs/9.4/static/postgres-fdw.html">postgres_fdw</a> extension to provide a unified view on top of a number of independent PostgreSQL servers, but this solution did not deal well with servers going down.</p><p>Research into the major players in the PostgreSQL space indicated that CitusDB had the potential to be a great fit for us. On the performance point, they already had customers running real-time analytics with queries running in parallel across a large cluster in tens of milliseconds.</p><p>CitusDB has also maintained compatibility with PostgreSQL, not by forking the code base like other vendors, but by extending it to plan and execute distributed queries. Furthermore, CitusDB used the concept of many logical shards so that if we were to add new machines to our cluster, we could easily rebalance the shards in the cluster by calling a simple PostgreSQL user-defined function.</p><p>With CitusDB, we could replicate logical shards to independent machines in the cluster, and automatically fail over between replicas even during queries. In case of a hardware failure, we could also use the rebalance function to re-replicate shards in the cluster.</p>
    <div>
      <h4>CitusDB Architecture</h4>
      <a href="#citusdb-architecture">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/74Tl2hP3Tfk1HNzpF1MV4i/121b31b62700289180653b647a653edb/image00.png" />
            
            </figure><p>CitusDB follows an architecture similar to Hadoop to scale out Postgres: one primary node holds authoritative metadata about shards in the cluster and parallelizes incoming queries. The worker nodes then do all the actual work of running the queries.</p><p>In CloudFlare's case, the cluster holds about 1 million shards and each shard is replicated to multiple machines. When the application sends a query to the cluster, the primary node first prunes away unrelated shards and finds the specific shards relevant to the query. The primary node then transforms the query into many smaller queries for <a href="http://www.citusdata.com/blog/19-ozgun/114-how-to-build-your-distributed-database">parallel execution</a> and ships those smaller queries to the worker nodes.</p><p>Finally, the primary node receives intermediate results from the workers, merges them, and returns the final results to the application. This takes anywhere between 25 milliseconds to 2 seconds for queries in the CloudFlare analytics cluster, depending on whether some or all of the data is available in page cache.</p><p>From a high availability standpoint, when a worker node fails, the primary node automatically fails over to the replicas, even during a query. The primary node holds slowly changing metadata, making it a good fit for continuous backups or PostgreSQL's streaming replication feature. Citus Data is currently working on further improvements to make it easy to replicate the primary metadata to all the other nodes.</p><p>At CloudFlare, we love the CitusDB architecture because it enabled us to continue using PostgreSQL. Our analytics dashboard and BI tools connect to Citus using standard PostgreSQL connectors, and tools like <code>pg_dump</code> and <code>pg_upgrade</code> just work. Two features that stand out for us are CitusDB’s PostgreSQL extensions that power our analytics dashboards, and CitusDB’s ability to parallelize the logic in those extensions out of the box.</p>
    <div>
      <h4>Postgres Extensions on CitusDB</h4>
      <a href="#postgres-extensions-on-citusdb">
        
      </a>
    </div>
    <p>PostgreSQL extensions are pieces of software that add functionality to the core database itself. Some examples are data types, user-defined functions, operators, aggregates, and custom index types. PostgreSQL has more than 150 publicly available official extensions. We’d like to highlight two of these extensions that might be of general interest. It’s worth noting that with CitusDB all of these extensions automatically scale to many servers without any changes.</p>
    <div>
      <h4>HyperLogLog</h4>
      <a href="#hyperloglog">
        
      </a>
    </div>
    <p><a href="https://en.wikipedia.org/wiki/HyperLogLog">HyperLogLog</a> is a sophisticated algorithm developed for doing unique count approximations quickly. And since a <a href="https://github.com/aggregateknowledge/postgresql-hll">HLL implementation for PostgreSQL</a> was open sourced by the good folks at Aggregate Knowledge, we could use it with CitusDB unchanged because it’s compatible with most (if not all) Postgres extensions.</p><p>HLL was important for our application because we needed to compute unique IP counts across various time intervals in real time and we didn’t want to store the unique IPs themselves. With this extension, we could, for example, count the number of unique IP addresses accessing a customer site in a minute, but still have an accurate count when further rolling up the aggregated data into a 1-hour aggregate.</p>
    <div>
      <h4>Hstore</h4>
      <a href="#hstore">
        
      </a>
    </div>
    <p>The <a href="http://www.postgresql.org/docs/9.4/static/hstore.html">hstore data type</a> stores sets of key/value pairs within a single PostgreSQL value. This can be helpful in various scenarios such as with rows with many attributes that are rarely examined, or to represent semi-structured data. We use the hstore data type to hold counters for sparse categories (e.g. country, HTTP status, data center).</p><p>With the hstore data type, we save ourselves from the burden of denormalizing our table schema into hundreds or thousands of columns. For example, we have one hstore data type that holds the number of requests coming in from different data centers per minute per CloudFlare customer. With millions of customers and hundreds of data centers, this counter data ends up being very sparse. Thanks to hstore, we can efficiently store that data, and thanks to CitusDB, we can efficiently parallelize queries of that data.</p><p>For future applications, we are also investigating other extensions such as the Postgres columnar store extension <a href="https://github.com/citusdata/cstore_fdw">cstore_fdw</a> that Citus Data has open sourced. This will allow us to compress and store even more historical analytics data in a smaller footprint.</p>
    <div>
      <h4>Conclusion</h4>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>CitusDB has been working very well for us as the new backend for our Customer Analytics system. We have also found many uses for the analytics data in a business intelligence context. The ease with which we can run distributed queries on the data allows us to quickly answer new questions about the CloudFlare network that arise from anyone in the company, from the SRE team through to Sales.</p><p>We are looking forward to features available in the recently released <a href="https://www.citusdata.com/citus-products/citusdb-software">CitusDB 4.0</a>, especially the performance improvements and the new shard rebalancer. We’re also excited about using the JSONB data type with CitusDB 4.0, along with all the other improvements that come standard as part of <a href="http://www.postgresql.org/docs/9.4/static/release-9-4.html">PostgreSQL 9.4</a>.</p><p>Finally, if you’re interested in building and operating distributed services like Kafka or CitusDB and writing Go as part of a dynamic team dealing with big (nay, gargantuan) amounts of data, <a href="https://www.cloudflare.com/join-our-team">CloudFlare is hiring</a>.</p> ]]></content:encoded>
            <category><![CDATA[Analytics]]></category>
            <category><![CDATA[SQL]]></category>
            <category><![CDATA[Postgres]]></category>
            <category><![CDATA[Kafka]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[DDoS]]></category>
            <guid isPermaLink="false">4WkjJAXrP1iZH5uthDDnAh</guid>
            <dc:creator>Albert Strasheim</dc:creator>
        </item>
        <item>
            <title><![CDATA[Introducing lua-capnproto: better serialization in Lua]]></title>
            <link>https://blog.cloudflare.com/introducing-lua-capnproto-better-serialization-in-lua/</link>
            <pubDate>Fri, 28 Feb 2014 09:00:00 GMT</pubDate>
            <description><![CDATA[ When we need to transfer data from one program to another program, either within a machine or from one data center to another some form of serialization is needed. ]]></description>
            <content:encoded><![CDATA[ <p>When we need to transfer data from one program to another program, either within a machine or from one data center to another some form of serialization is needed. Serialization converts data stored in memory into a form that can be sent across a network or between processes and then converted back into data a program can use directly.</p><p>At CloudFlare, we have data centers all over the world. When transferring data from one data center to another, we need a very efficient way of serializing data, saving us both time and network bandwidth.</p><p>We've looked at a few serialization projects. For example, one popular serialization format is JSON, for some of our Go programs we use gob, and we've made use of Protocol Buffers in the past. But lately we've been using a new serialization protocol called Cap'n Proto.</p><p><a href="http://kentonv.github.io/capnproto/">Cap'n Proto</a> attracted us because of its very high performance compared to other serialization projects. It looks a little like a better version of Protocol Buffers, and the author of Cap'n Proto, Kenton, was the primary author of Protocol Buffers version 2.</p><p>At CloudFlare, we use NGINX in conjunction with Lua for front-line web serving, proxying and traffic filtering. We need to serialize our data in Lua and transport it across the Internet. But unfortunately, there was no Lua module for <a href="http://kentonv.github.io/capnproto/index.html">Cap'n Proto</a>. So, we decided to write <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> and release it as yet another <a href="http://cloudflare.github.io/">CloudFlare open source</a> contribution.</p><p><a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> provides very fast data serialization and a really easy to use API. Here I'll show you how to use <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> to do serialization and deserialization.</p>
    <div>
      <h3>Install lua-capnproto</h3>
      <a href="#install-lua-capnproto">
        
      </a>
    </div>
    <p>To install lua-capnproto, you need to install <a href="http://kentonv.github.io/capnproto/install.html">Cap'n Proto</a>, <a href="http://luajit.org/install.html">LuaJIT 2.1</a> and <a href="http://luarocks.org/en/Download">luarocks</a> first.</p><p>Then you can install lua-capnproto using the following commands:</p><p>git clone <a href="https://github.com/cloudflare/lua-capnproto.git">https://github.com/cloudflare/lua-capnproto.git</a>cd lua-capnprotosudo luarocks make</p><p>To test whether lua-capnproto was installed successfully, you can use the <code>capnp</code> compiler to generate a Lua version of one of the Cap'n Proto examples as follows:</p><p>capnp compile -olua proto/example.capnp</p><p>If everything goes well, you should see no errors and a file named <code>example_capnp.lua</code> generated under the <code>proto</code> directory.</p>
    <div>
      <h3>Write a Cap’n Proto definition</h3>
      <a href="#write-a-capn-proto-definition">
        
      </a>
    </div>
    <p>Here's a sample Cap’n Proto definition that would be stored in a file called <code>AddressBook.capnp</code>:</p>
            <pre><code>    @0xdbb9ad1f14bf0b36;  # unique file ID, generated by capnp id

    struct Person {
      id @0 :UInt32;
      name @1 :Text;
      email @2 :Text;
      phones @3 :List(PhoneNumber);

      struct PhoneNumber {
        number @0 :Text;
        type @1 :Type;

        enum Type {
          mobile @0;
          home @1;
          work @2;
        }
      }

      employment :union {
        unemployed @4 :Void;
        employer @5 :Text;
        school @6 :Text;
        selfEmployed @7 :Void;
        # We assume that a person is only one of these.
      }
    }

    struct AddressBook {
      people @0 :List(Person);
    }</code></pre>
            <p>We have a root structure named <code>AddressBook</code> containing a list named <code>people</code> whose members are also structures. What we are going to do is to serialize an <code>AddressBook</code> structure and then read the structure from serialized data. For more details about the <a href="http://kentonv.github.io/capnproto/index.html">Cap'n Proto</a> definition, you can checkout its documentation at <a href="http://kentonv.github.io/capnproto/index.html">here</a>.</p>
    <div>
      <h3>Prepare your data</h3>
      <a href="#prepare-your-data">
        
      </a>
    </div>
    <p>Preparing data is pretty simple. All you need to do is to generate a Lua table corresponding to the root structure. The following list gives rules to help you write this table. On the left is a <a href="http://kentonv.github.io/capnproto/index.html">Cap'n Proto</a> data type, on the right is its corresponding Lua data type.</p><ul><li><p>struct -&gt; Lua hash table</p></li><li><p>list -&gt; Lua array table</p></li><li><p>bool -&gt; Lua boolean</p></li><li><p>int8/16/32 or uint8/16/32 or float32/64 -&gt; Lua number</p></li><li><p>int64/uint64 -&gt; LuaJIT 64bit number</p></li><li><p>enum -&gt; Lua string</p></li><li><p>void -&gt; Lua string <code>“Void”</code></p></li><li><p>group -&gt; Lua hash table (the same as struct)</p></li><li><p>union -&gt; Lua hash table which has only one value set</p></li></ul>
    <div>
      <h3>A few notices:</h3>
      <a href="#a-few-notices">
        
      </a>
    </div>
    <p>Because Lua number type represents real (double-precision floating-point) numbers and Lua has no integer type, so by default you can't store a 64 bit integer using number type without losing precision. LuaJIT has an <a href="http://luajit.org/ext_ffi_api.html#literals">extension</a> which supports 64-bit integers. You need to add <code>ULL</code> or <code>LL</code> to the end of the number (<code>ULL</code> is for unsigned integers, <code>LL</code> for signed). So, if you need to serialize a 64-bit integer, remember to append <code>ULL</code> or <code>LL</code> to your number.</p><p>For example:</p><p>id @0 :Int64;                   -&gt;   id = 12345678901234LL</p><p>Enum values are automatically converted from strings to their values, you don’t need to do it yourself. By default, enums will be converted to the uppercase with underscores form. You can change this behavior using annotations. The <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> <a href="https://github.com/cloudflare/lua-capnproto/blob/master/README.md">document</a> has more details.</p><p>Here is an example:</p><p>type @0 :Type;
enum Type {
binaryAddr @0;
textAddr @1;
}                               -&gt;    type = “TEXT_ADDR”</p><p><code>void</code> is a special type in Cap’n Proto. For simplicity, we just use a string <code>"Void"</code> to represent <code>void</code> (actually, when serializing, any value other than <code>nil</code> will work, but we use <code>"Void"</code> for consistency).</p><p>A sample data table looks like this:</p>
            <pre><code>    local data = {
        people = {
            {
                id = "123",
                name = "Alice",
                email = "alice@example.com",
                phones = {
                    {
                        number = "555-1212",
                        ["type"] = "MOBILE",
                    },
                },
                employment = {
                    school = "MIT",
                },
            },
            {
                id = "456",
                name = "Bob",
                email = "bob@example.com",
                phones = {
                    {
                        number = "555-4567",
                        ["type"] = "HOME",
                    },
                    {
                        number = "555-7654",
                        ["type"] = "WORK",
                    },
                },
                employment = {
                    unemployed = "Void",
                },
            },
        }
    }</code></pre>
            
    <div>
      <h3>Compile and run</h3>
      <a href="#compile-and-run">
        
      </a>
    </div>
    <p>Now let's compile the Cap'n Proto file:</p><p>capnp compile -olua AddressBook.capnp</p><p>You shouldn't see any errors and a file named <code>AddressBook_capnp.lua</code> is generated under the current directory.</p><p>To use this file, we only need to write a file named <code>main.lua</code> (or whatever name you desire), and get all the required modules ready.</p>
            <pre><code>    local addressBook = require "AddressBook_capnp"                                                                       
    local capnp = require "capnp"</code></pre>
            <p>Now we can start to serialize using our already prepared data.</p>
            <pre><code>    local bin = addressBook.AddressBook.serialize(data)</code></pre>
            <p>That’s it. Just one line of code. All the serialization work is done. Now variable <code>bin</code> (a Lua string) holds the serialized binary data. You can write this string to a file or send it through network.</p><p>Want about deserialization? It's as easy as serialization.</p>
            <pre><code>    local decoded = addressBook.AddressBook.parse(bin)</code></pre>
            <p>Now variable <code>decoded</code> holds a table which is identical to <code>data</code>. You can find the complete code <a href="https://github.com/cloudflare/lua-capnproto/tree/master/example">here</a>. Note that you need LuaJIT to run the code.</p>
    <div>
      <h3>Performance</h3>
      <a href="#performance">
        
      </a>
    </div>
    <p>If you are happy with the API, here is even better news. We chose Cap'n Proto because of its impressively high performance. So when writing lua-capnproto, I also made every effort to make it fast.</p><p>In one project we switched to lua-capnproto from <a href="http://www.kyne.com.au/~mark/software/lua-cjson.php">lua-cjson</a> (a quite fast JSON library for Lua) for serialization. So let's see how fast lua-capnproto is compared to lua-cjson.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/59GtNOY9Ix3jO9tFNn53ms/8b88605c6a817d02dd525926adebee8b/lua-capnproto.png" />
            
            </figure><p>You can also run <a href="https://github.com/cloudflare/lua-capnproto/blob/master/benchmark.lua">benchmark.lua</a> yourself (included in the source code) to find out how fast lua-capnproto is compared to <a href="http://www.kyne.com.au/~mark/software/lua-cjson.php">lua-cjson</a> on your machine.</p>
    <div>
      <h3>The future</h3>
      <a href="#the-future">
        
      </a>
    </div>
    <p>We are already using <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> in production at CloudFlare and it has been running very well for the past month. But <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> is still a very young project. Some features are missing and there's a lot of work to do in the future. We will continue to make <a href="https://github.com/cloudflare/lua-capnproto">lua-capnproto</a> more stable and more reliable, and would be happy to receive contributions from the open source community.</p> ]]></content:encoded>
            <category><![CDATA[Data]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Cap'n Proto]]></category>
            <category><![CDATA[LUA]]></category>
            <guid isPermaLink="false">5n9qvrLgdQCTRLUe0NlTiB</guid>
            <dc:creator>Jiale Zhi</dc:creator>
        </item>
        <item>
            <title><![CDATA[Keeping our open source promise]]></title>
            <link>https://blog.cloudflare.com/keeping-our-open-source-promise/</link>
            <pubDate>Sun, 22 Dec 2013 17:00:00 GMT</pubDate>
            <description><![CDATA[ Back in October I wrote a blog post about CloudFlare and open source software titled CloudFlare And Open Source Software: A Two-Way Street which detailed the many ways in which we use and support open source software. ]]></description>
            <content:encoded><![CDATA[ <p>Back in October I wrote a blog post about CloudFlare and open source software titled <a href="/open-source-two-way-street">CloudFlare And Open Source Software: A Two-Way Street</a> which detailed the many ways in which we use and support open source software.</p><p>Since then we've pushed out quite a lot of new open source projects, as well as continuing to support the likes of <a href="http://luajit.org/sponsors.html#sponsorship_perf">LuaJIT</a> and <a href="http://openresty.org/">OpenResty</a>. All our open source projects are available via our dedicated GitHub page <a href="http://cloudflare.github.io/">cloudflare.github.io</a>. Here are a few that have been recently updated or released:</p><ul><li><p><a href="https://github.com/cloudflare/redoctober">Red October</a>: our implementation of the 'two man rule' for control of secrets (and nuclear weapons :-). It was large enough to warrant its own <a href="/red-october-cloudflares-open-source-implementation-of-the-two-man-rule">blog post</a>.</p></li><li><p><a href="https://github.com/cloudflare/lua-resty-shcache">Lua Resty Shcache</a>: a shared cache implementation for OpenResty and Nginx Lua.</p></li><li><p><a href="https://github.com/agentzh/lua-resty-core">Lua Resty Core</a>: a new FFI-based Lua API for the ngx_lua module (part of work CloudFlare is doing on optimization).</p></li><li><p><a href="https://github.com/cloudflare/golibs">Go Libs</a>: at the other end of the size spectrum: golibs is where we'll be dumping small Go libraries that might be useful to others.</p></li><li><p><a href="https://github.com/cloudflare/bm">BM</a>: a Go implementation of Bentley-McIlroy long string compression (which is close to part of the compression performance by <a href="https://www.cloudflare.com/railgun">Railgun</a>).</p></li><li><p><a href="https://github.com/cloudflare/lua-raven">Lua Raven</a>: a Lua interface for sending error reports to <a href="https://getsentry.com/">Sentry</a>.</p></li><li><p><a href="https://github.com/cloudflare/lua-resty-logger-socket">Lua Resty Logger Socket</a>: a non-blocking logger for Nginx Lua that supports remote loggers.</p></li><li><p><a href="https://github.com/cloudflare/conf">conf</a>: a very simple key=value configuration file parser written in Go.</p></li><li><p><a href="https://github.com/cloudflare/lua-resty-kyototycoon">Lua Resty Kyoto Tycoon</a>: a non-blocking Lua interface for <a href="http://fallabs.com/kyototycoon/">Kyoto Tycoon</a>.</p></li><li><p><a href="https://github.com/cloudflare/golz4">Go LZ4</a>: a Go package for LZ4 compression.</p></li><li><p><a href="https://github.com/cloudflare/ahocorasick">Aho Corasick</a>: a Go package that does Aho-Corasick string matching.</p></li><li><p><a href="https://github.com/cloudflare/kt_fdw">kt-fdw</a>: a foreign data wrapper for Postegres that interfaces to Kyoto Tycoon. More details in its <a href="/kyoto_tycoon_with_postgresql">blog post</a>.</p></li><li><p><a href="https://github.com/cloudflare/lua-resty-cookie">Lua Resty Cookie</a>: a Lua Resty package that improves Cookie handling in OpenResty and Nginx Lua.</p></li><li><p><a href="https://github.com/terinjokes/docker-npmjs">Docker NPMJS</a>: a Docker image for a private npmjs repository.</p></li></ul><p>We've also been contributing to projects like <a href="http://git.openssl.org/gitweb/?p=openssl.git;a=search;s=Piotr+Sikora;st=author">OpenSSL</a>, <a href="https://sourceware.org/git/gitweb.cgi?p=systemtap.git;a=search;s=Yichun+Zhang+(agentzh);st=author">SystemTap</a> and <a href="https://code.google.com/p/phantomjs/source/detail?r=3ae632e70441125e6830ddb8e6535a3627f9444a&amp;path=/test/webpage-spec.js">PhantomJS</a>, and the names of CloudFlare employees Yichun and Piotr appear regularly in the Nginx <a href="http://nginx.org/en/CHANGES">changelog</a>.</p><p>And, on a personal level, I've been keeping a repository of all the talks I've given (including any associated code or data) in <a href="https://github.com/cloudflare/jgc-talks">jgc-talks</a>. The most recent of which was a talk in London about <a href="https://github.com/cloudflare/jgc-talks/tree/master/Other/BigO_London">rolling hashes</a>.</p><p>We'll keep pushing projects, large and small, to Github as we're ready to share them. We've pushed out so much open source code that we've recently reorganized our Github page by language/software. There are now sections for <a href="http://cloudflare.github.io/#cat-JavaScript">JavaScript</a>, <a href="http://cloudflare.github.io/#cat-Go">Go</a>, <a href="http://cloudflare.github.io/#cat-Nginx%20and%20Lua">Nginx and Lua</a>, and <a href="http://cloudflare.github.io/#cat-Postgres">Postgres</a>.</p><p>Right now there's a large and innovative security project getting ready for release. Expect to hear about it (and see its source code) in the New Year.</p> ]]></content:encoded>
            <category><![CDATA[OpenSSL]]></category>
            <category><![CDATA[Open Source]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <guid isPermaLink="false">35Aa0QeOHEMoZlmyo9HO8i</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[CloudFlare And Open Source Software: A Two-Way Street]]></title>
            <link>https://blog.cloudflare.com/open-source-two-way-street/</link>
            <pubDate>Mon, 07 Oct 2013 18:00:00 GMT</pubDate>
            <description><![CDATA[ CloudFlare uses a great deal of open source and free software. Our core server platform is nginx (which is released using a two-clause BSD license) and our primary database of choice is postgresql (which is released using their own BSD-like license).  ]]></description>
            <content:encoded><![CDATA[ <p>CloudFlare uses a great deal of open source and free software. Our core server platform is <a href="http://nginx.org/">nginx</a> (which is released using a <a href="http://nginx.org/LICENSE">two-clause BSD license</a>) and our primary database of choice is <a href="http://www.postgresql.org/">postgresql</a> (which is released using their own <a href="http://www.postgresql.org/about/licence/">BSD-like license</a>). We've <a href="/kyoto_tycoon_with_postgresql">talked in the past</a> about our use of <a href="http://fallabs.com/kyototycoon/">Kyoto Tycoon</a> (which is released under the GNU General Public License) and we've built many things on top of <a href="/pushing-nginx-to-its-limit-with-lua">OpenResty</a>.</p><p>And, of course, we make use of open source tools such as gcc, make, the Go programming language, Lua, python, Perl, and PHP, and projects like <a href="https://www.getsentry.com/welcome/">Sentry</a>, <a href="http://www.elasticsearch.org/">Kibana</a>, and <a href="http://www.nagios.org/">nagios</a>. And, naturally, we use Linux.</p><p>It would take a while to write down all the software that we use to build CloudFlare, but all that software has one thing in common: it's open source or free software. Our stack consists of either software we've built ourselves or an open source project (which we've sometimes forked).</p>
    <div>
      <h3>Why Build On Open Source</h3>
      <a href="#why-build-on-open-source">
        
      </a>
    </div>
    <p>It's probably obvious to most readers why we use open source software: it's reliable, it's easy to modify and it's easy to maintain. But there's another benefit that should not be overlooked: using and working on open source software brings a great deal of job satisfaction for programmers and it helps us hire the best.</p><p>We encourage our programmers to release changes they've made to open source software and to release projects through the <a href="http://cloudflare.github.io/">CloudFlare GitHub</a> page.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3TMjRYWUEXyn3g7aJadzx1/0836a32a7ce3cd21e3057ddb2905ada5/cloudflare-github.png" />
            
            </figure><p>At GitHub you'll find projects such as <a href="https://github.com/cloudflare/golog">golog</a> (a high-performance Go logger), <a href="https://github.com/cloudflare/lua-cmsgpack">lua-cmsgpack</a> (an implementation of MessagePack for Lua), a Python-based <a href="https://github.com/cloudflare/CloudFlare-CNAME-Flattener">CNAME flattener</a>, and a <a href="https://github.com/agentzh/stapxx">macro language</a> for systemtap, amongst others.</p><p>You'll also find the <a href="https://github.com/chaoslawful/lua-nginx-module">ngx_lua module</a> which embeds Lua in nginx. That's not something CloudFlare initially wrote, but we make such extensive use of it that we hired <a href="https://github.com/agentzh">Yichun Zhang</a>. He continues to work full-time on it while at CloudFlare.</p><p>And, if you've ever delved into the internals of nginx, you'll know another CloudFlare employee, Piotr Sikora, who recently added <a href="http://www.mail-archive.com/nginx-devel@nginx.org/msg01061.html">the ability to set keys for TLS Session Tickets</a> to nginx.</p><p>So, at CloudFlare, open source can get you a job, be your job or, at least, be a significant part of your job.</p>
    <div>
      <h3>Sponsoring</h3>
      <a href="#sponsoring">
        
      </a>
    </div>
    <p>Where appropriate (i.e. where we think we make the biggest impact and get something we need) we've sponsored external open source projects and paid for improvements that all can use.</p><p>We make wide use of the excellent <a href="http://luajit.org/">LuaJIT</a> project and after much profiling by engineers we discovered areas where more JITing would improve our performance. Rather than do the work ourselves we <a href="http://luajit.org/sponsors.html#sponsorship_perf">sponsored</a> the LuaJIT project. These speedups will be appearing in LuaJIT 2.1 when it is released.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/HzOPkOxjv7EyhnI9yyUBU/ff6bc6f6b09c39070d9202287fe7c10c/two-way-street.png" />
            
            </figure>
    <div>
      <h3>Two Way Street</h3>
      <a href="#two-way-street">
        
      </a>
    </div>
    <p>Of course, it would be easy for us to use open source software, make modifications and not release them. None of the licenses for the software we use force us to release our modifications. But we prefer to give back and not just because of karma.</p><p>There are two big advantages to releasing modifications we've made to existing projects: the many eyeballs effect and reducing fork cost.</p><p>The first, many eyeballs, is common to any open source project: the more people look at code, the better it gets. And that applies equally to code written by a core team of developers and code written by outsiders. When we contribute changes we've made, others look at the changes and improve them.</p><p>For example, back in 2012 we contributed an improvement to Go's <a href="https://code.google.com/p/go/source/detail?r=a041b45cc418">log/syslog</a> module. This year that work was <a href="https://code.google.com/p/go/source/detail?r=51407182d459">improved</a>.</p><p>And the cost of maintaining a fork provides useful economic pressure making releasing our modifications make sense. It's cheaper for us to release than to maintain a fork and merge as the core of a project changes.</p><p>But, what about CloudFlare's secret sauce?</p>
    <div>
      <h3>Open Sourcing CloudFlare Core</h3>
      <a href="#open-sourcing-cloudflare-core">
        
      </a>
    </div>
    <p>Our strong bias is to open source everything we've built. When we don't, it's usually because it's highly specific to us and/or because the support cost is high. Ultimately, we'd like to open source all our major components so that they can be used to build a faster, safer, smarter web.</p><p>Many of our smaller components are really glue code that don't make any sense to open source as they are so specific to our implementation of the overall system.</p><p>We don't believe that there is any chunk of code so clever that it gives us a long term competitive advantage. Instead, our advantage comes from the network we've built, the data we collect on making the web faster and safer, and, most importantly, the people we're able to attract.</p><p>A commitment to open source builds trust in the community which helps us continue to build our service and attract the best people.</p><p>In fact, the best way to get hired at CloudFlare is to make good contributions to open source projects we find interesting and useful. Contributions like that often speak more loudly than a resume.</p> ]]></content:encoded>
            <category><![CDATA[Open Source]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[GitHub]]></category>
            <category><![CDATA[LUA]]></category>
            <guid isPermaLink="false">5k8obbKvvWiWBkX0BNi8Xl</guid>
            <dc:creator>John Graham-Cumming</dc:creator>
        </item>
        <item>
            <title><![CDATA[Pushing Nginx to its limit with Lua]]></title>
            <link>https://blog.cloudflare.com/pushing-nginx-to-its-limit-with-lua/</link>
            <pubDate>Sat, 08 Dec 2012 20:46:00 GMT</pubDate>
            <description><![CDATA[ At CloudFlare, Nginx is at the core of what we do. It is part of the underlying foundation of our reverse proxy service. In addition to the built-in Nginx functionalities, we use an array of custom C modules... ]]></description>
            <content:encoded><![CDATA[ <p></p><p>At CloudFlare, Nginx is at the core of what we do. It is part of the underlying foundation of our reverse proxy service. In addition to the built-in Nginx functionalities, we use an array of custom C modules that are specific to our infrastructure including load balancing, monitoring, and caching. Recently, we've been adding more simple services. And they are almost exclusively written in Lua.</p><p>I wanted to share more about how we are augmenting Nginx with new capabilities using Lua and provide some examples so you can do the same.</p>
    <div>
      <h3>What is Lua?</h3>
      <a href="#what-is-lua">
        
      </a>
    </div>
    <p>Lua is a scripting language. Specifically, it is a full-featured multi-paradigm language with a simple syntax and semantics that resemble JavaScript or Scheme. Lua also has an interesting story to it, as it is one of the only languages from an emerging country that has had worldwide impact.</p><p>Lua has always meant to be embedded with larger systems written in other languages (like C and C++), and has thrived at staying very minimal and easy to integrate. As a result, Lua is popular within videogames, <a href="http://wiki.wireshark.org/Lua">security oriented software</a>, and, morerecently, <a href="http://en.wikipedia.org/wiki/Wikipedia:Wikipedia_Signpost/2012-01-30/Technology_report">Wikipedia</a>.</p>
    <div>
      <h3>Benefits of Nginx+Lua</h3>
      <a href="#benefits-of-nginx-lua">
        
      </a>
    </div>
    <p>Nginx+Lua is a self-contained web server embedding the scripting language Lua. Powerful applications can be written directly inside Nginx without using cgi, fastcgi, or uwsgi. By adding a little Lua code to an existing Nginx configuration file, it is easy to add small features. To see it yourself, at the end of this post I've included some logging code that can be added to any existing configuration.</p><p>One of the core benefits of Nginx+Lua is that it is fully asynchronous. Nginx+Lua inherits the same event loop model that has made Nginx a popular choice of webserver. "Asynchronous" simply means that Nginx can interrupt your code when it is waiting on a blocking operation, such as an outgoing connection or reading a file, and run the code of another incoming HTTP Request.</p><p>All the Lua code is written in a <i>sequential</i> fashion. The asynchronous logic is hidden to the Nginx+Lua programmer. If you are familiar with other event-driven webservers, that means <i>no callbacks</i>. In addition, Nginx+Lua is <a href="http://google-opensource.blogspot.com/2010/01/love-for-luajit.html">blazingly fast</a>, leveraging the LuaJIT interpreter.</p>
    <div>
      <h3>Getting Nginx+Lua installed</h3>
      <a href="#getting-nginx-lua-installed">
        
      </a>
    </div>
    <p>You can install it from source by compiling the lua nginx-module with your existing Nginx. If you chose that path you will also need a Lua interpreter. <a href="http://luajit.org/download.html">LuaJIT-2.0.0</a> is recommended.</p><p>Or, you can use the tested <a href="http://openresty.org/#Download">ngx_openresty</a> bundle. ngx_openresty comes loaded with Nginx, <a href="http://openresty.org/#Components">3rd party modules, Lua libraries and other goodies</a>. If youalready use Nginx without 3rd party modules, from your Linux distribution for instance, you can safely swap it out with ngx_openresty. (Quick shout-out to my CloudFlare colleague Yichun Zhang who wrote ngx_openresty. Thanks, Yichun!)</p>
    <div>
      <h3>Limitations</h3>
      <a href="#limitations">
        
      </a>
    </div>
    <p>What makes Nginx, and therefore Nginx+Lua, really fast is the asychronous model and the event loop that Nginx relies on. To stay within that model, outgoing communication that is outside of Nginx has to be treated carefully. It is not recommended that you use classic LuaSocket, and instead it is recommended that you rely on the built-in <a href="https://github.com/chaoslawful/lua-nginx-module/blob/master/README.markdown#ngxsockettcp">ngx_luasockets</a>.</p><p>However, with a multitude of openresty libraries to "speak" <a href="https://github.com/agentzh/lua-resty-mysql">SQL</a>, <a href="https://github.com/agentzh/lua-resty-memcached">memcached</a>, and <a href="https://github.com/agentzh/lua-resty-redis">Redis</a>, as well as the <a href="https://github.com/agentzh/lua-resty-dns">DNS</a> built on top of ngx_lua sockets, this isn't really a problem in practice.</p>
    <div>
      <h3>An example to try: Nginx Log Aggregation</h3>
      <a href="#an-example-to-try-nginx-log-aggregation">
        
      </a>
    </div>
    <p><a href="https://github.com/mtourne/nginx_log_by_lua">Here is an example</a> of how to build and run a simple log aggregator for Nginx. You can add it to any of your own existing configuration. This is the output once the aggregated logs are funneled to a <a href="http://opentsdb.net/">time series system</a>:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/42JwZlb8wDGCmz9bHrfVuP/59c96fcf6a1c24c25c8007b10e8e4c35/Production_Graph.png.scaled500.png" />
            
            </figure><p>This particular example graph shows the average number of requests per second on certain nodes of the CloudFlare infrastructure.</p>
    <div>
      <h3>Show me the code already!</h3>
      <a href="#show-me-the-code-already">
        
      </a>
    </div>
    <p>Let's assume you already have a working webapp in Nginx, or that you use the proxy_pass directives to upstream to an Apache server.</p><p>First, add some lines in the Nginx conf to look at .lua files, and use a 1MB space of shared memory between your Nginx workers. ($prefix is relative to your Nginx install).</p><p>Next, add a little Lua snippet to calculate request_time for each request, and aggregate it into shared memory using a logging library available. Here is a simple <a href="https://github.com/mtourne/nginx_log_by_lua/blob/master/logging.lua">logging library that I built</a>.</p><p>This snippet can be used directly inline in your Nginx conf, using the <a href="https://github.com/chaoslawful/lua-nginx-module/blob/master/README.markdown#log_by_lua">log_by_lua</a> directive.</p><p><a href="https://github.com/mtourne/nginx_log_by_lua"></a></p>
    <div>
      <h3>Displaying/collecting aggregated logs</h3>
      <a href="#displaying-collecting-aggregated-logs">
        
      </a>
    </div>
    <p>The last step to complete the example is a system to collect and/or display logs. In the <a href="https://github.com/mtourne/nginx_log_by_lua/blob/master/conf/nginx.conf#L42">full example</a>, we set the aggregation as a separate server listening on a different port.</p><p>You should now have a functioning Nginx+Lua modification running in your environment.</p>
    <div>
      <h3>Using Lua instead of custom C modules</h3>
      <a href="#using-lua-instead-of-custom-c-modules">
        
      </a>
    </div>
    <p>This example showed how Lua found its way into our system at CloudFlare, but we soon realized that it wasn't limited to aggregating and printing logs. Using the same <a href="http://www.nginxguts.com/2011/01/phases/">phases that Nginx has laid out</a> for processing HTTP requests, it is becoming possible to add interesting new capabilities to Nginx, with almost as much control as a custom C module, while being pleasant and easy to write.</p><p>For instance, the <a href="https://github.com/chaoslawful/lua-nginx-module/blob/master/README.markdown#rewrite_by_lua">access</a> phase can be seen as a programmatic .htaccess, and even <a href="http://seatgeek.com/blog/dev/oauth-support-for-nginx-with-lua">more</a>. Whereas the <a href="https://github.com/chaoslawful/lua-nginx-module/blob/master/README.markdown#content_by_lua">content</a> phase is where your web application would go.</p><p>Nginx+Lua has become a foundation for the work that I do at CloudFlare. As a long-time C developer, I am constantly struck by how powerful and extremely expressive Lua can be, while being simple and approachable as well.</p><p>Sometimes, simple is beautiful.</p><hr /><p><i>PS - We're hiring Lua programmers who are interested in working at extreme scale. Check out the Systems Engineer listing on our </i><a href="https://www.cloudflare.com/join-our-team"><i>careers page</i></a><i> if you're interested.</i></p> ]]></content:encoded>
            <category><![CDATA[NGINX]]></category>
            <category><![CDATA[LUA]]></category>
            <guid isPermaLink="false">4asxlfurkVRlt22KttoRYy</guid>
            <dc:creator>Matthieu Tourne</dc:creator>
        </item>
    </channel>
</rss>