Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
fail-fast: false
matrix:
version:
- '1.12'
- '1.12-nightly'
- 'nightly'
os:
- ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[compat]
DocStringExtensions = "0.9"
MethodAnalysis = "0.4"
MethodAnalysis = "0.4, 1"
julia = "1.12"

[extensions]
Expand Down
19 changes: 19 additions & 0 deletions ext/MethodAnalysisExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,23 @@ function MethodAnalysis.methodinstances(info::PkgCacheInfo)
return mis
end

function PkgCacheInspector.count_internal_specializations(info::PkgCacheInfo)
spec_counts = Dict{Module,Int}()

# Get all method instances from the cache
all_mis = methodinstances(info)

# Count method instances by their defining module
for mi in all_mis
if isa(mi, Core.MethodInstance) && isa(mi.def, Method)
method_module = mi.def.module
if method_module in info.modules
spec_counts[method_module] = get(spec_counts, method_module, 0) + 1
end
end
end

return spec_counts
end

end
78 changes: 78 additions & 0 deletions src/PkgCacheInspector.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,52 @@ function Base.show(io::IO, info::PkgCacheInfo)
nspecs = sort(collect(nspecs); by=last, rev=true)
nspecs_tot = sum(last, nspecs; init=0)

# Count internal methods and specializations
internal_methods = count_internal_methods(info)
total_internal = sum(values(internal_methods))

# Try to count internal specializations if MethodAnalysis is available
internal_specs = Dict{Module,Int}()
total_internal_specs = 0
internal_specs_sorted = Pair{Module,Int}[]

internal_specs = count_internal_specializations(info)
if internal_specs !== nothing
internal_specs_sorted = sort(collect(internal_specs); by=last, rev=true)
total_internal_specs = sum(last, internal_specs_sorted; init=0)
end

println(io, "Contents of ", info.cachefile, ':')
println(io, " modules: ", info.modules)
!isempty(info.init_order) && println(io, " init order: ", info.init_order)

# Show internal methods
if total_internal > 0
println(io, " ", total_internal, " internal methods")
if length(internal_methods) > 1
print(io, " (")
sorted_internal = sort(collect(internal_methods); by=last, rev=true)
for i = 1:length(sorted_internal)
mod, count = sorted_internal[i]
print(io, i==1 ? "" : ", ", nameof(mod), " ", count)
end
println(io, ")")
end
end

# Show internal specializations
if internal_specs === nothing
println(io, " specializations of internal methods: (requires MethodAnalysis.jl)")
elseif total_internal_specs > 0
print(io, " ", total_internal_specs, " specializations of internal methods ")
for i = 1:min(3, length(internal_specs_sorted))
mod, count = internal_specs_sorted[i]
pct = round(100*count/total_internal_specs; digits=1)
print(io, i==1 ? "(" : ", ", nameof(mod), " ", pct, "%")
end
println(io, length(internal_specs_sorted) > 3 ? ", ...)" : ")")
end

!isempty(info.external_methods) && println(io, " ", length(info.external_methods), " external methods")
if !isempty(info.new_specializations)
print(io, " ", length(info.new_specializations), " new specializations of external methods ")
Expand Down Expand Up @@ -182,6 +225,41 @@ function count_module_specializations(new_specializations)
return modcount
end

# count_internal_specializations is defined in MethodAnalysisExt when MethodAnalysis is loaded
count_internal_specializations(::Any) = nothing

# Count the number of methods defined within each of the package's own modules.
# These are methods that belong to the modules stored in the package image,
# as opposed to external methods which extend functions from other modules.
function count_internal_methods(info::PkgCacheInfo)
method_counts = Dict{Module,Int}()
for mod in info.modules
count = 0
# Count methods defined in this module
for name in names(mod; all=true)
if isdefined(mod, name)
obj = getfield(mod, name)
if isa(obj, Function)
for method in methods(obj)
if method.module == mod
count += 1
end
end
elseif isa(obj, Type) && isa(obj, DataType)
# Count constructors
for method in methods(obj)
if method.module == mod
count += 1
end
end
end
end
end
method_counts[mod] = count
end
return method_counts
end

function info_cachefile(pkg::PkgId, path::String, depmods::Vector{Any}, image_targets::Vector{Any}, isocache::Bool=false)
if isocache
sv = ccall(:jl_restore_package_image_from_file, Any, (Cstring, Any, Cint, Cstring, Cint), path, depmods, true, pkg.name, false)
Expand Down
2 changes: 2 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ module EmptyPkg end
str = sprint(show, info)
@test occursin("relocations", str) && occursin("new specializations", str) && occursin("targets", str)
@test occursin("file size", str)
@test occursin("internal methods", str)
@test occursin("specializations of internal methods", str)

mis = methodinstances(info)
@test eltype(mis) === Core.MethodInstance
Expand Down
Loading