storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/benchmark-utils_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016, 2017 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "bytes" 21 "context" 22 "math" 23 "math/rand" 24 "strconv" 25 "testing" 26 27 humanize "github.com/dustin/go-humanize" 28 ) 29 30 // Benchmark utility functions for ObjectLayer.PutObject(). 31 // Creates Object layer setup ( MakeBucket ) and then runs the PutObject benchmark. 32 func runPutObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) { 33 var err error 34 // obtains random bucket name. 35 bucket := getRandomBucketName() 36 // create bucket. 37 err = obj.MakeBucketWithLocation(context.Background(), bucket, BucketOptions{}) 38 if err != nil { 39 b.Fatal(err) 40 } 41 42 // get text data generated for number of bytes equal to object size. 43 textData := generateBytesData(objSize) 44 // generate md5sum for the generated data. 45 // md5sum of the data to written is required as input for PutObject. 46 47 md5hex := getMD5Hash(textData) 48 sha256hex := "" 49 50 // benchmark utility which helps obtain number of allocations and bytes allocated per ops. 51 b.ReportAllocs() 52 // the actual benchmark for PutObject starts here. Reset the benchmark timer. 53 b.ResetTimer() 54 for i := 0; i < b.N; i++ { 55 // insert the object. 56 objInfo, err := obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), 57 mustGetPutObjReader(b, bytes.NewReader(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) 58 if err != nil { 59 b.Fatal(err) 60 } 61 if objInfo.ETag != md5hex { 62 b.Fatalf("Write no: %d: Md5Sum mismatch during object write into the bucket: Expected %s, got %s", i+1, objInfo.ETag, md5hex) 63 } 64 } 65 // Benchmark ends here. Stop timer. 66 b.StopTimer() 67 } 68 69 // Benchmark utility functions for ObjectLayer.PutObjectPart(). 70 // Creates Object layer setup ( MakeBucket ) and then runs the PutObjectPart benchmark. 71 func runPutObjectPartBenchmark(b *testing.B, obj ObjectLayer, partSize int) { 72 var err error 73 // obtains random bucket name. 74 bucket := getRandomBucketName() 75 object := getRandomObjectName() 76 77 // create bucket. 78 err = obj.MakeBucketWithLocation(context.Background(), bucket, BucketOptions{}) 79 if err != nil { 80 b.Fatal(err) 81 } 82 83 objSize := 128 * humanize.MiByte 84 85 // PutObjectPart returns etag of the object inserted. 86 // etag variable is assigned with that value. 87 var etag, uploadID string 88 // get text data generated for number of bytes equal to object size. 89 textData := generateBytesData(objSize) 90 // generate md5sum for the generated data. 91 // md5sum of the data to written is required as input for NewMultipartUpload. 92 uploadID, err = obj.NewMultipartUpload(context.Background(), bucket, object, ObjectOptions{}) 93 if err != nil { 94 b.Fatal(err) 95 } 96 97 sha256hex := "" 98 99 var textPartData []byte 100 // benchmark utility which helps obtain number of allocations and bytes allocated per ops. 101 b.ReportAllocs() 102 // the actual benchmark for PutObjectPart starts here. Reset the benchmark timer. 103 b.ResetTimer() 104 for i := 0; i < b.N; i++ { 105 // insert the object. 106 totalPartsNR := int(math.Ceil(float64(objSize) / float64(partSize))) 107 for j := 0; j < totalPartsNR; j++ { 108 if j < totalPartsNR-1 { 109 textPartData = textData[j*partSize : (j+1)*partSize-1] 110 } else { 111 textPartData = textData[j*partSize:] 112 } 113 md5hex := getMD5Hash([]byte(textPartData)) 114 var partInfo PartInfo 115 partInfo, err = obj.PutObjectPart(context.Background(), bucket, object, uploadID, j, 116 mustGetPutObjReader(b, bytes.NewReader(textPartData), int64(len(textPartData)), md5hex, sha256hex), ObjectOptions{}) 117 if err != nil { 118 b.Fatal(err) 119 } 120 if partInfo.ETag != md5hex { 121 b.Fatalf("Write no: %d: Md5Sum mismatch during object write into the bucket: Expected %s, got %s", i+1, etag, md5hex) 122 } 123 } 124 } 125 // Benchmark ends here. Stop timer. 126 b.StopTimer() 127 } 128 129 // creates Erasure/FS backend setup, obtains the object layer and calls the runPutObjectPartBenchmark function. 130 func benchmarkPutObjectPart(b *testing.B, instanceType string, objSize int) { 131 // create a temp Erasure/FS backend. 132 ctx, cancel := context.WithCancel(context.Background()) 133 defer cancel() 134 objLayer, disks, err := prepareTestBackend(ctx, instanceType) 135 if err != nil { 136 b.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) 137 } 138 // cleaning up the backend by removing all the directories and files created on function return. 139 defer removeRoots(disks) 140 141 // uses *testing.B and the object Layer to run the benchmark. 142 runPutObjectPartBenchmark(b, objLayer, objSize) 143 } 144 145 // creates Erasure/FS backend setup, obtains the object layer and calls the runPutObjectBenchmark function. 146 func benchmarkPutObject(b *testing.B, instanceType string, objSize int) { 147 // create a temp Erasure/FS backend. 148 ctx, cancel := context.WithCancel(context.Background()) 149 defer cancel() 150 objLayer, disks, err := prepareTestBackend(ctx, instanceType) 151 if err != nil { 152 b.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) 153 } 154 // cleaning up the backend by removing all the directories and files created on function return. 155 defer removeRoots(disks) 156 157 // uses *testing.B and the object Layer to run the benchmark. 158 runPutObjectBenchmark(b, objLayer, objSize) 159 } 160 161 // creates Erasure/FS backend setup, obtains the object layer and runs parallel benchmark for put object. 162 func benchmarkPutObjectParallel(b *testing.B, instanceType string, objSize int) { 163 // create a temp Erasure/FS backend. 164 ctx, cancel := context.WithCancel(context.Background()) 165 defer cancel() 166 objLayer, disks, err := prepareTestBackend(ctx, instanceType) 167 if err != nil { 168 b.Fatalf("Failed obtaining Temp Backend: <ERROR> %s", err) 169 } 170 // cleaning up the backend by removing all the directories and files created on function return. 171 defer removeRoots(disks) 172 173 // uses *testing.B and the object Layer to run the benchmark. 174 runPutObjectBenchmarkParallel(b, objLayer, objSize) 175 } 176 177 // randomly picks a character and returns its equivalent byte array. 178 func getRandomByte() []byte { 179 const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 180 // seeding the random number generator. 181 rand.Seed(UTCNow().UnixNano()) 182 // pick a character randomly. 183 return []byte{letterBytes[rand.Intn(len(letterBytes))]} 184 } 185 186 // picks a random byte and repeats it to size bytes. 187 func generateBytesData(size int) []byte { 188 // repeat the random character chosen size 189 return bytes.Repeat(getRandomByte(), size) 190 } 191 192 // Parallel benchmark utility functions for ObjectLayer.PutObject(). 193 // Creates Object layer setup ( MakeBucket ) and then runs the PutObject benchmark. 194 func runPutObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) { 195 // obtains random bucket name. 196 bucket := getRandomBucketName() 197 // create bucket. 198 err := obj.MakeBucketWithLocation(context.Background(), bucket, BucketOptions{}) 199 if err != nil { 200 b.Fatal(err) 201 } 202 203 // get text data generated for number of bytes equal to object size. 204 textData := generateBytesData(objSize) 205 // generate md5sum for the generated data. 206 // md5sum of the data to written is required as input for PutObject. 207 208 md5hex := getMD5Hash([]byte(textData)) 209 sha256hex := "" 210 211 // benchmark utility which helps obtain number of allocations and bytes allocated per ops. 212 b.ReportAllocs() 213 // the actual benchmark for PutObject starts here. Reset the benchmark timer. 214 b.ResetTimer() 215 216 b.RunParallel(func(pb *testing.PB) { 217 i := 0 218 for pb.Next() { 219 // insert the object. 220 objInfo, err := obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), 221 mustGetPutObjReader(b, bytes.NewReader(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) 222 if err != nil { 223 b.Fatal(err) 224 } 225 if objInfo.ETag != md5hex { 226 b.Fatalf("Write no: Md5Sum mismatch during object write into the bucket: Expected %s, got %s", objInfo.ETag, md5hex) 227 } 228 i++ 229 } 230 }) 231 232 // Benchmark ends here. Stop timer. 233 b.StopTimer() 234 }