How can we easily time function calls in elixir?

20,824

Solution 1

You can write a module1 that can measure a given function. The following function returns the runtime of a given function in seconds:

defmodule Benchmark do
  def measure(function) do
    function
    |> :timer.tc
    |> elem(0)
    |> Kernel./(1_000_000)
  end
end

Use it like this:

iex> Benchmark.measure(fn -> 123456*654321 end)
9.0e-6

If you want to use that for Benchmarking, then there is another answer.

A better approach than measuring single run execution time is to measure operations per timeframe. This takes the code under test and executes it repeatingly within a given timeframe. This methodology yields more accurate results.

There is a library called Benchwarmer you can use for that:

Add Benchwarmer to your mix.exs

def deps do
  [ { :benchwarmer, "~> 0.0.2" } ]
end

Simply pass an inline function:

iex> Benchwarmer.benchmark fn -> 123456*654321 end
*** #Function<20.90072148/0 in :erl_eval.expr/5> ***
1.2 sec     2M iterations   0.61 μs/op

[%Benchwarmer.Results{...}]

Solution 2

This is an answer to a 6 year old question. But I ran into this topic while searching for such a capability and the module suggestion implies one can do:

{time, your_func_result} = :timer.tc(&your_func/arity, [your_func-args])

Thought I would drop that here in case someone else ended up searching for this. After all it's Erlang underneath. So you don't have to define another function in a module etc. time is in microseconds.

Share:
20,824

Related videos on Youtube

Ponni Radhakrishnan
Author by

Ponni Radhakrishnan

Updated on July 09, 2022

Comments

  • Ponni Radhakrishnan
    Ponni Radhakrishnan almost 2 years

    How can we easily time function calls in Elixir?

    Is there any hidden switch in IEx to enable this?

    • whatyouhide
      whatyouhide about 9 years
      I don't think there's an option to do that. Probably the easier and quickest way to do that is Erlang's timer:tc/1-2-3.
    • Ponni Radhakrishnan
      Ponni Radhakrishnan about 9 years
      @whatyouhide not sure what i'm doing wrong iex(54)> :timer.tc(Demo.sum 1000) ** (BadFunctionError) expected a function, got: 500500 (stdlib) timer.erl:165: :timer.tc/1
    • whatyouhide
      whatyouhide about 9 years
      as you can see in the documentation for timer:tc/1 I linked in the previous comment, if you're only passing one argument to timer:tc it has to be a function. Your example would be :timer.tc(fn -> Demo.sum(1000) end). If you want to pass a module+function+arguments triplet, just go with :timer.tc(Demo, :sum, [1000]).
    • Ponni Radhakrishnan
      Ponni Radhakrishnan about 9 years
      @whatyouhide thanks :timer.tc(Demo, :sum, [1000])
    • Overbryd
      Overbryd about 9 years
      @whatyouhide your comment should be an answer.
  • Ponni Radhakrishnan
    Ponni Radhakrishnan about 9 years
    Thanks, would be nice to have this build into the Iex tool.
  • Sasha Fonseca
    Sasha Fonseca over 7 years
    What is the unit of time that function |> :timer.tc |> elem(0) |> Kernel./(1_000_000) returns? Is it microseconds?
  • sougonde
    sougonde over 7 years
    Benchwarmer version should be "~> 0.0.2" or installing dependencies will fail.
  • sk29910
    sk29910 over 7 years
    @SashaFonseca it's in seconds, since timer.tc returns microseconds.
  • Justin DeMaris
    Justin DeMaris almost 7 years
    The Hex docs for IEx say: "The first one is that the code is truly evaluated and not compiled. This means that any benchmarking done in the shell is going to have skewed results. So never run any profiling nor benchmarks in the shell." Does this apply to these kind of imported libraries? Aka is this actually a realistic benchmark?
  • Overbryd
    Overbryd almost 7 years
    So the code above can be taken to compile and run a realistic benchmark. I will update the answer, so that I do not use iex for running the example.