Skip to content

Commit 834f39d

Browse files
Merge pull request #383 from singularitti/btimed
Add `@btimed` and `@ballocations` macros
2 parents 26e9209 + 659828a commit 834f39d

File tree

4 files changed

+104
-7
lines changed

4 files changed

+104
-7
lines changed

docs/src/manual.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
5757
Memory estimate: 0 bytes, allocs estimate: 0.
5858
```
5959

60-
Alternatively, you can use the `@btime` or `@belapsed` macros.
61-
These take exactly the same arguments as `@benchmark`, but
62-
behave like the `@time` or `@elapsed` macros included with
63-
Julia: `@btime` prints the minimum time and memory allocation
64-
before returning the value of the expression, while `@belapsed`
65-
returns the minimum time in seconds.
60+
Alternatively, you can use the `@btime`, `@btimed`,
61+
`@belapsed`, `@ballocated`, or `@ballocations` macros. These
62+
take exactly the same arguments as `@benchmark`, but behave
63+
like the `@time`, `@timed`, `@elapsed`, `@allocated`, or
64+
`@allocations` macros included with Julia.
6665

6766
```julia
6867
julia> @btime sin(1)
@@ -71,6 +70,15 @@ julia> @btime sin(1)
7170

7271
julia> @belapsed sin(1)
7372
1.3614228456913828e-8
73+
74+
julia> @btimed sin(1)
75+
(value = 0.8414709848078965, time = 9.16e-10, bytes = 0, alloc = 0, gctime = 0.0)
76+
77+
julia> @ballocated rand(4, 4)
78+
208
79+
80+
julia> @ballocations rand(4, 4)
81+
2
7482
```
7583

7684
### Benchmark `Parameters`

src/BenchmarkTools.jl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,16 @@ export BenchmarkGroup,
6363

6464
include("execution.jl")
6565

66-
export tune!, warmup, @ballocated, @benchmark, @benchmarkable, @belapsed, @btime, @bprofile
66+
export tune!,
67+
warmup,
68+
@ballocated,
69+
@ballocations,
70+
@benchmark,
71+
@benchmarkable,
72+
@belapsed,
73+
@btime,
74+
@btimed,
75+
@bprofile
6776

6877
#################
6978
# Serialization #

src/execution.jl

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,30 @@ macro ballocated(args...)
641641
)
642642
end
643643

644+
"""
645+
@ballocations expression [other parameters...]
646+
647+
Similar to the `@allocations` macro included with Julia,
648+
this macro evaluates an expression, discarding the resulting
649+
value, and returns the total number of allocations made
650+
during its execution.
651+
652+
Unlike `@allocations`, it uses the `@benchmark` macro from
653+
the `BenchmarkTools` package, and accepts all of the same
654+
additional parameters as `@benchmark`. The returned number
655+
of allocations corresponds to the trial with the *minimum*
656+
elapsed time measured during the benchmark.
657+
"""
658+
macro ballocations(args...)
659+
return esc(
660+
quote
661+
$BenchmarkTools.allocs(
662+
$BenchmarkTools.minimum($BenchmarkTools.@benchmark $(args...))
663+
)
664+
end,
665+
)
666+
end
667+
644668
"""
645669
@btime expression [other parameters...]
646670
@@ -684,6 +708,46 @@ macro btime(args...)
684708
)
685709
end
686710

711+
"""
712+
@btimed expression [other parameters...]
713+
714+
Similar to the `@timed` macro included with Julia, this
715+
macro executes an expression and returns a `NamedTuple`
716+
containing the value of the expression, the minimum elapsed
717+
time in seconds, the total bytes allocated, the number of
718+
allocations, and the garbage collection time in seconds
719+
during the benchmark.
720+
721+
Unlike `@timed`, it uses the `@benchmark` macro from the
722+
`BenchmarkTools` package for more detailed and consistent
723+
performance measurements. The elapsed time reported is the
724+
minimum time measured during the benchmark. It accepts all
725+
additional parameters supported by `@benchmark`.
726+
"""
727+
macro btimed(args...)
728+
_, params = prunekwargs(args...)
729+
bench, trial, result = gensym(), gensym(), gensym()
730+
trialmin = gensym()
731+
tune_phase = hasevals(params) ? :() : :($BenchmarkTools.tune!($bench))
732+
return esc(
733+
quote
734+
local $bench = $BenchmarkTools.@benchmarkable $(args...)
735+
$tune_phase
736+
local $trial, $result = $BenchmarkTools.run_result(
737+
$bench; warmup=$(hasevals(params))
738+
)
739+
local $trialmin = $BenchmarkTools.minimum($trial)
740+
(
741+
value=$result,
742+
time=$BenchmarkTools.time($trialmin) / 1e9, # `@timed` macro returns elapsed time in seconds
743+
bytes=$BenchmarkTools.memory($trialmin),
744+
alloc=$BenchmarkTools.allocs($trialmin),
745+
gctime=$BenchmarkTools.gctime($trialmin) / 1e9,
746+
)
747+
end,
748+
)
749+
end
750+
687751
"""
688752
@bprofile expression [other parameters...]
689753

test/ExecutionTests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,22 @@ str = String(take!(io))
345345
@test @ballocated(sin(0)) == 0
346346
@test @ballocated(Ref(1)) == 2 * sizeof(Int) # 1 for the pointer, 1 for content
347347

348+
@test @ballocations(sin($(foo.x)), evals = 3, samples = 10, setup = (foo.x = 0)) == 0
349+
@test @ballocations(sin(0)) == 0
350+
@test @ballocations(Ref(1)) == 1
351+
352+
@test let stats = @btimed sin($(foo.x)) evals = 3 samples = 10 setup = (foo.x = 0)
353+
stats.value == sin(0) &&
354+
stats.time > 0 &&
355+
stats.bytes == 0 &&
356+
stats.alloc == 0 &&
357+
stats.gctime == 0
358+
end
359+
360+
@test let stats = @btimed Ref(1)
361+
stats.bytes > 0 && stats.alloc == 1 && stats.gctime == 0
362+
end
363+
348364
let fname = tempname()
349365
try
350366
ret = open(fname, "w") do f

0 commit comments

Comments
 (0)