<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ruby ror optimization performance on random thoughts</title><link>https://awesomeprogrammer.com/categories/ruby-ror-optimization-performance/</link><description>Recent content in ruby ror optimization performance on random thoughts</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Sun, 06 Jul 2014 00:00:00 +0000</lastBuildDate><atom:link href="https://awesomeprogrammer.com/categories/ruby-ror-optimization-performance/index.xml" rel="self" type="application/rss+xml"/><item><title>Why my code is so darn slow?!</title><link>https://awesomeprogrammer.com/blog/2014/07/06/why-my-code-is-so-darn-slow/</link><pubDate>Sun, 06 Jul 2014 00:00:00 +0000</pubDate><guid>https://awesomeprogrammer.com/blog/2014/07/06/why-my-code-is-so-darn-slow/</guid><description><![CDATA[<p>-&gt; <img src="/images/slow_code.jpg" alt="Slow code?" title="Fry is confused about all this"> &lt;-</p>
<p>Ruby is very pretty, and unfortunattely it can be very slow. Beautiful syntax and flexebility of this language has its price (well, it&rsquo;s not so bad compared to other interpreted languages anyway).</p>
<p>Let&rsquo;s go over few (totally random) things that might cause performance issues.</p>
<h3 id="abusing-rails-view-helpers">Abusing rails view helpers</h3>
<p>Rails helpers are very useful, but if you&rsquo;re calling various helpers hundreds of times on a single page you might be surprised how much overhead it might produce. Do you really need that <code>number_with_delimiter</code> everywhere? Maybe you can use something simpler than <code>number_with_precision</code>?</p>
<p>Take a look at those two benchmarks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;action_view&#34;</span> <span style="color:#75715e">#rails 4.1.4</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Helper</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">extend</span> <span style="color:#66d9ef">ActionView</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Helpers</span><span style="color:#f92672">::</span><span style="color:#66d9ef">NumberHelper</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;number_with_delimiter&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Helper</span><span style="color:#f92672">.</span>number_with_delimiter(<span style="color:#ae81ff">100</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;without helper&#34;</span>)        { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> i } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;number_with_precision&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Helper</span><span style="color:#f92672">.</span>number_with_precision(i <span style="color:#f92672">*</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">.</span><span style="color:#ae81ff">1123</span>, <span style="color:#e6db74">precision</span>: <span style="color:#ae81ff">2</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;without helper&#34;</span>)        { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#e6db74">&#39;%.2f&#39;</span> <span style="color:#f92672">%</span> (i<span style="color:#f92672">*</span><span style="color:#ae81ff">1</span><span style="color:#f92672">.</span><span style="color:#ae81ff">1123</span>) } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># number_with_delimiter  3.350000   0.010000   3.360000 (  3.360141)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># without helper         0.000000   0.000000   0.000000 (  0.004517)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># number_with_precision 10.220000   0.010000  10.230000 ( 10.221791)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># without helper         0.120000   0.000000   0.120000 (  0.121396)</span>
</span></span></code></pre></div><p>If you&rsquo;re generating huge lists, summaries or reports - every ms matters.</p>
<h3 id="hashes---to-fetch-or-not-to-fetch">Hashes - to .fetch or not to .fetch?</h3>
<p>Stop and thing about very simple thing as retrieving value from a hash. Let&rsquo;s run some benchmarks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;ostruct&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>hash <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> i }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;fetch, proc&#34;</span>)     { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">.</span>fetch(i) { <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;one&#34;</span>, <span style="color:#e6db74">b</span>: <span style="color:#e6db74">&#34;two&#34;</span>) } } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;fetch, argument&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">.</span>fetch(i, <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;one&#34;</span>, <span style="color:#e6db74">b</span>: <span style="color:#e6db74">&#34;two&#34;</span>))} }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;[]&#34;</span>)              { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fetch, proc            0.020000   0.000000   0.020000 (  0.024753)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fetch, argument        1.080000   0.010000   1.090000 (  1.085491)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># []                     0.020000   0.000000   0.020000 (  0.019607)</span>
</span></span></code></pre></div><p><code>[]</code> seems like the fastest way (by tiny margin) to get the value, but what the hell happened in <code>fetch</code> with provided default argument?! Let me tell you that - it&rsquo;s a trap ;-). If you provide argument to a fetch method it will be <em>always</em> evaluated, <code>proc</code> on the other hand is only called when given key is missing.</p>
<p>Another gotcha related to hashes that is worth mentioning here:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>puts({ <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">false</span>}<span style="color:#f92672">[</span><span style="color:#e6db74">&#34;false&#34;</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#66d9ef">true</span>)         <span style="color:#75715e"># -&gt; true</span>
</span></span><span style="display:flex;"><span>puts({ <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">false</span> }<span style="color:#f92672">.</span>fetch(<span style="color:#e6db74">&#34;false&#34;</span>) { <span style="color:#66d9ef">true</span> }) <span style="color:#75715e"># -&gt; false</span>
</span></span></code></pre></div><h3 id="use-rubys-native-methods">Use Ruby&rsquo;s native methods</h3>
<p>Even simple things like checking if given date is a weekend can be optimized. In example below first method uses naive approach, when second method refers to methods provided by <code>Date</code> class.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>days <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>at(i <span style="color:#f92672">*</span> <span style="color:#ae81ff">3600</span>) }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Weekend</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">include?</span>(date)
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">[</span><span style="color:#ae81ff">0</span>,<span style="color:#ae81ff">6</span><span style="color:#f92672">].</span>include?(date<span style="color:#f92672">.</span>wday)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">ruby</span>(date)
</span></span><span style="display:flex;"><span>     date<span style="color:#f92672">.</span>sunday? <span style="color:#f92672">||</span> date<span style="color:#f92672">.</span>saturday?
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;check array&#34;</span>)  { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Weekend</span><span style="color:#f92672">.</span>include?(days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;use c method&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Weekend</span><span style="color:#f92672">.</span>ruby(days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span>) } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># check array            0.160000   0.020000   0.180000 (  0.184166)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># use c method           0.040000   0.000000   0.040000 (  0.039794)</span>
</span></span></code></pre></div><h3 id="memoize-gotcha">Memoize gotcha</h3>
<p>Often you want to cache some method&rsquo;s result into instance variable (simply by using <code>||=</code>), but let&rsquo;s say it&rsquo;s a complex SQL query/algorithm that returns <code>false</code> - if this is the case it will be executed over and over again, you might even not notice it at the beginning. The solution to this problem is quite simple, but worth mentioning.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;ostruct&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">VariableCache</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">method1</span>
</span></span><span style="display:flex;"><span>    @method1 <span style="color:#f92672">||=</span> <span style="color:#66d9ef">begin</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;b&#34;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">method2</span>
</span></span><span style="display:flex;"><span>    @method2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">begin</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;b&#34;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span> <span style="color:#66d9ef">unless</span> defined?(@method2)
</span></span><span style="display:flex;"><span>    @method2
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>cache_test <span style="color:#f92672">=</span> <span style="color:#66d9ef">VariableCache</span><span style="color:#f92672">.</span>new
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;method1&#34;</span>) { iterations<span style="color:#f92672">.</span>each { cache_test<span style="color:#f92672">.</span>method1 }}
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;method2&#34;</span>) { iterations<span style="color:#f92672">.</span>each { cache_test<span style="color:#f92672">.</span>method2 }}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># method1                0.620000   0.000000   0.620000 (  0.629754)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># method2                0.010000   0.000000   0.010000 (  0.013680)</span>
</span></span></code></pre></div><p>Those tiny things can add up and affect usability of your app. If you ever encounter performance issues stop for a minute, browse your code, benchmark it. You can help yourself by using <a href="https://github.com/ruby-prof/ruby-prof">ruby-prof</a> or <a href="https://github.com/MiniProfiler/rack-mini-profiler">rack-mini-profiler</a> - those two tools are quite powerful, but that&rsquo;s a topic for yet another blog post ;).</p>
<p><em>Note: Benchmarks executed on ruby 2.1.2p95</em></p>]]></description><content:encoded><![CDATA[<p>-&gt; <img src="/images/slow_code.jpg" alt="Slow code?" title="Fry is confused about all this"> &lt;-</p>
<p>Ruby is very pretty, and unfortunattely it can be very slow. Beautiful syntax and flexebility of this language has its price (well, it&rsquo;s not so bad compared to other interpreted languages anyway).</p>
<p>Let&rsquo;s go over few (totally random) things that might cause performance issues.</p>
<h3 id="abusing-rails-view-helpers">Abusing rails view helpers</h3>
<p>Rails helpers are very useful, but if you&rsquo;re calling various helpers hundreds of times on a single page you might be surprised how much overhead it might produce. Do you really need that <code>number_with_delimiter</code> everywhere? Maybe you can use something simpler than <code>number_with_precision</code>?</p>
<p>Take a look at those two benchmarks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;action_view&#34;</span> <span style="color:#75715e">#rails 4.1.4</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Helper</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">extend</span> <span style="color:#66d9ef">ActionView</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Helpers</span><span style="color:#f92672">::</span><span style="color:#66d9ef">NumberHelper</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;number_with_delimiter&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Helper</span><span style="color:#f92672">.</span>number_with_delimiter(<span style="color:#ae81ff">100</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;without helper&#34;</span>)        { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> i } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;number_with_precision&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Helper</span><span style="color:#f92672">.</span>number_with_precision(i <span style="color:#f92672">*</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">.</span><span style="color:#ae81ff">1123</span>, <span style="color:#e6db74">precision</span>: <span style="color:#ae81ff">2</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;without helper&#34;</span>)        { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#e6db74">&#39;%.2f&#39;</span> <span style="color:#f92672">%</span> (i<span style="color:#f92672">*</span><span style="color:#ae81ff">1</span><span style="color:#f92672">.</span><span style="color:#ae81ff">1123</span>) } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># number_with_delimiter  3.350000   0.010000   3.360000 (  3.360141)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># without helper         0.000000   0.000000   0.000000 (  0.004517)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># number_with_precision 10.220000   0.010000  10.230000 ( 10.221791)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># without helper         0.120000   0.000000   0.120000 (  0.121396)</span>
</span></span></code></pre></div><p>If you&rsquo;re generating huge lists, summaries or reports - every ms matters.</p>
<h3 id="hashes---to-fetch-or-not-to-fetch">Hashes - to .fetch or not to .fetch?</h3>
<p>Stop and thing about very simple thing as retrieving value from a hash. Let&rsquo;s run some benchmarks:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;ostruct&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>hash <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> i }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;fetch, proc&#34;</span>)     { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">.</span>fetch(i) { <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;one&#34;</span>, <span style="color:#e6db74">b</span>: <span style="color:#e6db74">&#34;two&#34;</span>) } } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;fetch, argument&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">.</span>fetch(i, <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;one&#34;</span>, <span style="color:#e6db74">b</span>: <span style="color:#e6db74">&#34;two&#34;</span>))} }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;[]&#34;</span>)              { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> hash<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fetch, proc            0.020000   0.000000   0.020000 (  0.024753)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fetch, argument        1.080000   0.010000   1.090000 (  1.085491)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># []                     0.020000   0.000000   0.020000 (  0.019607)</span>
</span></span></code></pre></div><p><code>[]</code> seems like the fastest way (by tiny margin) to get the value, but what the hell happened in <code>fetch</code> with provided default argument?! Let me tell you that - it&rsquo;s a trap ;-). If you provide argument to a fetch method it will be <em>always</em> evaluated, <code>proc</code> on the other hand is only called when given key is missing.</p>
<p>Another gotcha related to hashes that is worth mentioning here:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>puts({ <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">false</span>}<span style="color:#f92672">[</span><span style="color:#e6db74">&#34;false&#34;</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#66d9ef">true</span>)         <span style="color:#75715e"># -&gt; true</span>
</span></span><span style="display:flex;"><span>puts({ <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">false</span> }<span style="color:#f92672">.</span>fetch(<span style="color:#e6db74">&#34;false&#34;</span>) { <span style="color:#66d9ef">true</span> }) <span style="color:#75715e"># -&gt; false</span>
</span></span></code></pre></div><h3 id="use-rubys-native-methods">Use Ruby&rsquo;s native methods</h3>
<p>Even simple things like checking if given date is a weekend can be optimized. In example below first method uses naive approach, when second method refers to methods provided by <code>Date</code> class.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>days <span style="color:#f92672">=</span> {}
</span></span><span style="display:flex;"><span>iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>at(i <span style="color:#f92672">*</span> <span style="color:#ae81ff">3600</span>) }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Weekend</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">include?</span>(date)
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">[</span><span style="color:#ae81ff">0</span>,<span style="color:#ae81ff">6</span><span style="color:#f92672">].</span>include?(date<span style="color:#f92672">.</span>wday)
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">ruby</span>(date)
</span></span><span style="display:flex;"><span>     date<span style="color:#f92672">.</span>sunday? <span style="color:#f92672">||</span> date<span style="color:#f92672">.</span>saturday?
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;check array&#34;</span>)  { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Weekend</span><span style="color:#f92672">.</span>include?(days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span>) } }
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;use c method&#34;</span>) { iterations<span style="color:#f92672">.</span>each { <span style="color:#f92672">|</span>i<span style="color:#f92672">|</span> <span style="color:#66d9ef">Weekend</span><span style="color:#f92672">.</span>ruby(days<span style="color:#f92672">[</span>i<span style="color:#f92672">]</span>) } }
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># check array            0.160000   0.020000   0.180000 (  0.184166)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># use c method           0.040000   0.000000   0.040000 (  0.039794)</span>
</span></span></code></pre></div><h3 id="memoize-gotcha">Memoize gotcha</h3>
<p>Often you want to cache some method&rsquo;s result into instance variable (simply by using <code>||=</code>), but let&rsquo;s say it&rsquo;s a complex SQL query/algorithm that returns <code>false</code> - if this is the case it will be executed over and over again, you might even not notice it at the beginning. The solution to this problem is quite simple, but worth mentioning.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ruby" data-lang="ruby"><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;benchmark&#34;</span>
</span></span><span style="display:flex;"><span>require <span style="color:#e6db74">&#34;ostruct&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">VariableCache</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">method1</span>
</span></span><span style="display:flex;"><span>    @method1 <span style="color:#f92672">||=</span> <span style="color:#66d9ef">begin</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;b&#34;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">method2</span>
</span></span><span style="display:flex;"><span>    @method2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">begin</span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">OpenStruct</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">a</span>: <span style="color:#e6db74">&#34;b&#34;</span>)
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">end</span> <span style="color:#66d9ef">unless</span> defined?(@method2)
</span></span><span style="display:flex;"><span>    @method2
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>iterations <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)
</span></span><span style="display:flex;"><span>cache_test <span style="color:#f92672">=</span> <span style="color:#66d9ef">VariableCache</span><span style="color:#f92672">.</span>new
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">Benchmark</span><span style="color:#f92672">.</span>bm(<span style="color:#ae81ff">20</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>x<span style="color:#f92672">|</span>
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;method1&#34;</span>) { iterations<span style="color:#f92672">.</span>each { cache_test<span style="color:#f92672">.</span>method1 }}
</span></span><span style="display:flex;"><span>  x<span style="color:#f92672">.</span>report(<span style="color:#e6db74">&#34;method2&#34;</span>) { iterations<span style="color:#f92672">.</span>each { cache_test<span style="color:#f92672">.</span>method2 }}
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">end</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#                            user     system      total        real</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># method1                0.620000   0.000000   0.620000 (  0.629754)</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># method2                0.010000   0.000000   0.010000 (  0.013680)</span>
</span></span></code></pre></div><p>Those tiny things can add up and affect usability of your app. If you ever encounter performance issues stop for a minute, browse your code, benchmark it. You can help yourself by using <a href="https://github.com/ruby-prof/ruby-prof">ruby-prof</a> or <a href="https://github.com/MiniProfiler/rack-mini-profiler">rack-mini-profiler</a> - those two tools are quite powerful, but that&rsquo;s a topic for yet another blog post ;).</p>
<p><em>Note: Benchmarks executed on ruby 2.1.2p95</em></p>]]></content:encoded></item></channel></rss>