Skip to content

Commit 12e1dba

Browse files
vilterpNHDaly
authored andcommitted
GC: enable logging to stderr when GC runs (JuliaLang#43511)
Co-authored-by: Nathan Daly <[email protected]>
1 parent 829cbb9 commit 12e1dba

File tree

8 files changed

+56
-2
lines changed

8 files changed

+56
-2
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ External dependencies
198198

199199
Tooling Improvements
200200
---------------------
201+
* `GC.enable_logging(true)` can be used to log each garbage collection, with the
202+
time it took and the amount of memory that was collected ([#43511]).
201203

202204

203205
<!--- generated by NEWS-update.jl: -->

base/gcutils.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,13 @@ collection to run.
197197
"""
198198
safepoint() = ccall(:jl_gc_safepoint, Cvoid, ())
199199

200+
"""
201+
GC.enable_logging(on::Bool)
202+
203+
When turned on, print statistics about each GC to stderr.
204+
"""
205+
function enable_logging(on::Bool=true)
206+
ccall(:jl_enable_gc_logging, Cvoid, (Cint,), on)
207+
end
208+
200209
end # module GC

doc/src/base/base.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ Base.GC.gc
433433
Base.GC.enable
434434
Base.GC.@preserve
435435
Base.GC.safepoint
436+
Base.GC.enable_logging
436437
Meta.lower
437438
Meta.@lower
438439
Meta.parse(::AbstractString, ::Int)

doc/src/manual/profile.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,12 +297,18 @@ on the author's laptop).
297297

298298
## Memory allocation analysis
299299

300-
One of the most common techniques to improve performance is to reduce memory allocation. The
301-
total amount of allocation can be measured with [`@time`](@ref) and [`@allocated`](@ref), and
300+
One of the most common techniques to improve performance is to reduce memory allocation. Julia
301+
provides several tools measure this:
302+
303+
### `@time`
304+
305+
The total amount of allocation can be measured with [`@time`](@ref) and [`@allocated`](@ref), and
302306
specific lines triggering allocation can often be inferred from profiling via the cost of garbage
303307
collection that these lines incur. However, sometimes it is more efficient to directly measure
304308
the amount of memory allocated by each line of code.
305309

310+
### Line-by-Line Allocation Tracking
311+
306312
To measure allocation line-by-line, start Julia with the `--track-allocation=<setting>` command-line
307313
option, for which you can choose `none` (the default, do not measure allocation), `user` (measure
308314
memory allocation everywhere except Julia's core code), or `all` (measure memory allocation at
@@ -321,6 +327,15 @@ you want to analyze, then call [`Profile.clear_malloc_data()`](@ref) to reset al
321327
Finally, execute the desired commands and quit Julia to trigger the generation of the `.mem`
322328
files.
323329

330+
### GC Logging
331+
332+
While [`@time`](@ref) logs high-level stats about memory usage and garbage collection over the course
333+
of evaluating an expression, it can be useful to log each garbage collection event, to get an
334+
intuitive sense of how often the garbage collector is running, how long it's running each time,
335+
and how much garbage it collects each time. This can be enabled with
336+
[`GC.enable_logging(true)`](@ref), which causes Julia to log to stderr every time
337+
a garbage collection happens.
338+
324339
## External Profiling
325340

326341
Currently Julia supports `Intel VTune`, `OProfile` and `perf` as external profiling tools.

src/gc-debug.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,23 @@ NOINLINE void gc_mark_loop_unwind(jl_ptls_t ptls, jl_gc_mark_sp_t sp, int pc_off
13801380
jl_set_safe_restore(old_buf);
13811381
}
13821382

1383+
static int gc_logging_enabled = 0;
1384+
1385+
JL_DLLEXPORT void jl_enable_gc_logging(int enable) {
1386+
gc_logging_enabled = enable;
1387+
}
1388+
1389+
void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect) JL_NOTSAFEPOINT {
1390+
if (!gc_logging_enabled) {
1391+
return;
1392+
}
1393+
jl_safe_printf("GC: pause %.2fms. collected %fMB. %s %s\n",
1394+
pause/1e6, freed/1e6,
1395+
full ? "full" : "incr",
1396+
recollect ? "recollect" : ""
1397+
);
1398+
}
1399+
13831400
#ifdef __cplusplus
13841401
}
13851402
#endif

src/gc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3205,6 +3205,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
32053205

32063206
uint64_t gc_end_t = jl_hrtime();
32073207
uint64_t pause = gc_end_t - t0;
3208+
3209+
_report_gc_finished(pause, gc_num.freed, sweep_full, recollect);
3210+
32083211
gc_final_pause_end(t0, gc_end_t);
32093212
gc_time_sweep_pause(gc_end_t, actual_allocd, live_bytes,
32103213
estimate_freed, sweep_full);

src/gc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,9 @@ void gc_count_pool(void);
696696

697697
size_t jl_array_nbytes(jl_array_t *a) JL_NOTSAFEPOINT;
698698

699+
JL_DLLEXPORT void jl_enable_gc_logging(int enable);
700+
void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect) JL_NOTSAFEPOINT;
701+
699702
#ifdef __cplusplus
700703
}
701704
#endif

test/misc.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,10 @@ end
10231023
GC.gc(true); GC.gc(false)
10241024

10251025
GC.safepoint()
1026+
1027+
GC.enable_logging(true)
1028+
GC.gc()
1029+
GC.enable_logging(false)
10261030
end
10271031

10281032
@testset "fieldtypes Module" begin

0 commit comments

Comments
 (0)