performance monitoring

182 views
Skip to first unread message

zak9...@gmail.com

unread,
Mar 17, 2015, 5:10:37 AM3/17/15
to elixir-l...@googlegroups.com
Hi Guys,

I have two questions as follow:
Q1- is there any performance penalty when using guards instead of logical switch (see examples below)? 

    defmodule GuardExample do
      def fun(x) when p1(x) do
        ...
      end

      def fun(x) when p2(x) do
        ...
      end
    end

    defmodule LogicalSwitchExample do
      def fun(x) do
        cond do
          p1(x) -> ...
          p2(x) -> ...
        end
      end
   end

Q2- is there any way in Elixir to know how long it takes a function to execute?



Thanks


X4lldux

unread,
Mar 17, 2015, 6:41:51 AM3/17/15
to elixir-l...@googlegroups.com
Q1: Think there is none, but I'll wait until someone smarter will answer this question.

Q2: Yes of course, couple of them in fact! ExProf is an elixir wrpapper around fprof. There are two good posts that show how to use those tools http://learningelixir.joekain.com/profiling-elixir/ http://learningelixir.joekain.com/profiling-elixir-2/

Ben Wilson

unread,
Mar 17, 2015, 9:30:20 AM3/17/15
to elixir-l...@googlegroups.com
For quick and easy benchmarking also check out :timer.tc. I believe there's also a benchmarking package on hex that's basically a wrapper around :timer.tc plus averages. Sorry I'm on mobile or I'd post links!

Joseph Kain

unread,
Mar 17, 2015, 11:40:31 AM3/17/15
to elixir-l...@googlegroups.com
Hi All, 

X4lldux, thanks for recommending my blog, I really appreciate it.

Ben Wilson, you might be thinking of my tool bmark: https://github.com/joekain/bmark.  There is also, Alco's benchfella: https://github.com/alco/benchfella.  

The way that benchfella automatically determines the number of runs of the benchmark to perform should be better for comparing small functions like you would want to use for comparing guards vs. switch.

Thanks,
Joseph Kain

zak9...@gmail.com

unread,
Mar 17, 2015, 5:14:49 PM3/17/15
to elixir-l...@googlegroups.com
Still no reply for question Q1!

Regarding Q2, I found this in Joe Armstrong book "Programming Erlang": erlang:statistics(runtime) and erlang:statistics(wall_clock)
so to know the time it takes for a function to execute is as follow:

defmodule Test do
  def fun_to_test() do
     :erlang.statistics(:runtime)
     :erlang.statistics(:wall_clock)

     # put your code here

     {_, time1} = :erlang.statistics(:runtime)
     {_, time2} = :erlang.statistics(:wall_clock)

     IO.puts("Code execution time #{time1 * 1000} (#{time2 * 1000}) microseconds")
  end
end

Thanks.

John W Higgins

unread,
Mar 17, 2015, 6:10:52 PM3/17/15
to elixir-l...@googlegroups.com
Would not the answer to Q1 be to test it yourself with the answer from Q2? I'm pretty certain that even if there is a standard answer - testing it yourself cannot be a bad thing to have under your belt.

John

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/ec0579d4-b61d-47ba-a7ed-f1826908a58a%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

zak9...@gmail.com

unread,
Mar 18, 2015, 1:31:03 AM3/18/15
to elixir-l...@googlegroups.com
John,
Thanks for the advice. I know now how to do it but I was just surprised that Q1 did not trigger any discussion!

Peter Hamilton

unread,
Mar 18, 2015, 3:30:20 AM3/18/15
to elixir-l...@googlegroups.com
If I recall correctly, pattern matching with guards (be it in a function definition or in a case statement) is faster as the VM is heavily optimized for it. cond is a macro that rewrites the statements into a case statement through all sorts of trickery which will generally make it a bit slower.

The cost might not be very large. Benchmark it yourself and let us know what you find. :-)

On Tue, Mar 17, 2015 at 10:31 PM <zak9...@gmail.com> wrote:
John,
Thanks for the advice. I know now how to do it but I was just surprised that Q1 did not trigger any discussion!

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-talk+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-talk/319eab7c-b294-4cfc-be70-bf442ed2d283%40googlegroups.com.

zak9...@gmail.com

unread,
Mar 18, 2015, 4:39:16 AM3/18/15
to elixir-l...@googlegroups.com
Thanks Peter, I will do!


On Wednesday, March 18, 2015 at 8:30:20 AM UTC+1, Peter Hamilton wrote:
If I recall correctly, pattern matching with guards (be it in a function definition or in a case statement) is faster as the VM is heavily optimized for it. cond is a macro that rewrites the statements into a case statement through all sorts of trickery which will generally make it a bit slower.

The cost might not be very large. Benchmark it yourself and let us know what you find. :-)

On Tue, Mar 17, 2015 at 10:31 PM <zak9...@gmail.com> wrote:
John,
Thanks for the advice. I know now how to do it but I was just surprised that Q1 did not trigger any discussion!

--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.

zak9...@gmail.com

unread,
Mar 18, 2015, 5:56:44 AM3/18/15
to elixir-l...@googlegroups.com
I did quick test using odds_and_evens_acc from Joe Armstrong "Programming Erlang" book as a basis to benchmark logical switch and guards. The list size was 1000.
Guards and case construct produce the same benchmark (310 microseconds) . However, as Peter guessed it, cond construct is slower (470 microseconds).


On Tuesday, March 17, 2015 at 10:10:37 AM UTC+1, zak9...@gmail.com wrote:

zak9...@gmail.com

unread,
Mar 18, 2015, 11:31:39 AM3/18/15
to elixir-l...@googlegroups.com
Here is the code in case you would like to try it yourself:

defmodule CondTest do
  def odds_and_evens_acc(l) do
    odds_and_evens_acc(l,[],[])
  end

  def odds_and_evens_acc([h|t], odds, evens) do
    cond do
      rem(h,2) == 0 -> odds_and_evens_acc(t, odds, [h|evens])
      rem(h,2) == 1 -> odds_and_evens_acc(t, [h|odds], evens)
    end
  end

  def odds_and_evens_acc([], odds, evens) do
    {odds, evens}
  end
  
  def benchmark(n \\ 10000) do
    coll = Enum.into(1..1000,[])
    :erlang.statistics(:runtime)
    :erlang.statistics(:wall_clock)
    Enum.each(1..n, fn(_i)-> odds_and_evens_acc(coll) end)

    {_, t1} = :erlang.statistics(:runtime)
    {_, t2} = :erlang.statistics(:wall_clock)
    u1 = t1 * 1000/n
    u2 = t2 * 1000/n
    IO.puts("code exec time #{u1} (#{u2}) microseconds")
  end
  
end


defmodule GuardsTest do
  def odds_and_evens_acc(l) do
    odds_and_evens_acc(l,[],[])
  end


  def odds_and_evens_acc([h|t], odds, evens) when rem(h,2) == 0 do
    odds_and_evens_acc(t, odds, [h|evens])
  end

  def odds_and_evens_acc([h|t], odds, evens) when rem(h,2) == 1 do
    odds_and_evens_acc(t, [h|odds], evens)
  end


  def odds_and_evens_acc([], odds, evens) do
    {odds, evens}
  end

  def benchmark(n \\ 10000) do
    coll = Enum.into(1..1000,[])
    :erlang.statistics(:runtime)
    :erlang.statistics(:wall_clock)
    Enum.each(1..n, fn(_i)-> odds_and_evens_acc(coll) end)

    {_, t1} = :erlang.statistics(:runtime)
    {_, t2} = :erlang.statistics(:wall_clock)
    u1 = t1 * 1000/n
    u2 = t2 * 1000/n
    IO.puts("code exec time #{u1} (#{u2}) microseconds")  
  end
end


On Tuesday, March 17, 2015 at 10:10:37 AM UTC+1, zak9...@gmail.com wrote:
Reply all
Reply to author
Forward
0 new messages