diff --git a/base/show.jl b/base/show.jl index 9cd25aba2af9c..5a659baccdf7e 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1141,10 +1141,20 @@ function show_nd(io::IO, a::AbstractArray, limit, print_matrix, label_slices) end function whos(m::Module, pattern::Regex) + ptr_cache = Set() for v in sort(names(m)) s = string(v) if isdefined(m,v) && ismatch(pattern, s) - println(rpad(s, 30), summary(eval(m,v))) + tsz = "" + # totalsizeof might throw, whenever sizeof would throw + try + bytes = totalsizeof(getfield(m, v), ptr_cache) + bytes, mb = prettyprint_getunits(bytes, length(_mem_units), 1024) + tsz = string(lpad(bytes, 10), " ", rpad(_mem_units[mb], 6)) + catch + tsz = "undefined" + end + println(rpad(s, 30), rpad(tsz, 17), summary(eval(m,v))) end end end diff --git a/base/tuple.jl b/base/tuple.jl index e77abd8e328d9..c1235a7992485 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -15,6 +15,7 @@ getindex(t::Tuple, b::AbstractArray{Bool}) = getindex(t,find(b)) start(t::Tuple) = 1 done(t::Tuple, i::Int) = (length(t) < i) next(t::Tuple, i::Int) = (t[i], i+1) +eachindex(t::Tuple) = 1:length(t) # this allows partial evaluation of bounded sequences of next() calls on tuples, # while reducing to plain next() for arbitrary iterables. diff --git a/base/util.jl b/base/util.jl index 23a4e7f2ee870..d4d35eced9e31 100644 --- a/base/util.jl +++ b/base/util.jl @@ -220,6 +220,44 @@ macro allocated(ex) end end +# The sum of bytes that the given type references, including +# itself. The pointer cache (ptr_cache) can be provided. Pointers +# that are found in the cache do not count towards the sum. The +# cache must be a ``Set`` like object. +function totalsizeof(x, ptr_cache = Set()) + if in(pointer_from_objref(x), ptr_cache) + return 0 + end + push!(ptr_cache, pointer_from_objref(x)) + + if isa(x, DataType) || isa(x, Symbol) + return 0 + end + + sz = sizeof(x) + + for fn in fieldnames(x) + if isdefined(x, fn) + el = getfield(x, fn) + if !isbits(typeof(el)) + sz += totalsizeof(el, ptr_cache) + end + end + end + + if isa(x, AbstractArray) || isa(x, Tuple) + for idx in eachindex(x) + if isdefined(x, idx) + el = x[idx] + if !isbits(typeof(el)) + sz += totalsizeof(el, ptr_cache) + end + end + end + end + return sz +end + # print nothing, return value, elapsed time, bytes allocated & gc time macro timed(ex) quote diff --git a/test/misc.jl b/test/misc.jl index 04b9ea07e3515..7fddb5626201c 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -167,3 +167,30 @@ v11801, t11801 = @timed sin(1) @test isa(t11801,Real) && t11801 >= 0 @test names(current_module(), true) == names_before_timing + +# totalsizeof +@test Base.totalsizeof(Nothing) == 0 +@test Base.totalsizeof(10) == sizeof(10) +@test Base.totalsizeof(:mysymbol) >= 0 +@test Base.totalsizeof(Int) >= 0 +@test Base.totalsizeof(Base) >= 0 +@test Base.totalsizeof("123") >= 3 +@test Base.totalsizeof(sizeof) > 0 +@test Base.totalsizeof(rand) > 0 +@test Base.totalsizeof((1, 2, 3, 4)) >= 4*sizeof(Int) +@test Base.totalsizeof((1.0, 2.0, 3.0, 4.0)) >= 4*sizeof(typeof(1.0)) +@test Base.totalsizeof(Dict{Any, Any}("test1"=>2, "test2"=>3)) >= (8 + 2*sizeof(Int)) +@test Base.totalsizeof(Dict{String, Int}("test1"=>2, "test2"=>3)) >= (8 + 2*sizeof(Int)) +@test Base.totalsizeof([1 2 3]) >= sizeof([1 2 3]) +let + x = [1, 2, 3, 4] + y = (x, x, x, x, x, x) + ptr_cache = Set() + @test Base.totalsizeof(y, ptr_cache) < (Base.totalsizeof(x) * length(y)) +end +let + x = "some-string" + y = (x, x, x, x, x, x) + ptr_cache = Set() + @test Base.totalsizeof(y, ptr_cache) < (Base.totalsizeof(x) * length(y)) +end diff --git a/test/tuple.jl b/test/tuple.jl index f2e1bc4dee939..e82862a28a5de 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -49,6 +49,8 @@ @test_throws BoundsError next((5,6,7), 0) @test_throws BoundsError next((), 1) +@test (5,6,7)[eachindex((5,6,7))] === (5,6,7) +@test isempty(eachindex(())) ## eltype ##