github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/internal/poll/splice_linux_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package poll_test 6 7 import ( 8 "internal/poll" 9 "internal/syscall/unix" 10 "runtime" 11 "syscall" 12 "testing" 13 "time" 14 ) 15 16 // checkPipes returns true if all pipes are closed properly, false otherwise. 17 func checkPipes(fds []int) bool { 18 for _, fd := range fds { 19 // Check if each pipe fd has been closed. 20 _, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fd), syscall.F_GETPIPE_SZ, 0) 21 if errno == 0 { 22 return false 23 } 24 } 25 return true 26 } 27 28 func TestSplicePipePool(t *testing.T) { 29 const N = 64 30 var ( 31 p *poll.SplicePipe 32 ps []*poll.SplicePipe 33 fds []int 34 err error 35 ) 36 for i := 0; i < N; i++ { 37 p, _, err = poll.GetPipe() 38 if err != nil { 39 t.Skip("failed to create pipe, skip this test") 40 } 41 _, pwfd := poll.GetPipeFds(p) 42 fds = append(fds, pwfd) 43 ps = append(ps, p) 44 } 45 for _, p = range ps { 46 poll.PutPipe(p) 47 } 48 ps = nil 49 p = nil 50 51 // Exploit the timeout of "go test" as a timer for the subsequent verification. 52 timeout := 5 * time.Minute 53 if deadline, ok := t.Deadline(); ok { 54 timeout = deadline.Sub(time.Now()) 55 timeout -= timeout / 10 // Leave 10% headroom for cleanup. 56 } 57 expiredTime := time.NewTimer(timeout) 58 defer expiredTime.Stop() 59 60 // Trigger garbage collection repeatedly, waiting for all pipes in sync.Pool 61 // to either be deallocated and closed, or to time out. 62 for { 63 runtime.GC() 64 time.Sleep(10 * time.Millisecond) 65 if checkPipes(fds) { 66 break 67 } 68 select { 69 case <-expiredTime.C: 70 t.Fatal("at least one pipe is still open") 71 default: 72 } 73 } 74 } 75 76 func BenchmarkSplicePipe(b *testing.B) { 77 b.Run("SplicePipeWithPool", func(b *testing.B) { 78 for i := 0; i < b.N; i++ { 79 p, _, err := poll.GetPipe() 80 if err != nil { 81 continue 82 } 83 poll.PutPipe(p) 84 } 85 }) 86 b.Run("SplicePipeWithoutPool", func(b *testing.B) { 87 for i := 0; i < b.N; i++ { 88 p := poll.NewPipe() 89 if p == nil { 90 b.Skip("newPipe returned nil") 91 } 92 poll.DestroyPipe(p) 93 } 94 }) 95 } 96 97 func BenchmarkSplicePipePoolParallel(b *testing.B) { 98 b.RunParallel(func(pb *testing.PB) { 99 for pb.Next() { 100 p, _, err := poll.GetPipe() 101 if err != nil { 102 continue 103 } 104 poll.PutPipe(p) 105 } 106 }) 107 } 108 109 func BenchmarkSplicePipeNativeParallel(b *testing.B) { 110 b.RunParallel(func(pb *testing.PB) { 111 for pb.Next() { 112 p := poll.NewPipe() 113 if p == nil { 114 b.Skip("newPipe returned nil") 115 } 116 poll.DestroyPipe(p) 117 } 118 }) 119 }