github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/memsys/a_test.go (about) 1 // Package memsys provides memory management and Slab allocation 2 // with io.Reader and io.Writer interfaces on top of a scatter-gather lists 3 // (of reusable buffers) 4 /* 5 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 6 */ 7 package memsys_test 8 9 // How to run: 10 // 11 // 1) run each of the tests for 2 minutes in debug mode: 12 // go test -v -duration 2m -tags=debug 13 // 14 // 2) run each test for 10 minutes with the permission to use up to 90% of total RAM 15 // AIS_MINMEM_PCT_TOTAL=10 go test -v -run=No -duration 10m -timeout=1h 16 17 import ( 18 "flag" 19 "fmt" 20 "os" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/NVIDIA/aistore/cmn/cos" 26 "github.com/NVIDIA/aistore/memsys" 27 "github.com/NVIDIA/aistore/tools/tlog" 28 ) 29 30 var ( 31 duration time.Duration // test duration 32 verbose bool 33 ) 34 35 func TestMain(t *testing.M) { 36 var ( 37 d string 38 err error 39 ) 40 flag.StringVar(&d, "duration", "30s", "test duration") 41 flag.BoolVar(&verbose, "verbose", false, "verbose") 42 flag.Parse() 43 44 if duration, err = time.ParseDuration(d); err != nil { 45 cos.Exitf("Invalid duration %q", d) 46 } 47 48 os.Exit(t.Run()) 49 } 50 51 func Test_Sleep(*testing.T) { 52 if testing.Short() { 53 duration = 4 * time.Second 54 } 55 56 mem := &memsys.MMSA{Name: "amem", TimeIval: time.Second * 20, MinFree: cos.GiB} 57 mem.Init(0) 58 59 wg := &sync.WaitGroup{} 60 random := cos.NowRand() 61 for i := range 100 { 62 ttl := time.Duration(random.Int63n(int64(time.Millisecond*100))) + time.Millisecond 63 var siz, tot int64 64 if i%2 == 0 { 65 siz = random.Int63n(cos.MiB*10) + cos.KiB 66 } else { 67 siz = random.Int63n(cos.KiB*100) + cos.KiB 68 } 69 tot = random.Int63n(cos.DivCeil(cos.MiB*50, siz))*siz + cos.KiB 70 wg.Add(1) 71 go memstress(mem, i, ttl, siz, tot, wg) 72 } 73 c := make(chan struct{}, 1) 74 go printMaxRingLen(mem, c) 75 for range 7 { 76 time.Sleep(duration / 8) 77 mem.FreeSpec(memsys.FreeSpec{IdleDuration: 1, MinSize: cos.MiB}) 78 } 79 wg.Wait() 80 close(c) 81 mem.Terminate(false) 82 } 83 84 func Test_NoSleep(*testing.T) { 85 if testing.Short() { 86 duration = 4 * time.Second 87 } 88 89 mem := &memsys.MMSA{Name: "bmem", TimeIval: time.Second * 20, MinPctTotal: 5} 90 mem.Init(0) 91 go printStats(mem) 92 93 wg := &sync.WaitGroup{} 94 random := cos.NowRand() 95 for i := range 500 { 96 siz := random.Int63n(cos.MiB) + cos.KiB 97 tot := random.Int63n(cos.DivCeil(cos.KiB*10, siz))*siz + cos.KiB 98 wg.Add(1) 99 go memstress(mem, i, time.Millisecond, siz, tot, wg) 100 } 101 c := make(chan struct{}, 1) 102 go printMaxRingLen(mem, c) 103 for range 7 { 104 time.Sleep(duration / 8) 105 mem.FreeSpec(memsys.FreeSpec{Totally: true, ToOS: true, MinSize: cos.MiB * 10}) 106 } 107 wg.Wait() 108 close(c) 109 mem.Terminate(false) 110 } 111 112 func printMaxRingLen(mem *memsys.MMSA, c chan struct{}) { 113 for range 100 { 114 select { 115 case <-c: 116 return 117 case <-time.After(5 * time.Second): 118 if p := mem.Pressure(); p > memsys.PressureLow { 119 tlog.Logf("mem-pressure %d\n", p) 120 } 121 } 122 } 123 } 124 125 func memstress(mem *memsys.MMSA, id int, ttl time.Duration, siz, tot int64, wg *sync.WaitGroup) { 126 defer wg.Done() 127 sgls := make([]*memsys.SGL, 0, 128) 128 x := cos.ToSizeIEC(siz, 1) + "/" + cos.ToSizeIEC(tot, 1) 129 if id%100 == 0 && verbose { 130 if ttl > time.Millisecond { 131 tlog.Logf("%4d: %-19s ttl %v\n", id, x, ttl) 132 } else { 133 tlog.Logf("%4d: %-19s\n", id, x) 134 } 135 } 136 started := time.Now() 137 for { 138 t := tot 139 for t > 0 { 140 sgls = append(sgls, mem.NewSGL(siz)) 141 t -= siz 142 } 143 time.Sleep(ttl) 144 for i, sgl := range sgls { 145 sgl.Free() 146 sgls[i] = nil 147 } 148 sgls = sgls[:0] 149 if time.Since(started) > duration { 150 break 151 } 152 } 153 if id%100 == 0 && verbose { 154 tlog.Logf("%4d: done\n", id) 155 } 156 } 157 158 func printStats(mem *memsys.MMSA) { 159 for { 160 time.Sleep(mem.TimeIval) 161 stats := mem.GetStats() 162 for i := range memsys.NumPageSlabs { 163 slab, err := mem.GetSlab(int64(i+1) * memsys.PageSize) 164 cos.AssertNoErr(err) 165 x := "" 166 idle := stats.Idle[i] 167 if idle > 0 { 168 x = fmt.Sprintf(", idle=%v", idle) 169 } 170 fmt.Printf("%s: hits %d%s\n", slab.Tag(), stats.Hits[i], x) 171 } 172 } 173 }