@@ -6,17 +6,21 @@ struct SummarySize
6
6
frontier_i:: Vector{Int}
7
7
exclude:: Any
8
8
chargeall:: Any
9
+ count:: Bool
9
10
end
10
11
11
12
nth_pointer_isdefined (obj, i:: Int ) = ccall (:jl_nth_pointer_isdefined , Cint, (Any, Csize_t), obj, i- 1 ) != 0
12
13
get_nth_pointer (obj, i:: Int ) = ccall (:jl_get_nth_pointer , Any, (Any, Csize_t), obj, i- 1 )
13
14
14
15
"""
15
- Base.summarysize(obj; exclude=Union{...}, chargeall=Union{...})::Int
16
+ Base.summarysize(obj; count = false, exclude=Union{...}, chargeall=Union{...})::Int
16
17
17
- Compute the amount of memory, in bytes, used by all unique objects reachable from the argument.
18
+ Compute all unique objects reachable from the argument and return either their size in
19
+ memory (in bytes) or the number of allocations they span.
18
20
19
21
# Keyword Arguments
22
+ - `count`: if false, return the total size of the objects in memory. if true, return the
23
+ number of allocations spanned by the object.
20
24
- `exclude`: specifies the types of objects to exclude from the traversal.
21
25
- `chargeall`: specifies the types of objects to always charge the size of all of their
22
26
fields, even if those fields would normally be excluded.
@@ -33,28 +37,32 @@ julia> Base.summarysize(Ref(rand(100)))
33
37
34
38
julia> sizeof(Ref(rand(100)))
35
39
8
40
+
41
+ julia> Base.summarysize(Core.svec(1.0, "testing", true); count=true)
42
+ 4
36
43
```
37
44
"""
38
45
function summarysize (obj;
46
+ count:: Bool = false ,
39
47
exclude = Union{DataType, Core. TypeName, Core. MethodInstance},
40
48
chargeall = Union{Core. TypeMapEntry, Method})
41
49
@nospecialize obj exclude chargeall
42
- ss = SummarySize (IdDict (), Any[], Int[], exclude, chargeall)
50
+ ss = SummarySize (IdDict (), Any[], Int[], exclude, chargeall, count )
43
51
size:: Int = ss (obj)
44
52
while ! isempty (ss. frontier_x)
45
53
# DFS heap traversal of everything without a specialization
46
54
# BFS heap traversal of anything with a specialization
47
55
x = ss. frontier_x[end ]
48
56
i = ss. frontier_i[end ]
49
57
val = nothing
50
- if isa (x, SimpleVector)
58
+ if isa (x, Core . SimpleVector)
51
59
nf = length (x)
52
60
if isassigned (x, i)
53
61
val = x[i]
54
62
end
55
63
elseif isa (x, GenericMemory)
56
64
T = eltype (x)
57
- if Base . allocatedinline (T)
65
+ if allocatedinline (T)
58
66
np = datatype_npointers (T)
59
67
nf = length (x) * np
60
68
idx = (i- 1 ) ÷ np + 1
@@ -90,9 +98,9 @@ function summarysize(obj;
90
98
return size
91
99
end
92
100
93
- (ss:: SummarySize )(@nospecialize obj) = _summarysize (ss, obj)
101
+ (ss:: SummarySize )(@nospecialize obj) = _summarysize (ss, obj, ss . count )
94
102
# define the general case separately to make sure it is not specialized for every type
95
- @noinline function _summarysize (ss:: SummarySize , @nospecialize obj)
103
+ @noinline function _summarysize (ss:: SummarySize , @nospecialize ( obj), count :: Bool )
96
104
issingletontype (typeof (obj)) && return 0
97
105
# NOTE: this attempts to discover multiple copies of the same immutable value,
98
106
# and so is somewhat approximate.
112
120
# 0-field mutable structs are not unique
113
121
return gc_alignment (0 )
114
122
end
115
- return sz
123
+ return count ? 1 : sz
116
124
end
117
125
118
126
(:: SummarySize )(obj:: Symbol ) = 0
@@ -121,14 +129,13 @@ end
121
129
function (ss:: SummarySize )(obj:: String )
122
130
key = ccall (:jl_value_ptr , Ptr{Cvoid}, (Any,), obj)
123
131
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
124
- return Core. sizeof (Int) + Core. sizeof (obj)
132
+ return (ss . count ? 1 : ( Core. sizeof (Int) + Core. sizeof (obj)) )
125
133
end
126
134
127
135
function (ss:: SummarySize )(obj:: DataType )
128
136
key = pointer_from_objref (obj)
129
137
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
130
- size:: Int = 7 * Core. sizeof (Int) + 6 * Core. sizeof (Int32)
131
- size += 4 * nfields (obj) + ifelse (Sys. WORD_SIZE == 64 , 4 , 0 )
138
+ size:: Int = ss. count ? 1 : sizeof (DataType)
132
139
size += ss (obj. parameters):: Int
133
140
if isdefined (obj, :types )
134
141
size += ss (obj. types):: Int
@@ -139,30 +146,34 @@ end
139
146
function (ss:: SummarySize )(obj:: Core.TypeName )
140
147
key = pointer_from_objref (obj)
141
148
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
142
- return Core. sizeof (obj)
149
+ return (ss . count ? 1 : Core. sizeof (obj) )
143
150
end
144
151
145
152
function (ss:: SummarySize )(obj:: GenericMemory )
146
153
haskey (ss. seen, obj) ? (return 0 ) : (ss. seen[obj] = true )
147
- headersize = 2 * sizeof (Int)
148
- size:: Int = headersize
154
+ headersize = 2 * sizeof (Int)
155
+ size:: Int = (ss . count ? 1 : headersize)
149
156
datakey = unsafe_convert (Ptr{Cvoid}, obj)
150
157
if ! haskey (ss. seen, datakey)
151
158
ss. seen[datakey] = true
152
- size += sizeof (obj)
159
+ if ! ss. count
160
+ size += sizeof (obj)
161
+ elseif pointer_from_objref (obj) + 16 != datakey
162
+ size += 1
163
+ end
153
164
T = eltype (obj)
154
- if ! isempty (obj) && T != = Symbol && (! Base . allocatedinline (T) || (T isa DataType && ! Base . datatype_pointerfree (T)))
165
+ if ! isempty (obj) && T != = Symbol && (! allocatedinline (T) || (T isa DataType && ! datatype_pointerfree (T)))
155
166
push! (ss. frontier_x, obj)
156
167
push! (ss. frontier_i, 1 )
157
168
end
158
169
end
159
170
return size
160
171
end
161
172
162
- function (ss:: SummarySize )(obj:: SimpleVector )
173
+ function (ss:: SummarySize )(obj:: Core. SimpleVector )
163
174
key = pointer_from_objref (obj)
164
175
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
165
- size:: Int = Core. sizeof (obj)
176
+ size:: Int = (ss . count ? 1 : Core. sizeof (obj) )
166
177
if ! isempty (obj)
167
178
push! (ss. frontier_x, obj)
168
179
push! (ss. frontier_i, 1 )
172
183
173
184
function (ss:: SummarySize )(obj:: Module )
174
185
haskey (ss. seen, obj) ? (return 0 ) : (ss. seen[obj] = true )
175
- size:: Int = Core. sizeof (obj)
186
+ size:: Int = (ss . count ? 1 : Core. sizeof (obj) )
176
187
for binding in names (obj, all = true )
177
188
if isdefined (obj, binding) && ! isdeprecated (obj, binding)
178
189
value = getfield (obj, binding)
193
204
194
205
function (ss:: SummarySize )(obj:: Task )
195
206
haskey (ss. seen, obj) ? (return 0 ) : (ss. seen[obj] = true )
196
- size:: Int = Core. sizeof (obj)
207
+ size:: Int = (ss . count ? 1 : Core. sizeof (obj) )
197
208
if isdefined (obj, :code )
198
209
size += ss (obj. code):: Int
199
210
end
@@ -204,4 +215,4 @@ function (ss::SummarySize)(obj::Task)
204
215
return size
205
216
end
206
217
207
- (ss:: SummarySize )(obj:: BigInt ) = _summarysize (ss, obj) + obj. alloc* sizeof (Base . GMP. Limb)
218
+ (ss:: SummarySize )(obj:: BigInt ) = _summarysize (ss, obj, ss . count ) + (ss . count ? 1 : obj. alloc * sizeof (GMP. Limb) )
0 commit comments