JuliaCI / BenchmarkTools.jl

A benchmarking framework for the Julia language
Other
617 stars 100 forks source link

`@btime` has constant runtime whereas `@time` is dependent on input #301

Closed roflmaostc closed 1 year ago

roflmaostc commented 1 year ago

Hi,

the following example confuses me.

The compiler is able to reduce the function to the constant O(1) Gauss sum. But only when used with @btime. With @time the runtime is dependent on N.

julia> using BenchmarkTools

julia> function f(N)
                  x = 0
                  for i in 1:N
                      x += i
                  end
                  x
              end
f (generic function with 2 methods)

julia> @time f(10)
  0.000001 seconds
55

julia> @time f(100_000)
  0.000109 seconds
5000050000

julia> @time f(100_000_000)
  0.107553 seconds
5000000050000000

julia> @btime $f(100_000_000)
  2.327 ns (0 allocations: 0 bytes)
5000000050000000

julia> @btime $f(100_000)
  2.328 ns (0 allocations: 0 bytes)
5000050000

julia> @btime $f(10)
  2.327 ns (0 allocations: 0 bytes)
55

Why is that?

vtjnash commented 1 year ago

btime inlines the computation for measuring repeated calls, while time records the cost of the call occurring once. Both accurate measurements, but of different operations.

roflmaostc commented 1 year ago

Hm, I'm confused :confused:

So @btime does not calculate the same operation? Does it execute the for-loop or not? Because @time executes the for-loop (it scales linearly with N where @btime doesn't)

julia> @btime $f(100_000_000) evals=1 samples=1
  365.000 ns (0 allocations: 0 bytes)
5000000050000000

julia> @time f(100_000_000)
  0.107526 seconds
5000000050000000
vchuravy commented 1 year ago

It take the call f(10) and creates a new function g() = f(10) and then benchmarks the call to g. Now N is known to be constant and the compiler can optimize that.

roflmaostc commented 1 year ago

Ah, got it! Thanks @vchuravy @vtjnash !