github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/pkg/pool/virtualmem/virtualmem_test.go (about) 1 // Copyright (c) 2023 Paweł Gaczyński 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package virtualmem 16 17 import ( 18 "crypto/rand" 19 "fmt" 20 "io/ioutil" 21 "log" 22 "os" 23 "os/exec" 24 "reflect" 25 "syscall" 26 "testing" 27 "unsafe" 28 29 . "github.com/stretchr/testify/require" 30 ) 31 32 func deallocate(data []byte, size int) error { 33 return internalMunmap(uintptr(unsafe.Pointer(&data[0])), size*2) 34 } 35 36 func allocateTempfileBuffer(size int) []byte { 37 nofd := ^uintptr(0) 38 39 vaddr, err := internalMmap( 40 0, 2*size, syscall.MAP_SHARED|syscall.MAP_ANONYMOUS, nofd) 41 if err != nil { 42 log.Panic(err) 43 } 44 45 file, err := ioutil.TempFile("", "magicbuffer") 46 if err != nil { 47 log.Panic(err) 48 } 49 defer file.Close() 50 51 if err = os.Remove(file.Name()); err != nil { 52 log.Panic(err) 53 } 54 55 fd := file.Fd() 56 if err = syscall.Ftruncate(int(fd), int64(size)); err != nil { 57 log.Panic(err) 58 } 59 60 _, err = internalMmap(vaddr, size, syscall.MAP_SHARED|syscall.MAP_FIXED, fd) 61 if err != nil { 62 log.Panic(fmt.Errorf("first internal mmap failed: %w", err)) 63 } 64 65 _, err = internalMmap( 66 vaddr+uintptr(size), size, syscall.MAP_SHARED|syscall.MAP_FIXED, fd) 67 if err != nil { 68 log.Panic(fmt.Errorf("second internal mmap failed: %w", err)) 69 } 70 71 sliceHeader := reflect.SliceHeader{ 72 Data: vaddr, 73 Len: 2 * size, 74 Cap: 2 * size, 75 } 76 buf := *(*[]byte)(unsafe.Pointer(&sliceHeader)) //nolint:govet 77 78 return buf 79 } 80 81 func BenchmarkVMTempFile(b *testing.B) { 82 var ( 83 pagesize = os.Getpagesize() 84 err error 85 ) 86 87 for i := 0; i < b.N; i++ { 88 data := allocateTempfileBuffer(pagesize) 89 if err = deallocate(data, pagesize); err != nil { 90 log.Panic(err) 91 } 92 } 93 } 94 95 func BenchmarkVMMemfd(b *testing.B) { 96 var ( 97 pagesize = os.Getpagesize() 98 err error 99 ) 100 101 for i := 0; i < b.N; i++ { 102 data := allocateBuffer(pagesize) 103 if err = deallocate(data, pagesize); err != nil { 104 log.Panic(err) 105 } 106 } 107 } 108 109 var printMapsAndFds = os.Getenv("TEST_PRINT_MAPS_AND_FDS") == "true" 110 111 var printCmd = func(label, cmd string) { 112 out, err := exec.Command("bash", "-c", cmd).Output() 113 if err != nil { 114 log.Panic(err) 115 } 116 117 if printMapsAndFds { 118 fmt.Printf("%s: %s\n", label, string(out)) //nolint:forbidigo 119 } 120 } 121 122 func TestMemfdMMapAndUnmap(_ *testing.T) { 123 pagesize := os.Getpagesize() 124 pid := os.Getpid() 125 listCmd := fmt.Sprintf("cat /proc/%d/maps", pid) 126 countCmd := fmt.Sprintf("cat /proc/%d/maps | wc -l", pid) 127 fdCmd := fmt.Sprintf("ls -l /proc/%d/fd | wc -l", pid) 128 129 printCmd("ulimit -a", "ulimit -a") 130 printCmd("max map count", "sysctl vm.max_map_count") 131 132 printList := func() { 133 printCmd("list of proc maps", listCmd) 134 } 135 printCount := func() { 136 printCmd("count of proc maps", countCmd) 137 } 138 printFds := func() { 139 printCmd("count of proc fds", fdCmd) 140 } 141 142 var ( 143 data []byte 144 err error 145 ) 146 147 printCount() 148 printFds() 149 150 for i := 0; i < 1; i++ { 151 data = allocateBuffer(pagesize) 152 if err = deallocate(data, pagesize); err != nil { 153 log.Panic(err) 154 } 155 } 156 157 printCount() 158 printFds() 159 160 for i := 0; i < 100; i++ { 161 data = allocateBuffer(pagesize) 162 if err = deallocate(data, pagesize); err != nil { 163 log.Panic(err) 164 } 165 } 166 167 printCount() 168 printFds() 169 170 for i := 0; i < 1000; i++ { 171 data = allocateBuffer(pagesize) 172 if err = deallocate(data, pagesize); err != nil { 173 log.Panic(err) 174 } 175 } 176 177 printCount() 178 printFds() 179 180 for i := 0; i < 10000; i++ { 181 data = allocateBuffer(pagesize) 182 if err = deallocate(data, pagesize); err != nil { 183 log.Panic(err) 184 } 185 } 186 187 printCount() 188 printFds() 189 190 for i := 0; i < 10000; i++ { 191 data = allocateBuffer(pagesize) 192 if err = deallocate(data, pagesize); err != nil { 193 log.Panic(err) 194 } 195 } 196 197 printCount() 198 printFds() 199 200 for i := 0; i < 10000; i++ { 201 data = allocateBuffer(pagesize) 202 if err = deallocate(data, pagesize); err != nil { 203 log.Panic(err) 204 } 205 } 206 207 printCount() 208 printFds() 209 210 for i := 0; i < 10000; i++ { 211 data = allocateBuffer(pagesize) 212 if err = deallocate(data, pagesize); err != nil { 213 log.Panic(err) 214 } 215 } 216 217 printCount() 218 printFds() 219 220 for i := 0; i < 10000; i++ { 221 data = allocateBuffer(pagesize) 222 if err = deallocate(data, pagesize); err != nil { 223 log.Panic(err) 224 } 225 } 226 227 printCount() 228 printFds() 229 230 for i := 0; i < 10000; i++ { 231 data = allocateBuffer(pagesize) 232 if err = deallocate(data, pagesize); err != nil { 233 log.Panic(err) 234 } 235 } 236 237 printCount() 238 printFds() 239 240 for i := 0; i < 10000; i++ { 241 data = allocateBuffer(pagesize) 242 if err = deallocate(data, pagesize); err != nil { 243 log.Panic(err) 244 } 245 } 246 247 printCount() 248 printFds() 249 250 for i := 0; i < 10000; i++ { 251 data = allocateBuffer(pagesize) 252 if err = deallocate(data, pagesize); err != nil { 253 log.Panic(err) 254 } 255 } 256 257 printCount() 258 printFds() 259 260 for i := 0; i < 10000; i++ { 261 data = allocateBuffer(pagesize) 262 if err = deallocate(data, pagesize); err != nil { 263 log.Panic(err) 264 } 265 } 266 267 printCount() 268 printFds() 269 270 for i := 0; i < 30000; i++ { 271 data = allocateBuffer(pagesize) 272 if err = deallocate(data, pagesize); err != nil { 273 log.Panic(err) 274 } 275 } 276 277 printCount() 278 printFds() 279 280 for i := 0; i < 60000; i++ { 281 data = allocateBuffer(pagesize) 282 if err = deallocate(data, pagesize); err != nil { 283 log.Panic(err) 284 } 285 } 286 287 printCount() 288 printFds() 289 printList() 290 } 291 292 func TestVirtualMem(t *testing.T) { 293 vm := NewVirtualMem(os.Getpagesize()) 294 NotNil(t, vm) 295 Equal(t, os.Getpagesize(), vm.Size) 296 297 Equal(t, os.Getpagesize()*2, len(vm.Buf)) 298 299 dataSize := os.Getpagesize() 300 data := make([]byte, dataSize) 301 _, err := rand.Read(data) 302 Nil(t, err) 303 304 for i := range vm.Buf { 305 Zero(t, vm.Buf[i]) 306 } 307 308 for i := 0; i < vm.Size; i++ { 309 vm.Buf[i] = data[i] 310 } 311 312 for i := 0; i < vm.Size; i++ { 313 Equal(t, vm.Buf[i], vm.Buf[i+vm.Size]) 314 } 315 316 vm.Zeroes() 317 318 for i := range vm.Buf { 319 Zero(t, vm.Buf[i]) 320 } 321 322 for i := 0; i < vm.Size; i++ { 323 vm.Buf[i+vm.Size] = data[i] 324 } 325 326 for i := 0; i < vm.Size; i++ { 327 Equal(t, vm.Buf[i], vm.Buf[i+vm.Size]) 328 } 329 330 vm.Zeroes() 331 332 for i := range vm.Buf { 333 Zero(t, vm.Buf[i]) 334 } 335 }