Skip to content

Commit

Permalink
some improvements to summarysize, fixes #32881
Browse files Browse the repository at this point in the history
- 0-field mutable structs take 1 word
- include alignment in object sizes
- take uniqueness into account for Strings
- include union selector bytes for Arrays
  • Loading branch information
JeffBezanson committed Aug 13, 2019
1 parent df1ee8c commit dc450be
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 8 deletions.
2 changes: 1 addition & 1 deletion base/atomics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ inttype(::Type{Float32}) = Int32
inttype(::Type{Float64}) = Int64


gc_alignment(::Type{T}) where {T} = ccall(:jl_alignment, Cint, (Csize_t,), sizeof(T))
import ..Base.gc_alignment

# All atomic operations have acquire and/or release semantics, depending on
# whether the load or store values. Most of the time, this is what one wants
Expand Down
3 changes: 3 additions & 0 deletions base/reflection.jl
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ function datatype_alignment(dt::DataType)
return Int(alignment & 0x1FF)
end

gc_alignment(sz::Integer) = Int(ccall(:jl_alignment, Cint, (Csize_t,), sz))
gc_alignment(T::Type) = gc_alignment(Core.sizeof(T))

"""
Base.datatype_haspadding(dt::DataType) -> Bool
Expand Down
37 changes: 31 additions & 6 deletions base/summarysize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,29 @@ end
end
if isa(obj, UnionAll) || isa(obj, Union)
# black-list of items that don't have a Core.sizeof
return 2 * sizeof(Int)
sz = 2 * sizeof(Int)
else
sz = Core.sizeof(obj)
end
return Core.sizeof(obj)
if sz == 0
# 0-field mutable structs are not unique
return gc_alignment(0)
end
sz += sizeof(Int) # type tag
al = gc_alignment(sz)
return (sz + al - 1) & -al
end

(::SummarySize)(obj::Symbol) = 0
(::SummarySize)(obj::SummarySize) = 0
(::SummarySize)(obj::String) = Core.sizeof(Int) + Core.sizeof(obj)

function (ss::SummarySize)(obj::String)
key = ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), obj)
haskey(ss.seen, key) ? (return 0) : (ss.seen[key] = true)
sz = 2*Core.sizeof(Int) + Core.sizeof(obj)
al = gc_alignment(sz)
return (sz + al - 1) & -al
end

function (ss::SummarySize)(obj::DataType)
key = pointer_from_objref(obj)
Expand All @@ -103,12 +118,20 @@ end

function (ss::SummarySize)(obj::Array)
haskey(ss.seen, obj) ? (return 0) : (ss.seen[obj] = true)
headersize = 4*sizeof(Int) + 8 + max(0, ndims(obj)-2)*sizeof(Int)
headersize = 5*sizeof(Int) + 8 + max(0, ndims(obj)-2)*sizeof(Int)
headersize = (headersize + 64 - 1) & -64
size::Int = headersize
datakey = unsafe_convert(Ptr{Cvoid}, obj)
if !haskey(ss.seen, datakey)
ss.seen[datakey] = true
size += Core.sizeof(obj)
dsize = Core.sizeof(obj)
if isbitsunion(eltype(obj))
# add 1 union selector byte for each element
dsize += length(obj)
end
al = gc_alignment(dsize)
dsize = (dsize + al - 1) & -al
size += dsize
if !isbitstype(eltype(obj)) && !isempty(obj)
push!(ss.frontier_x, obj)
push!(ss.frontier_i, 1)
Expand All @@ -120,7 +143,9 @@ end
function (ss::SummarySize)(obj::SimpleVector)
key = pointer_from_objref(obj)
haskey(ss.seen, key) ? (return 0) : (ss.seen[key] = true)
size::Int = Core.sizeof(obj)
size::Int = sizeof(Int) + Core.sizeof(obj)
al = gc_alignment(size)
size = (size + al - 1) & -al
if !isempty(obj)
push!(ss.frontier_x, obj)
push!(ss.frontier_i, 1)
Expand Down
12 changes: 11 additions & 1 deletion test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ let R = Ref{Any}(nothing), depth = 10^6
R = Ref{Any}(R)
end
R = Core.svec(R, R)
@test summarysize(R) == (depth + 4) * sizeof(Ptr)
@test summarysize(R) == (2*(depth+1) + 4) * sizeof(Ptr)
end

# issue #25367 - summarysize with reshaped arrays
Expand All @@ -194,6 +194,16 @@ let A = zeros(1000), B = reshape(A, (1,1000))
@test summarysize(A) > sizeof(A)
end

# issue #32881
mutable struct S32881; end
let s = "abc"
@test summarysize([s,s]) < summarysize(["abc","xyz"])
@test summarysize("a") > sizeof(Int)+1
end
@test summarysize(Vector{Union{Nothing,Missing}}(undef, 16)) < summarysize(Vector{Union{Nothing,Missing}}(undef, 32))
@test summarysize(Vector{Nothing}(undef, 16)) == summarysize(Vector{Nothing}(undef, 32))
@test summarysize(S32881()) == sizeof(Int)

# issue #13021
let ex = try
Main.x13021 = 0
Expand Down

0 comments on commit dc450be

Please sign in to comment.