@@ -6,17 +6,20 @@ 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 their quantity.
18
20
19
21
# Keyword Arguments
22
+ - `count`: if true, returns object quantity rather than total object size.
20
23
- `exclude`: specifies the types of objects to exclude from the traversal.
21
24
- `chargeall`: specifies the types of objects to always charge the size of all of their
22
25
fields, even if those fields would normally be excluded.
@@ -33,29 +36,33 @@ julia> Base.summarysize(Ref(rand(100)))
33
36
34
37
julia> sizeof(Ref(rand(100)))
35
38
8
39
+
40
+ julia> Base.summarysize(Core.svec(1.0, "testing", true); count=true)
41
+ 4
36
42
```
37
43
"""
38
44
function summarysize (obj;
45
+ count:: Bool = false ,
39
46
exclude = Union{DataType, Core. TypeName, Core. MethodInstance},
40
47
chargeall = Union{Core. TypeMapEntry, Method})
41
48
@nospecialize obj exclude chargeall
42
- ss = SummarySize (IdDict (), Any[], Int[], exclude, chargeall)
49
+ ss = SummarySize (IdDict (), Any[], Int[], exclude, chargeall, count )
43
50
size:: Int = ss (obj)
44
51
while ! isempty (ss. frontier_x)
45
52
# DFS heap traversal of everything without a specialization
46
53
# BFS heap traversal of anything with a specialization
47
54
x = ss. frontier_x[end ]
48
55
i = ss. frontier_i[end ]
49
56
val = nothing
50
- if isa (x, SimpleVector)
57
+ if isa (x, Core . SimpleVector)
51
58
nf = length (x)
52
59
if isassigned (x, i)
53
60
val = x[i]
54
61
end
55
62
elseif isa (x, GenericMemory)
56
63
T = eltype (x)
57
64
if Base. allocatedinline (T)
58
- np = datatype_npointers (T)
65
+ np = Base . datatype_npointers (T)
59
66
nf = length (x) * np
60
67
idx = (i- 1 ) ÷ np + 1
61
68
if @inbounds @inline isassigned (x, idx)
@@ -72,7 +79,7 @@ function summarysize(obj;
72
79
end
73
80
end
74
81
else
75
- nf = datatype_npointers (typeof (x))
82
+ nf = Base . datatype_npointers (typeof (x))
76
83
if nth_pointer_isdefined (x, i)
77
84
val = get_nth_pointer (x, i)
78
85
end
@@ -90,15 +97,15 @@ function summarysize(obj;
90
97
return size
91
98
end
92
99
93
- (ss:: SummarySize )(@nospecialize obj) = _summarysize (ss, obj)
100
+ (ss:: SummarySize )(@nospecialize obj) = _summarysize (ss, obj, ss . count )
94
101
# define the general case separately to make sure it is not specialized for every type
95
- @noinline function _summarysize (ss:: SummarySize , @nospecialize obj)
96
- issingletontype (typeof (obj)) && return 0
102
+ @noinline function _summarysize (ss:: SummarySize , @nospecialize ( obj), count :: Bool )
103
+ Base . issingletontype (typeof (obj)) && return 0
97
104
# NOTE: this attempts to discover multiple copies of the same immutable value,
98
105
# and so is somewhat approximate.
99
106
key = ccall (:jl_value_ptr , Ptr{Cvoid}, (Any,), obj)
100
107
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
101
- if datatype_npointers (typeof (obj)) > 0
108
+ if Base . datatype_npointers (typeof (obj)) > 0
102
109
push! (ss. frontier_x, obj)
103
110
push! (ss. frontier_i, 1 )
104
111
end
112
119
# 0-field mutable structs are not unique
113
120
return gc_alignment (0 )
114
121
end
115
- return sz
122
+ return count ? 1 : sz
116
123
end
117
124
118
125
(:: SummarySize )(obj:: Symbol ) = 0
@@ -121,14 +128,14 @@ end
121
128
function (ss:: SummarySize )(obj:: String )
122
129
key = ccall (:jl_value_ptr , Ptr{Cvoid}, (Any,), obj)
123
130
haskey (ss. seen, key) ? (return 0 ) : (ss. seen[key] = true )
124
- return Core. sizeof (Int) + Core. sizeof (obj)
131
+ return (ss . count ? 1 : ( Core. sizeof (Int) + Core. sizeof (obj)) )
125
132
end
126
133
127
134
function (ss:: SummarySize )(obj:: DataType )
128
135
key = pointer_from_objref (obj)
129
136
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 )
137
+ size:: Int = (ss . count ? 1 : ( 7 * Core. sizeof (Int) + 6 * Core. sizeof (Int32)) )
138
+ size += (ss . count ? 1 : ( 4 * nfields (obj) + ifelse (Sys. WORD_SIZE == 64 , 4 , 0 )) )
132
139
size += ss (obj. parameters):: Int
133
140
if isdefined (obj, :types )
134
141
size += ss (obj. types):: Int
@@ -139,17 +146,21 @@ 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
149
- datakey = unsafe_convert (Ptr{Cvoid}, obj)
154
+ headersize = 2 * sizeof (Int)
155
+ size:: Int = (ss . count ? 1 : headersize)
156
+ datakey = Base . 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) + headersize != datakey
162
+ size += 1
163
+ end
153
164
T = eltype (obj)
154
165
if ! isempty (obj) && T != = Symbol && (! Base. allocatedinline (T) || (T isa DataType && ! Base. datatype_pointerfree (T)))
155
166
push! (ss. frontier_x, obj)
@@ -159,10 +170,10 @@ function (ss::SummarySize)(obj::GenericMemory)
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 ) + obj. alloc * (ss . count ? 1 : sizeof (Base. GMP. Limb) )
0 commit comments