Performance issue when storing function in a struct as a field

I have a bit of code like this. In the function simulation, I generate a random tree and count the size of each subtree. Then I sim.func to the subtree sizes and add it up.

I mostly need sim.func=log. But to have some flexibility, I choose to make it a field in SubtreeSizeSimulator. However, this turns out to be about twice as slow as using log directly. Is there anyway to avoid such performance issue?

struct SubtreeSizeSimulator <: AbstractSimulator
    tree::FiniteTree
    func::Function
    funcname::String
end

function simulation(sim::SubtreeSizeSimulator)
    # simulate the random tree and get subtree sizes
    walker = SubtreeSizeWalker(sim.tree)
    walk(sim.tree, walker)
    subtree_sizes = result(walker)

    # sum over log of subtree sizes
    ret = 0
    for size in subtree_sizes
        #@fastmath ret += sim.func(size) # slow
        @fastmath ret += log(size) # much faster
    end
    ret
end

You want to use

struct SubtreeSizeSimulator{F<:Function} <: AbstractSimulator
    tree::FiniteTree
    func::F
    funcname::String
end

The difference is that this new one specializes the struct on the specific function you use (all functions are their own type), so this will make it efficient as long as your code is still type stable. This will still cause dynamic dispatch issues if you have a bunch of these each with different functions though.

5 Likes

This indeed solves the problem. Thanks.