@@ -9,6 +9,7 @@ gcscrub() = (GC.gc(); GC.gc(); GC.gc(); GC.gc())
9
9
10
10
mutable struct Benchmark
11
11
samplefunc
12
+ quote_vals
12
13
params:: Parameters
13
14
end
14
15
@@ -95,13 +96,13 @@ function _run(b::Benchmark, p::Parameters; verbose = false, pad = "", kwargs...)
95
96
start_time = Base. time ()
96
97
trial = Trial (params)
97
98
params. gcsample && gcscrub ()
98
- s = b. samplefunc (params)
99
+ s = b. samplefunc (b . quote_vals, params)
99
100
push! (trial, s[1 : end - 1 ]. .. )
100
101
return_val = s[end ]
101
102
iters = 2
102
103
while (Base. time () - start_time) < params. seconds && iters ≤ params. samples
103
104
params. gcsample && gcscrub ()
104
- push! (trial, b. samplefunc (params)[1 : end - 1 ]. .. )
105
+ push! (trial, b. samplefunc (b . quote_vals, params)[1 : end - 1 ]. .. )
105
106
iters += 1
106
107
end
107
108
return trial, return_val
@@ -157,7 +158,7 @@ function _lineartrial(b::Benchmark, p::Parameters = b.params; maxevals = RESOLUT
157
158
for evals in eachindex (estimates)
158
159
params. gcsample && gcscrub ()
159
160
params. evals = evals
160
- estimates[evals] = first (b. samplefunc (params))
161
+ estimates[evals] = first (b. samplefunc (b . quote_vals, params))
161
162
completed += 1
162
163
((time () - start_time) > params. seconds) && break
163
164
end
@@ -305,18 +306,22 @@ function collectvars(ex::Expr, vars::Vector{Symbol} = Symbol[])
305
306
return vars
306
307
end
307
308
308
- function quasiquote! (ex:: Expr , vars:: Vector{Expr} )
309
+ """
310
+ quasiquote!(expr::Expr, vars::Vector{Symbol}, vals::Vector{Expr})
311
+
312
+ Replace every interpolated value in `expr` with a placeholder variable and
313
+ store the resulting variable / value pairings in `vars` and `vals`.
314
+ """
315
+ quasiquote! (ex, _... ) = ex
316
+ function quasiquote! (ex:: Expr , vars:: Vector{Symbol} , vals:: Vector{Expr} )
309
317
if ex. head === :($ )
310
- lhs = ex. args[1 ]
311
- rhs = isa (lhs, Symbol) ? gensym (lhs) : gensym ( )
312
- push! (vars, Expr (:( = ), rhs, ex) )
313
- return rhs
318
+ var = isa ( ex. args[1 ], Symbol) ? gensym (ex . args[ 1 ]) : gensym ()
319
+ push! (vars, var )
320
+ push! (vals, ex )
321
+ return var
314
322
elseif ex. head != = :quote
315
323
for i in 1 : length (ex. args)
316
- arg = ex. args[i]
317
- if isa (arg, Expr)
318
- ex. args[i] = quasiquote! (arg, vars)
319
- end
324
+ ex. args[i] = quasiquote! (ex. args[i], vars, vals)
320
325
end
321
326
end
322
327
return ex
@@ -410,15 +415,11 @@ function benchmarkable_parts(args)
410
415
end
411
416
deleteat! (params, delinds)
412
417
413
- if isa (core, Expr)
414
- quote_vars = Expr[]
415
- core = quasiquote! (core, quote_vars)
416
- if ! isempty (quote_vars)
417
- setup = Expr (:block , setup, quote_vars... )
418
- end
419
- end
418
+ quote_vars = Symbol[]
419
+ quote_vals = Expr[]
420
+ core = quasiquote! (core, quote_vars, quote_vals)
420
421
421
- return core, setup, teardown, params
422
+ return core, setup, teardown, quote_vars, quote_vals, params
422
423
end
423
424
424
425
"""
@@ -428,7 +429,7 @@ Create a `Benchmark` instance for the given expression. `@benchmarkable`
428
429
has similar syntax with `@benchmark`. See also [`@benchmark`](@ref).
429
430
"""
430
431
macro benchmarkable (args... )
431
- core, setup, teardown, params = benchmarkable_parts (args)
432
+ core, setup, teardown, quote_vars, quote_vals, params = benchmarkable_parts (args)
432
433
map! (esc, params, params)
433
434
434
435
# extract any variable bindings shared between the core and setup expressions
@@ -441,6 +442,8 @@ macro benchmarkable(args...)
441
442
generate_benchmark_definition ($ __module__,
442
443
$ (Expr (:quote , out_vars)),
443
444
$ (Expr (:quote , setup_vars)),
445
+ $ (Expr (:quote , quote_vars)),
446
+ $ (esc (Expr (:vect ,Expr .(:quote , quote_vals)... ))),
444
447
$ (esc (Expr (:quote , core))),
445
448
$ (esc (Expr (:quote , setup))),
446
449
$ (esc (Expr (:quote , teardown))),
@@ -455,14 +458,14 @@ end
455
458
# The double-underscore-prefixed variable names are not particularly hygienic - it's
456
459
# possible for them to conflict with names used in the setup or teardown expressions.
457
460
# A more robust solution would be preferable.
458
- function generate_benchmark_definition (eval_module, out_vars, setup_vars, core, setup, teardown, params)
461
+ function generate_benchmark_definition (eval_module, out_vars, setup_vars, quote_vars, quote_vals, core, setup, teardown, params)
459
462
@nospecialize
460
463
corefunc = gensym (" core" )
461
464
samplefunc = gensym (" sample" )
462
- type_vars = [gensym () for i in 1 : length (setup_vars)]
463
- signature = Expr (:call , corefunc, setup_vars... )
465
+ type_vars = [gensym () for i in 1 : length (quote_vars) + length ( setup_vars)]
466
+ signature = Expr (:call , corefunc, quote_vars ... , setup_vars... )
464
467
signature_def = Expr (:where , Expr (:call , corefunc,
465
- [Expr (:(:: ), setup_var, type_var ) for (setup_var, type_var ) in zip (setup_vars, type_vars)]. .. )
468
+ [Expr (:(:: ), var, type ) for (var, type ) in zip ([quote_vars; setup_vars] , type_vars)]. .. )
466
469
, type_vars... )
467
470
if length (out_vars) == 0
468
471
invocation = signature
@@ -478,7 +481,7 @@ function generate_benchmark_definition(eval_module, out_vars, setup_vars, core,
478
481
end
479
482
return Core. eval (eval_module, quote
480
483
@noinline $ (signature_def) = begin $ (core_body) end
481
- @noinline function $ (samplefunc)(__params:: $BenchmarkTools.Parameters )
484
+ @noinline function $ (samplefunc)($ ( Expr ( :tuple , quote_vars ... )), __params:: $BenchmarkTools.Parameters )
482
485
$ (setup)
483
486
__evals = __params. evals
484
487
__gc_start = Base. gc_num ()
@@ -498,7 +501,7 @@ function generate_benchmark_definition(eval_module, out_vars, setup_vars, core,
498
501
__evals))
499
502
return __time, __gctime, __memory, __allocs, __return_val
500
503
end
501
- $ BenchmarkTools. Benchmark ($ (samplefunc), $ (params))
504
+ $ BenchmarkTools. Benchmark ($ (samplefunc), $ (quote_vals), $ ( params))
502
505
end )
503
506
end
504
507
0 commit comments