aboutsummaryrefslogtreecommitdiff
path: root/src/sync/oncefunc_test.go
AgeCommit message (Collapse)Author
2025-05-08runtime: schedule cleanups across multiple goroutinesMichael Anthony Knyszek
This change splits the finalizer and cleanup queues and implements a new lock-free blocking queue for cleanups. The basic design is as follows: The cleanup queue is organized in fixed-sized blocks. Individual cleanup functions are queued, but only whole blocks are dequeued. Enqueuing cleanups places them in P-local cleanup blocks. These are flushed to the full list as they get full. Cleanups can only be enqueued by an active sweeper. Dequeuing cleanups always dequeues entire blocks from the full list. Cleanup blocks can be dequeued and executed at any time. The very last active sweeper in the sweep phase is responsible for flushing all local cleanup blocks to the full list. It can do this without any synchronization because the next GC can't start yet, so we can be very certain that nobody else will be accessing the local blocks. Cleanup blocks are stored off-heap because the need to be allocated by the sweeper, which is called from heap allocation paths. As a result, the GC treats cleanup blocks as roots, just like finalizer blocks. Flushes to the full list signal to the scheduler that cleanup goroutines should be awoken. Every time the scheduler goes to wake up a cleanup goroutine and there were more signals than goroutines to wake, it then forwards this signal to runtime.AddCleanup, so that it creates another goroutine the next time it is called, up to gomaxprocs goroutines. The signals here are a little convoluted, but exist because the sweeper and the scheduler cannot safely create new goroutines. For #71772. For #71825. Change-Id: Ie839fde2b67e1b79ac1426be0ea29a8d923a62cc Reviewed-on: https://go-review.googlesource.com/c/go/+/650697 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Michael Knyszek <mknyszek@google.com>
2025-02-26sync: don't keep func alive after OnceFunc panicsMateusz Poliwczak
This moves the f = nil assignment to the defer statement, so that in case the functions panics, the f func is not referenced anymore. Change-Id: I3e53b90a10f21741e26602270822c8a75679f163 GitHub-Last-Rev: bda01100c6d48d1b0ca3e1baefef4d592cca1fee GitHub-Pull-Request: golang/go#68636 Reviewed-on: https://go-review.googlesource.com/c/go/+/601240 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
2025-02-25sync: reduce OnceFunc (and variants) heap allocationsBrian Byrne
The lifetime of the variables are identical; capture them in a single struct to avoid individual allocations. The inner closure can also avoid allocation by using the capture of the outer closure. Escape analysis for OnceValues: /go/src/sync/oncefunc.go:74:29: moved to heap: sync.f /go/src/sync/oncefunc.go:76:3: moved to heap: sync.once /go/src/sync/oncefunc.go:77:3: moved to heap: sync.valid /go/src/sync/oncefunc.go:78:3: moved to heap: sync.p /go/src/sync/oncefunc.go:79:3: moved to heap: sync.r1 /go/src/sync/oncefunc.go:80:3: moved to heap: sync.r2 /go/src/sync/oncefunc.go:82:7: func literal escapes to heap /go/src/sync/oncefunc.go:83:9: func literal does not escape /go/src/sync/oncefunc.go:93:9: func literal escapes to heap After provided changes: /go/src/sync/oncefunc.go:86:2: moved to heap: sync.d /go/src/sync/oncefunc.go:96:9: func literal escapes to heap /go/src/sync/oncefunc.go:99:13: func literal does not escape /go/src/sync/oncefunc.go:100:10: func literal does not escape Change-Id: Ib06e650fd427b57e0bdbdf1fe759fe436104ff79 Reviewed-on: https://go-review.googlesource.com/c/go/+/601596 Auto-Submit: Austin Clements <austin@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Austin Clements <austin@google.com>
2025-02-14sync: use runtime.AddCleanup instead of runtime.SetFinalizerCarlos Amedee
This changes the use of finalizers to the cleanup implementation in tests. Updates #70907 Change-Id: I7d7289999a83fa53f538698f34294f7d9651c921 Reviewed-on: https://go-review.googlesource.com/c/go/+/640735 Reviewed-by: Ian Lance Taylor <iant@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2023-11-21sync: do not unnecessarily keep alive functions wrapped by ↵Carlo Alberto Ferraris
Once(Func|Value|Values) The function passed to OnceFunc/OnceValue/OnceValues may transitively keep more allocations alive. As the passed function is guaranteed to be called at most once, it is safe to drop it after the first call is complete. This avoids keeping the passed function (and anything it transitively references) alive until the returned function is GCed. Change-Id: I2faf397b481d2f693ab3aea8e2981b02adbc7a21 Reviewed-on: https://go-review.googlesource.com/c/go/+/481515 Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: David Chase <drchase@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: qiulaidongfeng <2645477756@qq.com>
2023-03-31sync: implement OnceFunc, OnceValue, and OnceValuesAustin Clements
This adds the three functions from #56102 to the sync package. These provide a convenient API for the most common uses of sync.Once. The performance of these is comparable to direct use of sync.Once: $ go test -run ^$ -bench OnceFunc\|OnceVal -count 20 | benchstat -row .name -col /v goos: linux goarch: amd64 pkg: sync cpu: 11th Gen Intel(R) Core(TM) i7-1185G7 @ 3.00GHz │ Once │ Global │ Local │ │ sec/op │ sec/op vs base │ sec/op vs base │ OnceFunc 1.3500n ± 6% 2.7030n ± 1% +100.22% (p=0.000 n=20) 0.3935n ± 0% -70.86% (p=0.000 n=20) OnceValue 1.3155n ± 0% 2.7460n ± 1% +108.74% (p=0.000 n=20) 0.5478n ± 1% -58.35% (p=0.000 n=20) The "Once" column represents the baseline of how code would typically express these patterns using sync.Once. "Global" binds the closure returned by OnceFunc/OnceValue to global, which is how I expect these to be used most of the time. Currently, this defeats some inlining opportunities, which roughly doubles the cost over sync.Once; however, it's still *extremely* fast. Finally, "Local" binds the returned closure to a local variable. This unlocks several levels of inlining and represents pretty much the best possible case for these APIs, but is also unlikely to happen in practice. In principle the compiler could recognize that the global in the "Global" case is initialized in place and never mutated and do the same optimizations it does in the "Local" case, but it currently does not. Fixes #56102 Change-Id: If7355eccd7c8de7288d89a4282ff15ab1469e420 Reviewed-on: https://go-review.googlesource.com/c/go/+/451356 TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Andrew Gerrand <adg@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Caleb Spare <cespare@gmail.com> Auto-Submit: Austin Clements <austin@google.com>