Skip to content

Commit

Permalink
builtin: expose gc_disable(), gc_enable(), gc_is_enabled(), in additi…
Browse files Browse the repository at this point in the history
…on to the existing gc_collect() (#21002)
  • Loading branch information
spytheman committed Mar 12, 2024
1 parent a023fe3 commit a373bee
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
30 changes: 27 additions & 3 deletions vlib/builtin/builtin_d_gcboehm.c.v
Expand Up @@ -134,13 +134,37 @@ fn C.GC_is_disabled() int
// protect memory block from being freed before this call
fn C.GC_reachable_here(voidptr)

// gc_collect explicitly performs a garbage collection run.
// Note, that garbage collections are done automatically when needed in most cases,
// so usually you should need to call that function often.
// gc_is_enabled() returns true, if the GC is enabled at runtime.
// See also gc_disable() and gc_enable().
pub fn gc_is_enabled() bool {
return 0 == C.GC_is_disabled()
}

// gc_collect explicitly performs a single garbage collection run.
// Note, that garbage collections, are done automatically, when needed in most cases,
// so usually you should NOT need to call gc_collect() often.
// Note that gc_collect() is a NOP with `-gc none`.
pub fn gc_collect() {
C.GC_gcollect()
}

// gc_enable explicitly enables the GC.
// Note, that garbage collections are done automatically, when needed in most cases,
// and also that by default the GC is on, so you do not need to enable it.
// See also gc_disable() and gc_collect().
// Note that gc_enable() is a NOP with `-gc none`.
pub fn gc_enable() {
C.GC_enable()
}

// gc_disable explicitly disables the GC. Do not forget to enable it again by calling gc_enable(),
// when your program is otherwise idle, and can afford it.
// See also gc_enable() and gc_collect().
// Note that gc_disable() is a NOP with `-gc none`.
pub fn gc_disable() {
C.GC_disable()
}

// for leak detection it is advisable to do explicit garbage collections
pub fn gc_check_leaks() {
$if gcboehm_leak ? {
Expand Down
22 changes: 21 additions & 1 deletion vlib/builtin/builtin_notd_gcboehm.c.v
Expand Up @@ -24,8 +24,28 @@ fn C.GC_gcollect()
// When GC is not used, it is a NOP.
pub fn gc_check_leaks() {}

// gc_is_enabled() returns true, if the GC is enabled at runtime.
// It will always return false, with `-gc none`.
// See also gc_disable() and gc_enable().
pub fn gc_is_enabled() bool {
return false
}

// gc_enable explicitly enables the GC.
// Note, that garbage collections are done automatically, when needed in most cases,
// and also that by default the GC is on, so you do not need to enable it.
// See also gc_disable() and gc_collect().
// Note that gc_enable() is a NOP with `-gc none`.
pub fn gc_enable() {}

// gc_disable explicitly disables the GC. Do not forget to enable it again by calling gc_enable(),
// when your program is otherwise idle, and can afford it.
// See also gc_enable() and gc_collect().
// Note that gc_disable() is a NOP with `-gc none`.
pub fn gc_disable() {}

// gc_collect explicitly performs a garbage collection.
// When the GC is not on, it is a NOP.
// When the GC is not on, (with `-gc none`), it is a NOP.
pub fn gc_collect() {}

type FnGC_WarnCB = fn (msg &char, arg usize)
Expand Down
44 changes: 44 additions & 0 deletions vlib/v/tests/bench/bench_gc_enable_disable_collect.v
@@ -0,0 +1,44 @@
// The goal of this program, is to test V's garbage collector interaction with gc_disable(), gc_enable(), gc_collect() and `-gc none`.
// Note that this program is intended to be run on Linux, where /proc/PID/status exists.
// It should run on other platforms too, but the last columns of the output will be empty.
// Example invocation: `MAX_ITERATIONS=100 BLOCK_SIZE=1_000_000 v run gc.v` .
import os

const block_size = os.getenv_opt('BLOCK_SIZE') or { '1_000' }.int()
const max_iterations = os.getenv_opt('MAX_ITERATIONS') or { '40' }.int()

fn do_some_work_and_allocate_memory() u64 {
a := []u8{len: block_size, init: u8(index)}
mut s := u64(0)
for x in a {
s += x
}
return s
}

fn process_mem_stats(pid int) string {
lines := os.read_lines('/proc/${pid}/status') or { [] }
mut vals := map[string]string{}
for line in lines {
x := line.split(':')
vals[x[0]] = x[1]
}
return 'VmSize: ${vals['VmSize']} | VmRSS: ${vals['VmRSS']}'
}

fn main() {
println('BLOCK_SIZE: ${block_size:15}, MAX_ITERATIONS: ${max_iterations:5}, gc_is_enabled: ${gc_is_enabled()}')
gc_disable()
mypid := os.getpid()
for c := 0; c < max_iterations; c++ {
if c % 15 == 0 {
gc_enable()
}
gc_collect()
s := do_some_work_and_allocate_memory()
println('gc_is_enabled: ${gc_is_enabled():6}, c: ${c:5}, s: ${s:10}, gc_memory_use: ${gc_memory_use():10}, ${process_mem_stats(mypid):30}')
if c % 15 == 0 {
gc_disable()
}
}
}

0 comments on commit a373bee

Please sign in to comment.