Fastest way to get CodeInfo from a function call

Given a function f and its arguments args, Is there a faster way to get corresponding CodeInfo than code_lowered(f, map(typeof, args))? I don’t care about type inference and compiler optimizations - in fact, the closer to the original method definition, the better

I think code_lowered is really bare minimal already, it comes down to (as you probably have looked at):

julia> m = first(Base.method_instances(+, (Int, Int))).def
julia> Base.uncompressed_ir(m)
    @ int.jl:87 within `+`
1 ─ %1 = Base.add_int(x, y)
└──      return %1

and looks like if the function is not generated, the uncompressed_ir is just calling:

_uncompressed_ir(m::Method, s::Array{UInt8,1}) = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), m, C_NULL, s)::CodeInfo

on the byte vector of m.def.source

1 Like

Huh, actually, if we use only the methods you showed and skip a few checks you avoided, we get a good performance improvement for the first call on the first function:

# each line ran in a fresh Julia session
@time for fn in fns get_code_info(fn, 1.0) end      # 0.29s
@time for fn in fns get_code_info2(fn, 1.0) end     # 0.09
@time get_code_info(sin, 1.0)    # 0.23
@time get_code_info2(sin, 1.0)   # 0.08


function get_code_info(f, args...)
    types = map(typeof, args)
    cis = code_lowered(f, types)
    if isempty(cis)
        arg_type_str = join(types, ", ")
        error("Cannot get CodeInfo for $f($arg_type_str)")
    return cis[1]

function get_code_info2(f, args...)
    types = map(typeof, args)
    mis = Base.method_instances(f, types)
    if isempty(mis)
        arg_type_str = join(types, ", ")
        error("Cannot get CodeInfo for $f($arg_type_str)")
    m = first(mis).def
    ci = Base.uncompressed_ir(m)
    return ci

Anyway, the added latency of code_info() only shows up during the very first invocation, so probably it’s not worth the complexity. Thanks for confirming my expectations!

1 Like