Iβm trying to count the number of times a function is called; rather than assign a global variable by hand inside each function, it makes sense to use a macro. The instrumenting profiler can do this, but it seems overkill for what I want. Any tips on how best to do this?
type Counting{TF}
f::TF
counter::Int
end
Counting(f) = Counting(f, 0)
function (c::Counting)(args...)
c.counter += 1
c.f(args...)
end
cf = Counting(identity)
[cf(i) for i in 1:10]
cf.counter
@Tamas_Papp nice solution!
Iβd add one minor thing, to underline the fact that you can use this like the real function with almost no downsides:
type Counting{TF} <: Function # inherit from function, to integrate better with e.g. map
f::TF
counter::Int
end
# Define the function you want to count like this:
const my_function = Counting() do args...
# my function body
end
# use as like any other julia function
map(my_function, rand(10))
Yes, that works, thank you. The extra quote level was because I was fiddling to get something like this to work:
type Thing
fs::Vector{Function}
timer::TimerOutput
end
function Thing(funs::Symbol...)
timed_funs = Function[]
timer = TimerOutput()
for fun in funs
fname = Symbol("timed_$(fun)")
@eval begin
$(fname)(args...) = @timeit timer string($(fun)) $fun(args...)
push!($(timed_funs), $(fname))
end
end
return Thing(timed_funs, timer)
end
Somehow, the timed functions have lost track of timer:
julia> f(x) = x; g(x) = x+1; h(x) = x+2;
julia> thing = Thing(:f, :g, :h);
julia> [f(1) for f in thing.fs]
ERROR: UndefVarError: timer not defined
Iβd rather not pass timer as argument to the constructor because Iβd like to have several Things, each with its own timer.
I must be confused. I guess @timeit doesnβt quite behave like a closure?!
My thinking is if you want to have a function reference a global variable you need to make the variable global.
So perhaps something like:
function Thing(funs::Symbol...)
timed_funs = Function[]
timerlabel = gensym()
@eval const $timerlabel = TimerOutput()
for fun in funs
fname = Symbol("timed_$(fun)")
@eval begin
$(fname)(args...) = @timeit $(timerlabel) string($(fun)) $fun(args...)
push!($(timed_funs), $(fname))
end
end
return Thing(timed_funs, @eval $timerlabel)
end
giving
julia> f(x) = x; g(x) = x+1; h(x) = x+2;
julia> thing = Thing(:f, :g, :h);
julia> [f(1) for f in thing.fs]
3-element Array{Int64,1}:
1
2
3
julia> thing.timer
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Time Allocations
ββββββββββββββββββββββ βββββββββββββββββββββββ
Tot / % measured: 8.54s / 0.05% 14.0MiB / 0.02%
Section ncalls time %tot avg alloc %tot avg
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
h 1 1.57ms 33.8% 1.57ms - 35.2% -
g 1 1.56ms 33.6% 1.56ms - 35.2% -
f 1 1.51ms 32.6% 1.51ms - 29.7% -
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
I followed the instructions of the package but I could not get it to work. I want to track the number of function calls.
The function is defined inside a module and is being used by a variety of other modules. I am able to modify the code inside the module.
example code of my trial:
module MyModule
const to = TimerOutput()
function myFunc()
@timeit to "myFunc" begin
#normal computation of myFunc()
end
return
end
end
# code that uses other modules that use MyModule #
show(MyModule.to)
and the output is empty even though it counts time and allocations:
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Time Allocations
βββββββββββββββββββββββ ββββββββββββββββββββββββ
Tot / % measured: 13.1s / 0.0% 1.48GiB / 0.0%
Section ncalls time %tot avg alloc %tot avg
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
module MyModule
using TimerOutputs
const to = TimerOutput()
function myFunc()
@timeit to "myFunc" begin
sleep(0.00001)
end
return
end
end
using TimerOutputs
TimerOutputs.reset_timer!(MyModule.to)
for i in 1:100
MyModule.myFunc()
end
show(MyModule.to)