Skip to content

Commit

Permalink
Merge pull request JuliaLang#33717 from JuliaLang/jn/allocated
Browse files Browse the repository at this point in the history
simplify allocated macro
  • Loading branch information
vtjnash committed Nov 15, 2019
2 parents 4caf944 + b36a8c6 commit bbccbac
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 68 deletions.
88 changes: 40 additions & 48 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@

# This type must be kept in sync with the C struct in src/gc.h
struct GC_Num
allocd ::Int64 # GC internal
deferred_alloc::Int64 # GC internal
freed ::Int64 # GC internal
malloc ::UInt64
realloc ::UInt64
poolalloc ::UInt64
bigalloc ::UInt64
freecall ::UInt64
total_time ::UInt64
total_allocd::UInt64 # GC internal
since_sweep ::UInt64 # GC internal
collect ::Csize_t # GC internal
pause ::Cint
full_sweep ::Cint
allocd ::Int64 # GC internal
deferred_alloc ::Int64 # GC internal
freed ::Int64 # GC internal
malloc ::Int64
realloc ::Int64
poolalloc ::Int64
bigalloc ::Int64
freecall ::Int64
total_time ::Int64
total_allocd ::Int64 # GC internal
since_sweep ::Int64 # GC internal
collect ::Csize_t # GC internal
pause ::Cint
full_sweep ::Cint
end

gc_num() = ccall(:jl_gc_num, GC_Num, ())
Expand All @@ -35,21 +35,21 @@ struct GC_Diff
end

gc_total_bytes(gc_num::GC_Num) =
(gc_num.allocd + gc_num.deferred_alloc + Int64(gc_num.total_allocd))
gc_num.allocd + gc_num.deferred_alloc + gc_num.total_allocd

function GC_Diff(new::GC_Num, old::GC_Num)
# logic from `src/gc.c:jl_gc_total_bytes`
old_allocd = gc_total_bytes(old)
new_allocd = gc_total_bytes(new)
return GC_Diff(new_allocd - old_allocd,
Int64(new.malloc - old.malloc),
Int64(new.realloc - old.realloc),
Int64(new.poolalloc - old.poolalloc),
Int64(new.bigalloc - old.bigalloc),
Int64(new.freecall - old.freecall),
Int64(new.total_time - old.total_time),
new.pause - old.pause,
new.full_sweep - old.full_sweep)
new.malloc - old.malloc,
new.realloc - old.realloc,
new.poolalloc - old.poolalloc,
new.bigalloc - old.bigalloc,
new.freecall - old.freecall,
new.total_time - old.total_time,
new.pause - old.pause,
new.full_sweep - old.full_sweep)
end

function gc_alloc_count(diff::GC_Diff)
Expand All @@ -60,9 +60,6 @@ end
# total time spend in garbage collection, in nanoseconds
gc_time_ns() = ccall(:jl_gc_total_hrtime, UInt64, ())

# total number of bytes allocated so far
gc_bytes() = ccall(:jl_gc_total_bytes, Int64, ())

# print elapsed time, return expression value
const _mem_units = ["byte", "KiB", "MiB", "GiB", "TiB", "PiB"]
const _cnt_units = ["", " k", " M", " G", " T", " P"]
Expand Down Expand Up @@ -159,6 +156,7 @@ julia> @time begin
"""
macro time(ex)
quote
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local stats = gc_num()
local elapsedtime = time_ns()
local val = $(esc(ex))
Expand Down Expand Up @@ -192,6 +190,7 @@ malloc() calls: 1
"""
macro timev(ex)
quote
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local stats = gc_num()
local elapsedtime = time_ns()
local val = $(esc(ex))
Expand All @@ -217,27 +216,21 @@ julia> @elapsed sleep(0.3)
"""
macro elapsed(ex)
quote
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local t0 = time_ns()
local val = $(esc(ex))
(time_ns()-t0)/1e9
$(esc(ex))
(time_ns() - t0) / 1e9
end
end

# measure bytes allocated without *most* contamination from compilation
# Note: This reports a different value from the @time macros, because
# it wraps the call in a function, however, this means that things
# like: @allocated y = foo()
# will not work correctly, because it will set y in the context of
# the local function made by the macro, not the current function
# total number of bytes allocated so far
gc_bytes(b::Ref{Int64}) = ccall(:jl_gc_get_total_bytes, Cvoid, (Ptr{Int64},), b)

"""
@allocated
A macro to evaluate an expression, discarding the resulting value, instead returning the
total number of bytes allocated during evaluation of the expression. Note: the expression is
evaluated inside a local function, instead of the current context, in order to eliminate the
effects of compilation, however, there still may be some allocations due to JIT compilation.
This also makes the results inconsistent with the `@time` macros, which do not try to adjust
for the effects of compilation.
total number of bytes allocated during evaluation of the expression.
See also [`@time`](@ref), [`@timev`](@ref), [`@timed`](@ref),
and [`@elapsed`](@ref).
Expand All @@ -249,15 +242,13 @@ julia> @allocated rand(10^6)
"""
macro allocated(ex)
quote
let
local f
function f()
b0 = gc_bytes()
$(esc(ex))
gc_bytes() - b0
end
f()
end
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local b0 = Ref{Int64}(0)
local b1 = Ref{Int64}(0)
gc_bytes(b0)
$(esc(ex))
gc_bytes(b1)
b1[] - b0[]
end
end

Expand Down Expand Up @@ -292,6 +283,7 @@ julia> memallocs.total_time
"""
macro timed(ex)
quote
while false; end # compiler heuristic: compile this block (alter this if the heuristic changes)
local stats = gc_num()
local elapsedtime = time_ns()
local val = $(esc(ex))
Expand Down
17 changes: 13 additions & 4 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2625,38 +2625,47 @@ JL_DLLEXPORT int jl_gc_enable(int on)
}
return prev;
}

JL_DLLEXPORT int jl_gc_is_enabled(void)
{
jl_ptls_t ptls = jl_get_ptls_states();
return !ptls->disable_gc;
}

JL_DLLEXPORT int64_t jl_gc_total_bytes(void)
JL_DLLEXPORT void jl_gc_get_total_bytes(int64_t *bytes)
{
jl_gc_num_t num = gc_num;
combine_thread_gc_counts(&num);
// Sync this logic with `base/util.jl:GC_Diff`
return (num.total_allocd + num.deferred_alloc + num.allocd);
*bytes = (num.total_allocd + num.deferred_alloc + num.allocd);
}

JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void)
{
return gc_num.total_time;
}

JL_DLLEXPORT jl_gc_num_t jl_gc_num(void)
{
jl_gc_num_t num = gc_num;
combine_thread_gc_counts(&num);
return num;
}

// TODO: these were supposed to be thread local
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void)
{
int64_t oldtb = last_gc_total_bytes;
int64_t newtb = jl_gc_total_bytes();
int64_t newtb;
jl_gc_get_total_bytes(&newtb);
last_gc_total_bytes = newtb;
return newtb - oldtb;
}
void jl_gc_sync_total_bytes(void) {last_gc_total_bytes = jl_gc_total_bytes();}

void jl_gc_sync_total_bytes(void)
{
jl_gc_get_total_bytes(&last_gc_total_bytes);
}

static void jl_gc_premark(jl_ptls_t ptls2)
{
Expand Down
3 changes: 0 additions & 3 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -749,9 +749,6 @@ extern void JL_GC_POP() JL_NOTSAFEPOINT;

JL_DLLEXPORT int jl_gc_enable(int on);
JL_DLLEXPORT int jl_gc_is_enabled(void);
JL_DLLEXPORT int64_t jl_gc_total_bytes(void);
JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void);
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void);

typedef enum {
JL_GC_AUTO = 0, // use heuristics to determine the collection type
Expand Down
1 change: 1 addition & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz);

JL_DLLEXPORT void JL_NORETURN jl_throw_out_of_memory_error(void);

JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void);
void jl_gc_sync_total_bytes(void);
void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT;
void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT;
Expand Down
4 changes: 2 additions & 2 deletions stdlib/Test/src/Test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1112,7 +1112,7 @@ function testset_beginend(args, tests, source)
err isa InterruptException && rethrow()
# something in the test block threw an error. Count that as an
# error in this test set
record(ts, Error(:nontest_error, :(), err, Base.catch_stack(), $(QuoteNode(source))))
record(ts, Error(:nontest_error, Expr(:tuple), err, Base.catch_stack(), $(QuoteNode(source))))
finally
copy!(RNG, oldrng)
end
Expand Down Expand Up @@ -1185,7 +1185,7 @@ function testset_forloop(args, testloop, source)
err isa InterruptException && rethrow()
# Something in the test block threw an error. Count that as an
# error in this test set
record(ts, Error(:nontest_error, :(), err, Base.catch_stack(), $(QuoteNode(source))))
record(ts, Error(:nontest_error, Expr(:tuple), err, Base.catch_stack(), $(QuoteNode(source))))
end
end
quote
Expand Down
8 changes: 5 additions & 3 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5019,13 +5019,15 @@ end
# when calculating total allocation size.
@noinline function f17255(n)
GC.enable(false)
b0 = Base.gc_bytes()
b0 = Ref{Int64}(0)
b1 = Ref{Int64}(0)
Base.gc_bytes(b0)
local a
for i in 1:n
a, t, allocd = @timed [Ref(1) for i in 1:1000]
@test allocd > 0
b1 = Base.gc_bytes()
if b1 < b0
Base.gc_bytes(b1)
if b1[] < b0[]
return false, a
end
end
Expand Down
8 changes: 4 additions & 4 deletions test/offsetarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -533,15 +533,15 @@ end
B = OffsetArray(reshape(1:24, 4, 3, 2), -5, 6, -7)
for R in (fill(0, -4:-1), fill(0, -4:-1, 7:7), fill(0, -4:-1, 7:7, -6:-6))
@test @inferred(maximum!(R, B)) == reshape(maximum(B, dims=(2,3)), axes(R)) == reshape(21:24, axes(R))
@test @allocated(maximum!(R, B)) <= 400
@test @allocated(maximum!(R, B)) <= 800
@test @inferred(minimum!(R, B)) == reshape(minimum(B, dims=(2,3)), axes(R)) == reshape(1:4, axes(R))
@test @allocated(minimum!(R, B)) <= 400
@test @allocated(minimum!(R, B)) <= 800
end
for R in (fill(0, -4:-4, 7:9), fill(0, -4:-4, 7:9, -6:-6))
@test @inferred(maximum!(R, B)) == reshape(maximum(B, dims=(1,3)), axes(R)) == reshape(16:4:24, axes(R))
@test @allocated(maximum!(R, B)) <= 400
@test @allocated(maximum!(R, B)) <= 800
@test @inferred(minimum!(R, B)) == reshape(minimum(B, dims=(1,3)), axes(R)) == reshape(1:4:9, axes(R))
@test @allocated(minimum!(R, B)) <= 400
@test @allocated(minimum!(R, B)) <= 800
end
@test_throws DimensionMismatch maximum!(fill(0, -4:-1, 7:7, -6:-6, 1:1), B)
@test_throws DimensionMismatch minimum!(fill(0, -4:-1, 7:7, -6:-6, 1:1), B)
Expand Down
2 changes: 0 additions & 2 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1492,8 +1492,6 @@ end
end

@testset "allocation of TwicePrecision call" begin
0:286.493442:360
0:286:360
@test @allocated(0:286.493442:360) == 0
@test @allocated(0:286:360) == 0
end
Expand Down
3 changes: 1 addition & 2 deletions test/syntax.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1845,8 +1845,7 @@ end
@testset "closure conversion in testsets" begin
p = (2, 3, 4)
@test p == (2, 3, 4)
identity(p)
allocs = @allocated identity(p)
allocs = (() -> @allocated identity(p))()
@test allocs == 0
end

Expand Down

0 comments on commit bbccbac

Please sign in to comment.