Skip to content
13 changes: 13 additions & 0 deletions docs/src/manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,19 @@ julia> suite
As you might imagine, `BenchmarkGroup` supports a subset of Julia's `Associative` interface. A full list of
these supported functions can be found [in the reference document](reference.md#benchmarkgrouptagsvector-datadict).

One can also create a nested `BenchmarkGroup` simply by passing the keys, similar to how
`mkdir -p` works:

```julia
suite2 = BenchmarkGroup()

suite2["my"]["nested"]["benchmark"] = @benchmarkable sum(randn(32))
```

which will result in a hierarchical benchmark without us needing to create each `BenchmarkGroup` ourselves.
(Note that keys are automatically created upon access, even if a key does not exist. Thus, if you wish
to empty the unused keys, you can use `clear_empty!` to do so)

### Tuning and running a `BenchmarkGroup`

Similarly to individual benchmarks, you can `tune!` and `run` whole `BenchmarkGroup` instances (following from the previous section):
Expand Down
3 changes: 2 additions & 1 deletion src/BenchmarkTools.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export BenchmarkGroup,
addgroup!,
leaves,
@benchmarkset,
@case
@case,
clear_empty!

######################
# Execution Strategy #
Expand Down
16 changes: 13 additions & 3 deletions src/groups.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,26 @@ function addgroup!(suite::BenchmarkGroup, id, args...)
return g
end

clear_empty!(x) = x
function clear_empty!(group::BenchmarkGroup)
for (k,v) in pairs(group)
if v isa BenchmarkGroup && isempty(v)
delete!(group, k)
end
end
group
end

# Dict-like methods #
#-------------------#

Base.:(==)(a::BenchmarkGroup, b::BenchmarkGroup) = a.tags == b.tags && a.data == b.data
Base.copy(group::BenchmarkGroup) = BenchmarkGroup(copy(group.tags), copy(group.data))
Base.similar(group::BenchmarkGroup) = BenchmarkGroup(copy(group.tags), empty(group.data))
Base.isempty(group::BenchmarkGroup) = isempty(group.data)
Base.isempty(group::BenchmarkGroup) = isempty(clear_empty!(group).data)
Base.length(group::BenchmarkGroup) = length(group.data)
Base.getindex(group::BenchmarkGroup, k) = getindex(group.data, makekey(k))
Base.getindex(group::BenchmarkGroup, k...) = getindex(group.data, makekey(k))
Base.getindex(group::BenchmarkGroup, k) = get!(group.data, makekey(k), BenchmarkGroup())
Base.getindex(group::BenchmarkGroup, k...) = get!(group.data, makekey(k), BenchmarkGroup())
Base.setindex!(group::BenchmarkGroup, v, k) = setindex!(group.data, v, makekey(k))
Base.setindex!(group::BenchmarkGroup, v, k...) = setindex!(group.data, v, makekey(k))
Base.delete!(group::BenchmarkGroup, k) = delete!(group.data, makekey(k))
Expand Down
40 changes: 40 additions & 0 deletions test/GroupsTests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,44 @@ g1["c"] = tc
"c" => TrialEstimate(1.000 ns)
⋮"""

# EasyConfig-style benchmark groups #
#-----------------------------------#

g1 = BenchmarkGroup()
for T in [Float32, Float64], n in [10, 100], m in [5, 20]
g1["sum"][T][n][m] = @benchmarkable sum(x) setup=(x=randn($T, $n, $m))
end

# Test that the groups were created:
for T in [Float32, Float64], n in [10, 100], m in [5, 20]
@test "sum" in keys(g1.data)
@test string(T) in keys(g1["sum"].data)
@test n in keys(g1["sum"][T].data)
@test m in keys(g1["sum"][T][n].data)
@test typeof(g1["sum"][T][n][m]) == BenchmarkTools.Benchmark
end

# Expected side effect is that accessing groups creates them:
g1["ssum"]
@test "ssum" in keys(g1.data)
g1["ssum2"][Int32]
@test "ssum2" in keys(g1.data)
@test "Int32" in keys(g1["ssum2"].data)

# So we can clear the empty groups with `clear_empty!`:
clear_empty!(g1)

# Now it is clean
@test !("ssum" in keys(g1.data))
@test !("ssum2" in keys(g1.data))
# But other groups should still be present:
for T in [Float32, Float64], n in [10, 100], m in [5, 20]
@test "sum" in keys(g1.data)
@test string(T) in keys(g1["sum"].data)
@test n in keys(g1["sum"][T].data)
@test m in keys(g1["sum"][T][n].data)
@test typeof(g1["sum"][T][n][m]) == BenchmarkTools.Benchmark
end


# end # module