How can we easily time function calls in elixir?
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{...}]
- [1]: Code taken from http://www.littlelines.com/blog/2014/06/27/elixir-vs-ruby-showdown-part-one/
- Benchee https://github.com/bencheeorg/benchee
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.
Related videos on Youtube
Ponni Radhakrishnan
Updated on July 09, 2022Comments
-
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 about 9 yearsI 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 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 about 9 yearsas you can see in the documentation for
timer:tc/1
I linked in the previous comment, if you're only passing one argument totimer: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 about 9 years@whatyouhide thanks :timer.tc(Demo, :sum, [1000])
-
Overbryd about 9 years@whatyouhide your comment should be an answer.
-
-
Ponni Radhakrishnan about 9 yearsThanks, would be nice to have this build into the Iex tool.
-
Sasha Fonseca over 7 yearsWhat is the unit of time that function |> :timer.tc |> elem(0) |> Kernel./(1_000_000) returns? Is it microseconds?
-
sougonde over 7 yearsBenchwarmer version should be "~> 0.0.2" or installing dependencies will fail.
-
sk29910 over 7 years@SashaFonseca it's in seconds, since
timer.tc
returns microseconds. -
Justin DeMaris almost 7 yearsThe 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 almost 7 yearsSo 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.