Tic() + toc/toq() VS @elapsed


#1

Other than the difference in syntax, is there any essential difference between a combination of tic+toc and @elapsed? Any difference between what they return? The only difference described by the doc is as follows, which I don’t quite understand. Can anyone explain a bit?

instead returning the number of seconds it (i.e. @elapsed) took to execute as a floating-point number.

Thanks a lot!!


#2

The all use the same basic functionality (see time_ns()), but provide a different user interface. @time displays the time (and other info), use @elapsed when instead of displaying it, you would like to use the value, eg to compile statistics, etc, but see

tic and toc save the info in the global state (of the task). I find @time and @elapsed cleaner, but YMMV. Also, it is very easy to implement a combination of @elapsed and @time, if for some reason you need both the time and the value (eg as a tuple).


#3

In addition to @time, as @Tamas_Papp mentioned, there is also @timev, which displays even more detailed information (about memory allocations, the GC, etc.), that can help if you are trying to figure out a performance issue.


#4

Thanks both of you for the suggestions. Now I see the difference. I have been using BenchmarkTools.jl too to have more detailed statistics. However, if I want to use @elapsed or @benchmark, I have to wrap up all I want to time in a function. That’s not very convenient. That’s why I think I have to resort to using tic() and toc() sometimes.

May I know what most of you do when trying to time a few lines of your code in a big project or a large module? Do you also wrap the lines you want to time in a function in order to use @elapsed or @benchmark? Thanks!


#5

I use @benchmark to time a single call. BenchmarkTools is much more careful about compensating for externalities than are the other options.


#6

You do want to wrap things in a function for benchmarking. But otherwise you could use

@time begin
    ...
end

#7

Thanks. For a standalone function without much of dependencies, I use BenchmarkTools.jl too. What do you use for timing a few lines of code in a project?


#8

Thanks. This is very useful. One question - What is the breakdown of the time returned by @time? My understanding is the time returned by @time = compiling time + memory allocation time + computing time + GC time. Is it right?


#9

Never do this in global scope, though – the result is worse than meaningless. (I.e. it is actively misleading.)


#10

I don’t think so. First, @time just returns the result of evaluating the expression, not the elapsed time. That is displayed. At least on 0.5, it prints the elapsed time and the allocations (as a count, and the total memory allocated).


#11

For quick & dirty timing I use @time, twice, wrapping things in a function. I only care about the second result. I do this realizing that there could easily be ±20% sampling errors.

For anything more serious, I use BenchmarkTools.jl. Which is a great tool. For very little time investment (learning how to use it), you get very nice & consistent benchmarks. For something quick, I use seconds=3 to get three seconds worth of samples.


#12

What is displayed? Can you elaborate a bit?

Thanks!! This is very helpful


#13

The elapsed time (see second line below):

julia> x = @time 1+1
  0.000007 seconds (4 allocations: 160 bytes)
2

julia> x
2

which also demonstrates that the value of @time expr is the value of expr.


#14

Thanks. Well. I thought you something else. Now I understand what you meant.

Can you give a breakdown of the value returned by @elapsed? I’m sorry. I’m really curious what may contribute to the total returned by @elapsed. Thanks!!


#15

@elapsed just returns a single value, which, AFAIK, is wall time spent executing the expression (because time_ns() counts that). It is a very simple macro. You can read the source, eg using @edit @elapsed 1 or something like that.


#16
using BenchmarkTools

macro nanosecs(xs...)
    quote
        bench = @benchmark $(esc(xs...))
        t0 = bench.times[1]
        t1 = median(bench.times)
        tm = round(Int64, 2/(1/t0 + 1/t1))
        return tm
    end
end

macro memused(xs...)
    quote
        bench = @benchmark $(esc(xs...))
        a = bench.allocs
        m = bench.memory
        return (m,a)
    end
end

# use values held in variables
a = 0.75
@nanosecs sin(a)
# Int64 harmonic mean of fastest and median 
@memused sin(a)
# total bytes, distinct allocations

#17

Note that BenchmarkTools now has @btime and @belapsed, which are drop-in replacements for @time and @elapsed. (They take longer to run, however, because they spend some time collecting timing statistics, whereas @time and @elapsed only run the code once.)