包装 TimerOutputs 宏
Wrapping TimerOutputs macros
我有一种情况,如果有一个变量 to
会很方便,它可以是 TimerOutput
或 nothing
。我有兴趣提供一个宏,它采用与来自 TimerOutputs 的 @timeit
相同的参数(例如 @timeit to "time spent" s = foo()
)。因为 to
可能设置为 nothing
,我不能简单地禁用 TimerObject。
如果设置了 to
,我的偏好是将参数传递给 @timeit
,但可以接受调用 timer_expr(__module__, false, args...)
.
如果未设置 to
,我只想 return 剩余的参数(可能类似于 args[3:end]
)作为表达式。
我已经纠结了一天左右,可以单独处理每个案例。对于我不涉及 TimerOutput 的情况,这似乎有效:
macro no_timer(args...)
args[3:end][1]
end
对于我 是 使用 TimerOutput 的情况,我可以这样做:
macro with_timer(args...)
timer_expr(__module__, false, args...)
end
不足为奇,因为这正是 @timeit
所做的。
我还没有想出如何在一个宏中处理这两种情况。我通过将所有内容包装在三元运算符中获得了最接近的结果 - 即 return :(isnothing($(args[1])) ? <expression stuff> : <TimerOutput stuff>)
,但是存在某种程度的抽象不匹配我还没有解开。
附录:我得出的结论是我的原始框架是一个“X-Y”问题。我实际上并不需要一个新的宏来解决我的问题 - 因此我接受了我所做的答案。也就是说,令我震惊的是,所提供的两个答案都远离定义宏。
您已经在 TimerOuputs 中拥有此功能。
只需使用 disable_timer!
和 enable_timer!
方法。
julia> const to = TimerOutput();
julia> disable_timer!(to);
julia> @timeit to "sleep" sleep(0.02)
julia> to
────────────────────────────────────────────────────────────────────
Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 23.6s / 0.0% 464KiB / 0.0%
Section ncalls time %tot avg alloc %tot avg
────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────
julia> enable_timer!(to);
julia> @timeit to "sleep" sleep(0.02)
julia> to
────────────────────────────────────────────────────────────────────
Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 37.3s / 0.1% 777KiB / 0.0%
Section ncalls time %tot avg alloc %tot avg
────────────────────────────────────────────────────────────────────
sleep 1 22.6ms 100.0% 22.6ms 320B 100.0% 320B
────────────────────────────────────────────────────────────────────
您可以定义自己更具体的宏调用的 timer_expr
函数版本,其中返回的表达式包含对 to
参数是否为 nothing
的检查,然后执行合适的东西。
import TimerOutputs: timer_expr
function timer_expr(m::Module, is_debug::Bool, to::Symbol, label::String, ex::Expr)
unescaped(ex) = ex.head == :escape ? ex.args[1] : ex
# this is from the original timer_expr functions,
# to be used when `to` isn't nothing
timer_ex = TimerOutputs.is_func_def(ex) ?
unescaped(TimerOutputs.timer_expr_func(m, is_debug, to, ex, label)) :
TimerOutputs._timer_expr(m, is_debug, to, label, ex)
cond_ex = esc(:(if isnothing($to)
$ex
else
placeholder # dummy symbol, to be replaced
end))
# args[3] = "else" section,
# the placeholder is args[2] within that
unescaped(cond_ex).args[3].args[2] = timer_ex
cond_ex
end
我有一种情况,如果有一个变量 to
会很方便,它可以是 TimerOutput
或 nothing
。我有兴趣提供一个宏,它采用与来自 TimerOutputs 的 @timeit
相同的参数(例如 @timeit to "time spent" s = foo()
)。因为 to
可能设置为 nothing
,我不能简单地禁用 TimerObject。
如果设置了 to
,我的偏好是将参数传递给 @timeit
,但可以接受调用 timer_expr(__module__, false, args...)
.
如果未设置 to
,我只想 return 剩余的参数(可能类似于 args[3:end]
)作为表达式。
我已经纠结了一天左右,可以单独处理每个案例。对于我不涉及 TimerOutput 的情况,这似乎有效:
macro no_timer(args...)
args[3:end][1]
end
对于我 是 使用 TimerOutput 的情况,我可以这样做:
macro with_timer(args...)
timer_expr(__module__, false, args...)
end
不足为奇,因为这正是 @timeit
所做的。
我还没有想出如何在一个宏中处理这两种情况。我通过将所有内容包装在三元运算符中获得了最接近的结果 - 即 return :(isnothing($(args[1])) ? <expression stuff> : <TimerOutput stuff>)
,但是存在某种程度的抽象不匹配我还没有解开。
附录:我得出的结论是我的原始框架是一个“X-Y”问题。我实际上并不需要一个新的宏来解决我的问题 - 因此我接受了我所做的答案。也就是说,令我震惊的是,所提供的两个答案都远离定义宏。
您已经在 TimerOuputs 中拥有此功能。
只需使用 disable_timer!
和 enable_timer!
方法。
julia> const to = TimerOutput();
julia> disable_timer!(to);
julia> @timeit to "sleep" sleep(0.02)
julia> to
────────────────────────────────────────────────────────────────────
Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 23.6s / 0.0% 464KiB / 0.0%
Section ncalls time %tot avg alloc %tot avg
────────────────────────────────────────────────────────────────────
────────────────────────────────────────────────────────────────────
julia> enable_timer!(to);
julia> @timeit to "sleep" sleep(0.02)
julia> to
────────────────────────────────────────────────────────────────────
Time Allocations
─────────────────────── ────────────────────────
Tot / % measured: 37.3s / 0.1% 777KiB / 0.0%
Section ncalls time %tot avg alloc %tot avg
────────────────────────────────────────────────────────────────────
sleep 1 22.6ms 100.0% 22.6ms 320B 100.0% 320B
────────────────────────────────────────────────────────────────────
您可以定义自己更具体的宏调用的 timer_expr
函数版本,其中返回的表达式包含对 to
参数是否为 nothing
的检查,然后执行合适的东西。
import TimerOutputs: timer_expr
function timer_expr(m::Module, is_debug::Bool, to::Symbol, label::String, ex::Expr)
unescaped(ex) = ex.head == :escape ? ex.args[1] : ex
# this is from the original timer_expr functions,
# to be used when `to` isn't nothing
timer_ex = TimerOutputs.is_func_def(ex) ?
unescaped(TimerOutputs.timer_expr_func(m, is_debug, to, ex, label)) :
TimerOutputs._timer_expr(m, is_debug, to, label, ex)
cond_ex = esc(:(if isnothing($to)
$ex
else
placeholder # dummy symbol, to be replaced
end))
# args[3] = "else" section,
# the placeholder is args[2] within that
unescaped(cond_ex).args[3].args[2] = timer_ex
cond_ex
end