Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrapping TimerOutputs macros

Tags:

macros

julia

I've got a situation where it would be handy to have a variable, to, which can either be a TimerOutput or nothing. I'm interested in providing a macro that takes the same arguments as @timeit from TimerOutputs (e.g. @timeit to "time spent" s = foo()). Because to is potentially set to nothing, I can't simply disable a TimerObject.

If to is set, my preference would be to pass the arguments along to @timeit, but could live with calling timer_expr(__module__, false, args...).

If to is not set, I'd want to just return the remaining arguments (something like args[3:end], maybe) as an expression.

I've been fussing with this for a day or so, and can handle each of the cases in isolation. For the case where I'm not involving TimerOutput, this seems to work:

macro no_timer(args...)
    args[3:end][1]
end

And for the case where I am using TimerOutput, I can do this:

macro with_timer(args...)
    timer_expr(__module__, false, args...)
end

Not surprising, as that's just what @timeit does.

I haven't figured out how to handle both cases in one macro. I've gotten the closest by wrapping everything in a ternary operator - i.e. return :(isnothing($(args[1])) ? <expression stuff> : <TimerOutput stuff>), but there is some level of abstraction mismatch that I haven't unsnarled.

Addendum: I've come to the conclusion that my original framing was an "X-Y" problem. I didn't actually need a new macro to solve my problem - hence my accepting the answer I did. That said, I am struck by the fact that both of the answers proffered stayed well away from defining a macro.

like image 947
user888379 Avatar asked Jun 18 '26 21:06

user888379


2 Answers

You have already this functionality in TimerOuputs. Just use disable_timer! and enable_timer! methods.

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
 ────────────────────────────────────────────────────────────────────
like image 154
Przemyslaw Szufel Avatar answered Jun 21 '26 16:06

Przemyslaw Szufel


You can define your own more specific version of the timer_expr function that the macro calls, where the returned expression contains a check for to argument being nothing, then doing the appropriate thing.


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

like image 22
Sundar R Avatar answered Jun 21 '26 16:06

Sundar R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!