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