Skip to content

Commit 7d37634

Browse files
authored
Don't tune manually set evals parameter (#318)
* Add evals_set field to benchmark parameters for manually set evals * Better testing and comments in docs * Forgot stuff * Replace 1 with true for evals_set
1 parent b3f4078 commit 7d37634

File tree

4 files changed

+53
-8
lines changed

4 files changed

+53
-8
lines changed

docs/src/manual.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ You can pass the following keyword arguments to `@benchmark`, `@benchmarkable`,
7979

8080
- `samples`: The number of samples to take. Execution will end if this many samples have been collected. Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.samples = 10000`.
8181
- `seconds`: The number of seconds budgeted for the benchmarking process. The trial will terminate if this time is exceeded (regardless of `samples`), but at least one sample will always be taken. In practice, actual runtime can overshoot the budget by the duration of a sample. Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.seconds = 5`.
82-
- `evals`: The number of evaluations per sample. For best results, this should be kept consistent between trials. A good guess for this value can be automatically set on a benchmark via `tune!`, but using `tune!` can be less consistent than setting `evals` manually. Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.evals = 1`.
82+
- `evals`: The number of evaluations per sample. For best results, this should be kept consistent between trials. A good guess for this value can be automatically set on a benchmark via `tune!`, but using `tune!` can be less consistent than setting `evals` manually (which bypasses tuning). Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.evals = 1`. If the function you study mutates its input, it is probably a good idea to set `evals=1` manually.
8383
- `overhead`: The estimated loop overhead per evaluation in nanoseconds, which is automatically subtracted from every sample time measurement. The default value is `BenchmarkTools.DEFAULT_PARAMETERS.overhead = 0`. `BenchmarkTools.estimate_overhead` can be called to determine this value empirically (which can then be set as the default value, if you want).
8484
- `gctrial`: If `true`, run `gc()` before executing this benchmark's trial. Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.gctrial = true`.
8585
- `gcsample`: If `true`, run `gc()` before each sample. Defaults to `BenchmarkTools.DEFAULT_PARAMETERS.gcsample = false`.

src/execution.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,17 @@ tune!(group::BenchmarkGroup; verbose::Bool = false, pad = "", kwargs...) =
243243
tune!(b::Benchmark, p::Parameters = b.params; verbose::Bool = false, pad = "", kwargs...)
244244
245245
Tune a `Benchmark` instance.
246+
247+
If the number of evals in the parameters `p` has been set manually, this function does nothing.
246248
"""
247249
function tune!(b::Benchmark, p::Parameters = b.params;
248250
progressid=nothing, nleaves=NaN, ndone=NaN, # ignored
249251
verbose::Bool = false, pad = "", kwargs...)
250-
warmup(b, verbose = false)
251-
estimate = ceil(Int, minimum(lineartrial(b, p; kwargs...)))
252-
b.params.evals = guessevals(estimate)
252+
if !p.evals_set
253+
warmup(b, verbose=false)
254+
estimate = ceil(Int, minimum(lineartrial(b, p; kwargs...)))
255+
b.params.evals = guessevals(estimate)
256+
end
253257
return b
254258
end
255259

@@ -268,6 +272,9 @@ function prunekwargs(args...)
268272
for ex in params
269273
if isa(ex, Expr) && ex.head == :(=)
270274
ex.head = :kw
275+
if ex.args[1] == :evals
276+
push!(params, :(evals_set = true))
277+
end
271278
end
272279
end
273280
if isa(core, Expr) && core.head == :kw

src/parameters.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,26 @@ mutable struct Parameters
99
seconds::Float64
1010
samples::Int
1111
evals::Int
12+
evals_set::Bool
1213
overhead::Float64
1314
gctrial::Bool
1415
gcsample::Bool
1516
time_tolerance::Float64
1617
memory_tolerance::Float64
1718
end
1819

19-
const DEFAULT_PARAMETERS = Parameters(5.0, 10000, 1, 0, true, false, 0.05, 0.01)
20+
const DEFAULT_PARAMETERS = Parameters(5.0, 10000, 1, false, 0, true, false, 0.05, 0.01)
2021

2122
function Parameters(; seconds = DEFAULT_PARAMETERS.seconds,
2223
samples = DEFAULT_PARAMETERS.samples,
2324
evals = DEFAULT_PARAMETERS.evals,
25+
evals_set = DEFAULT_PARAMETERS.evals_set,
2426
overhead = DEFAULT_PARAMETERS.overhead,
2527
gctrial = DEFAULT_PARAMETERS.gctrial,
2628
gcsample = DEFAULT_PARAMETERS.gcsample,
2729
time_tolerance = DEFAULT_PARAMETERS.time_tolerance,
2830
memory_tolerance = DEFAULT_PARAMETERS.memory_tolerance)
29-
return Parameters(seconds, samples, evals, overhead, gctrial,
31+
return Parameters(seconds, samples, evals, evals_set, overhead, gctrial,
3032
gcsample, time_tolerance, memory_tolerance)
3133
end
3234

@@ -57,8 +59,17 @@ function Base.:(==)(a::Parameters, b::Parameters)
5759
a.memory_tolerance == b.memory_tolerance
5860
end
5961

60-
Base.copy(p::Parameters) = Parameters(p.seconds, p.samples, p.evals, p.overhead, p.gctrial,
61-
p.gcsample, p.time_tolerance, p.memory_tolerance)
62+
Base.copy(p::Parameters) = Parameters(
63+
p.seconds,
64+
p.samples,
65+
p.evals,
66+
p.evals_set,
67+
p.overhead,
68+
p.gctrial,
69+
p.gcsample,
70+
p.time_tolerance,
71+
p.memory_tolerance
72+
)
6273

6374
function loadparams!(a::Parameters, b::Parameters, fields...)
6475
fields = isempty(fields) ? fieldnames(Parameters) : fields

test/ExecutionTests.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ loadparams!(oldgroups, params(groups))
6363

6464
@test oldgroups == oldgroupscopy == groups
6565

66+
# Explicitly set evals should not get tuned
67+
68+
b = @benchmarkable sin(1) evals=1
69+
tune!(b)
70+
@test params(b).evals == 1
71+
72+
b = @benchmarkable sin(1) evals=10
73+
tune!(b)
74+
@test params(b).evals == 10
75+
76+
function test_length_and_push!(x::AbstractVector)
77+
length(x) == 2 || error("setup not correctly executed")
78+
push!(x, randn())
79+
end
80+
81+
b_fail = @benchmarkable test_length_and_push!(y) setup=(y=randn(2))
82+
@test_throws Exception tune!(b_fail)
83+
84+
b_pass = @benchmarkable test_length_and_push!(y) setup=(y=randn(2)) evals=1
85+
@test tune!(b_pass) isa BenchmarkTools.Benchmark
86+
6687
#######
6788
# run #
6889
#######
@@ -81,6 +102,12 @@ testexpected(run(groups["sin"][first(sizes)]; seconds = 1, gctrial = false, time
81102

82103
testexpected(run(groups["sum"][first(sizes)], BenchmarkTools.DEFAULT_PARAMETERS))
83104

105+
# Mutating benchmark
106+
107+
b_pass = @benchmarkable test_length_and_push!(y) setup=(y=randn(2)) evals=1
108+
tune!(b_pass)
109+
@test run(b_pass) isa BenchmarkTools.Trial
110+
84111
###########
85112
# warmup #
86113
###########

0 commit comments

Comments
 (0)