]> Cypherpunks repositories - gostls13.git/commitdiff
runtime,runtime/pprof: avoid tiny allocations in finalizer-related tests
authorNick Ripley <nick.ripley@datadoghq.com>
Tue, 19 Sep 2023 18:10:27 +0000 (14:10 -0400)
committerGopher Robot <gobot@golang.org>
Wed, 28 Feb 2024 20:13:50 +0000 (20:13 +0000)
A few tests rely on finalizers running, but are doing tiny allocations.
These tests will break if, for example, the testing package does is own
tiny allocations before calling the test function (see CL 478955). The
tiny allocator will group these allocations together and the ones done
for the tests themselves will live longer than desired. Use types which
have/are pointers for these tests so they won't be allocated by the tiny
allocator.

While here, pick up a small refactor suggested by Michael Knyszek to use
the BlockUntilEmptyFinalizerQueue helper to wait for the finalizers to
run in TestFinalizerRegisterABI.

Change-Id: I39f477d61f81dc76c87fae215339f8a38979cf94
Reviewed-on: https://go-review.googlesource.com/c/go/+/529555
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
src/runtime/abi_test.go
src/runtime/pprof/pprof_test.go

index d7039e758a4bb503d54c94b0da9ab5f0b28858ec..4caee597c5419e9fb10f600aa5bb2e546579f243 100644 (file)
@@ -15,25 +15,34 @@ import (
        "os"
        "os/exec"
        "runtime"
+       "runtime/internal/atomic"
        "strings"
        "testing"
        "time"
 )
 
-var regConfirmRun chan int
+var regConfirmRun atomic.Int32
 
 //go:registerparams
-func regFinalizerPointer(v *Tint) (int, float32, [10]byte) {
-       regConfirmRun <- *(*int)(v)
+func regFinalizerPointer(v *TintPointer) (int, float32, [10]byte) {
+       regConfirmRun.Store(int32(*(*int)(v.p)))
        return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
 }
 
 //go:registerparams
 func regFinalizerIface(v Tinter) (int, float32, [10]byte) {
-       regConfirmRun <- *(*int)(v.(*Tint))
+       regConfirmRun.Store(int32(*(*int)(v.(*TintPointer).p)))
        return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
 }
 
+// TintPointer has a pointer member to make sure that it isn't allocated by the
+// tiny allocator, so we know when its finalizer will run
+type TintPointer struct {
+       p *Tint
+}
+
+func (*TintPointer) m() {}
+
 func TestFinalizerRegisterABI(t *testing.T) {
        testenv.MustHaveExec(t)
 
@@ -87,10 +96,8 @@ func TestFinalizerRegisterABI(t *testing.T) {
        for i := range tests {
                test := &tests[i]
                t.Run(test.name, func(t *testing.T) {
-                       regConfirmRun = make(chan int)
-
-                       x := new(Tint)
-                       *x = (Tint)(test.confirmValue)
+                       x := &TintPointer{p: new(Tint)}
+                       *x.p = (Tint)(test.confirmValue)
                        runtime.SetFinalizer(x, test.fin)
 
                        runtime.KeepAlive(x)
@@ -99,13 +106,11 @@ func TestFinalizerRegisterABI(t *testing.T) {
                        runtime.GC()
                        runtime.GC()
 
-                       select {
-                       case <-time.After(time.Second):
+                       if !runtime.BlockUntilEmptyFinalizerQueue(int64(time.Second)) {
                                t.Fatal("finalizer failed to execute")
-                       case gotVal := <-regConfirmRun:
-                               if gotVal != test.confirmValue {
-                                       t.Fatalf("wrong finalizer executed? got %d, want %d", gotVal, test.confirmValue)
-                               }
+                       }
+                       if got := int(regConfirmRun.Load()); got != test.confirmValue {
+                               t.Fatalf("wrong finalizer executed? got %d, want %d", got, test.confirmValue)
                        }
                })
        }
index 6b299e59bf0899c9ff061a2e544f16122b11eda9..f57c1fed500dd58b6dda8a691d4f1b9aca967f9a 100644 (file)
@@ -1605,7 +1605,11 @@ func TestGoroutineProfileConcurrency(t *testing.T) {
 
        // The finalizer goroutine should show up when it's running user code.
        t.Run("finalizer present", func(t *testing.T) {
-               obj := new(byte)
+               // T is a pointer type so it won't be allocated by the tiny
+               // allocator, which can lead to its finalizer not being called
+               // during this test
+               type T *byte
+               obj := new(T)
                ch1, ch2 := make(chan int), make(chan int)
                defer close(ch2)
                runtime.SetFinalizer(obj, func(_ interface{}) {