Skip to content

Instantly share code, notes, and snippets.

@timholy
Last active November 20, 2019 11:50
Show Gist options
  • Save timholy/1d0823269a1ceb592bfad457a41f178a to your computer and use it in GitHub Desktop.
Save timholy/1d0823269a1ceb592bfad457a41f178a to your computer and use it in GitHub Desktop.
Traversing all compiled methods
function traverse(val, mod::Module, visiting=Set{Module}())
push!(visiting, mod)
val = increment(val, mod)
for nm in names(mod; all=true)
if isdefined(mod, nm)
obj = getfield(mod, nm)
if isa(obj, Module)
obj in visiting && continue
val = traverse(val, obj, visiting)
else
val = traverse(val, obj)
end
end
end
return val
end
function traverse(val, f::Function)
val = increment(val, f)
Base.visit(methods(f).mt) do m
val = traverse(val, m)
end
return val
end
function traverse(val, m::Method)
val = increment(val, m)
for fn in (:specializations, :invokes)
if isdefined(m, fn)
spec = getfield(m, fn)
if spec === nothing
elseif isa(spec, Core.TypeMapEntry) || isa(spec, Core.TypeMapLevel)
Base.visit(spec) do m
val = traverse(val, m)
end
else
error("unhandled type ", typeof(spec))
end
end
end
return val
end
function traverse(val, mi::Core.MethodInstance)
val = increment(val, mi)
if isdefined(mi, :cache)
val = traverse(val, mi.cache)
end
return val
end
function traverse(val, ci::Core.CodeInstance)
val = increment(val, ci)
inf = ci.inferred
if isa(inf, Core.CodeInfo)
val = traverse(val, inf)
elseif isa(inf, Vector{UInt8})
inf = Core.Compiler._uncompressed_ast(ci, inf)
val = traverse(val, inf)
elseif isa(inf, Nothing)
else
error("unhandled type ", typeof(inf))
end
return val
end
traverse(val, x) = increment(val, x)
mutable struct TypeCounter{T}
nmodules::Int
nfunctions::Int
nmethods::Int
nmethodinstances::Int
ncodeinstances::Int
ncodeinfos::Int
nT::Int
end
TypeCounter{T}() where T = TypeCounter{T}(0, 0, 0, 0, 0, 0, 0)
function increment(val::TypeCounter, ::Module)
val.nmodules += 1
return val
end
function increment(val::TypeCounter, @nospecialize(::Function))
val.nfunctions += 1
return val
end
function increment(val::TypeCounter, ::Method)
val.nmethods += 1
return val
end
function increment(val::TypeCounter, ::Core.MethodInstance)
val.nmethodinstances += 1
return val
end
function increment(val::TypeCounter, ::Core.CodeInstance)
val.ncodeinstances += 1
return val
end
function increment(val::TypeCounter, src::Core.CodeInfo)
val.ncodeinfos += 1
vt = src.ssavaluetypes
if isa(vt, Vector{Any})
for typ in vt
# performance hotspot, use manual dispatch
if isa(typ, TypeVar)
val = _increment(val, typ)
elseif isa(typ, Core.TypeofBottom)
elseif isa(typ, Union)
val = _increment(val, typ)
elseif isa(typ, UnionAll)
val = _increment(val, Base.unwrap_unionall(typ))
elseif isa(typ, DataType)
val = _increment(val, typ)
end
end
end
return val
end
function _increment(val::TypeCounter{T}, @nospecialize(typ::Type)) where T
typ = Base.unwrap_unionall(typ)
typ === Union{} && return val
if isa(typ, DataType)
if typ <: T
val.nT += 1
end
for p in typ.parameters
if isa(p, Type)
val = _increment(val, p)
end
end
elseif isa(typ, Union)
val = _increment(val, typ.a)
val = _increment(val, typ.b)
else
error("unhandled type ", typeof(typ))
end
return val
end
function _increment(val::TypeCounter, tv::TypeVar)
val = _increment(val, tv.lb)
val = _increment(val, tv.ub)
end
increment(val::TypeCounter, @nospecialize(::Type)) = val
increment(val::TypeCounter, ::Any) = val
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment