Improving Rails Performance | Part 1 | Execution Time Benchmarking

Juan Carlos Garzon
iCapital Network Technology Group
3 min readFeb 8, 2018

There comes a time in the course of development, when we realize how poorly optimized our code is. Ideally, we aim to do this as we code, but as we know, that’s not always the case. The pressure to get things done can and does often win over getting things done optimally.

Tasked with that mission, I decided to document my efforts, and just as importantly MEASURE performance, and share it with the developer community.

All my examples and tools are coming from Rails 4.2.7.1 + Angular 1.x perspective. But most of the general ideas are platform agnostic, and useful regardless of tech stack.

Benchmarking

So what is Benchmarking? Put simply benchmarking is the process gathering and comparing performance metrics.

In software development, there are two metrics in particular that we pay attention too. Those are execution time and memory. These are so important that there is a mathematical notation that is used in computer science to classify and analyze algorithms. If you don’t know it, I suggest you brush up on Big O notation, understanding these concepts should be your first line of defense toward writing code that performs faster and consumes less memory. I won’t go into here, but I may touch on this here or there.

To perform a benchmark, we will need to measure. Like any good carpenter who has their own set of tools, so must a developer. The good news is that Ruby comes with a Benchmark module baked in, which will help us measure execution time.

Simple guide on Execution Time Benchmarking

  • Require and Include the module
require ‘benchmark’
include Benchmark
  • Set your $stdout
    To make your life easier, set your $stdout. Doing this will log your results to a log file of your choosing, and will make it that much easier for you see your results.
$stdout = File.new(‘log/perf.log’, ‘a+’)
$stdout.sync = true

Keep in mind any puts, or printcommands will be logged in this file.

  • Performing the Benchmark test

For Execution Time benchmarking, you have the advantage of being able to test more than one block of code at a time.

To benchmark you’ll need to start by calling the Benchmark class, we’re going use the bm method. It provides a simple interface to generate sequential reports with labels. You can see the documentation for the module here.

This is what it looks like:

Benchmark.bm(7, “>total:”) do |x|
le = x.report(“line:”) { # Insert you code here }
cs = x.report(“custom:”) do # Insert your code here
end
# This will add up each report, and display it as a total
[le + cs]
end
  • View the results

So let’s run these benchmark testing using real code. Let’s measure the difference between counting from 1 to 5000000, between using three different kinds of counting loops.

Benchmark.bm(7, “>total:”) do |x|
forx = x.report(“for:”) { for i in 1..5000000; a = “1”; end }
times = x.report(“times:”) { 5000000.times do ; a = “1”; end }
upto = x.report(“upto:”) { 1.upto(5000000) do ; a = “1”; end }
[forx + times + upto]
end

With the code in place, and $stdout set. The only thing left to do is run your code.

From there all need to do is open log/perf.log (if you used my example) and see your results. The report should look something like this

user system total real
for: 4.180000 0.050000 4.230000 ( 4.303220)
times: 4.530000 0.040000 4.570000 ( 4.717092)
upto: 4.140000 0.030000 4.170000 ( 4.215828)
>total: 12.850000 0.120000 12.970000 ( 13.236140)

This report shows the user CPU time, system CPU time, the sum of the user and system CPU times, and the elapsed real time. They measure time in seconds.

With that done, you can now wash rinse repeat with your code and start performance testing the code execution time.

For more information about these tools.
Visit the Benchmark documentation page.

--

--