github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/bench/microbenchmarks/nstlvl/nstlvl_test.go (about) 1 // Package nstlvl is intended to measure impact (or lack of thereof) of POSIX directory nesting on random read performance. 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package nstlvl_test 6 7 import ( 8 "flag" 9 "fmt" 10 "io" 11 "math/rand" 12 "os" 13 "os/exec" 14 "runtime" 15 "strconv" 16 "testing" 17 "time" 18 19 "github.com/NVIDIA/aistore/bench/microbenchmarks/nstlvl" 20 "github.com/NVIDIA/aistore/cmn/cos" 21 "github.com/NVIDIA/aistore/tools/trand" 22 ) 23 24 // run with all defaults: 25 // $ go test -v -bench=. 26 // 27 // generate and random-read 300K 4K-size files: 28 // $ go test -v -bench=. -size=4096 -num=300000 29 // 30 // generate 8K files under `/ais/mpath` and run for at least 1m (to increase the number of iterations) 31 // $ go test -v -bench=. -size=8192 -dir=/ais/mpath -benchtime=1m 32 // 33 // print usage and exit: 34 // $ go test -bench=. -usage 35 36 const ( 37 fileNameLen = 15 38 dirs = "/aaaaaa/bbbbbb/cccccc/dddddd/eeeeee/ffffff/gggggg/hhhhhh/iiiiii/jjjjjj" 39 dirNameLen = 6 // NOTE: must reflect the length of dirs' dirs 40 skipModulo = 967 41 ) 42 43 type benchContext struct { 44 // internal 45 rnd *rand.Rand 46 fileNames []string 47 48 // command line 49 level int 50 fileSize int64 51 fileCount int 52 skipMod int 53 dir string 54 help bool 55 } 56 57 var benchCtx benchContext 58 59 func init() { 60 flag.IntVar(&benchCtx.level, "level", 2, "initial (mountpath) nesting level") 61 flag.IntVar(&benchCtx.fileCount, "num", 1000, "number of files to generate (and then randomly read)") 62 flag.Int64Var(&benchCtx.fileSize, "size", cos.KiB, "file/object size") 63 flag.StringVar(&benchCtx.dir, "dir", "/tmp", "top directory for generated files") 64 flag.BoolVar(&benchCtx.help, "usage", false, "show command-line options") 65 } 66 67 func (bctx *benchContext) init() { 68 flag.Parse() 69 if bctx.help { 70 flag.Usage() 71 os.Exit(0) 72 } 73 if bctx.fileCount < 10 { 74 fmt.Printf("Error: number of files (%d) must be greater than 10 (see README for usage)\n", bctx.fileCount) 75 os.Exit(2) 76 } 77 fmt.Printf("files: %d size: %d\n", bctx.fileCount, bctx.fileSize) 78 bctx.fileNames = make([]string, 0, bctx.fileCount) 79 bctx.rnd = cos.NowRand() 80 bctx.skipMod = skipModulo 81 if bctx.fileCount < skipModulo { 82 bctx.skipMod = bctx.fileCount/2 - 1 83 } 84 } 85 86 func BenchmarkNestedLevel(b *testing.B) { 87 benchCtx.init() 88 for _, extraDepth := range []int{0, 2, 4, 6} { 89 nestedLvl := benchCtx.level + extraDepth 90 91 benchCtx.createFiles(nestedLvl) 92 b.Run(strconv.Itoa(nestedLvl), benchNestedLevel) 93 benchCtx.removeFiles() 94 } 95 } 96 97 func benchNestedLevel(b *testing.B) { 98 for i, j, k := 0, 0, 0; i < b.N; i, j = i+1, j+benchCtx.skipMod { 99 if j >= benchCtx.fileCount { 100 k++ 101 if k >= benchCtx.skipMod { 102 k = 0 103 } 104 j = k 105 } 106 fqn := benchCtx.fileNames[j] 107 file, err := os.Open(fqn) 108 cos.AssertNoErr(err) 109 cos.DrainReader(file) 110 cos.Close(file) 111 } 112 } 113 114 func (bctx *benchContext) createFiles(lvl int) { 115 var ( 116 reader = &io.LimitedReader{R: bctx.rnd, N: bctx.fileSize} 117 buf = make([]byte, 32*cos.KiB) 118 ) 119 for range bctx.fileCount { 120 fileName := bctx.dir + dirs[:lvl*(dirNameLen+1)+1] + bctx.randNestName() 121 file, err := cos.CreateFile(fileName) 122 cos.AssertNoErr(err) 123 _, err = io.CopyBuffer(file, reader, buf) 124 cos.AssertNoErr(err) 125 err = file.Close() 126 cos.AssertNoErr(err) 127 128 reader.N = bctx.fileSize 129 bctx.fileNames = append(bctx.fileNames, fileName) 130 } 131 132 cmd := exec.Command("sync") 133 _, err := cmd.Output() 134 cos.AssertNoErr(err) 135 time.Sleep(time.Second) 136 137 nstlvl.DropCaches() 138 runtime.GC() 139 time.Sleep(time.Second) 140 } 141 142 func (bctx *benchContext) removeFiles() { 143 err := os.RemoveAll(bctx.dir + dirs[:dirNameLen+1]) 144 cos.AssertNoErr(err) 145 bctx.fileNames = bctx.fileNames[:0] 146 } 147 148 func (*benchContext) randNestName() string { 149 return trand.String(fileNameLen) 150 }