diff --git a/benchmark-script/2x_performance_test/main.go b/benchmark-script/2x_performance_test/main.go index e8fad7a..eaf94a1 100644 --- a/benchmark-script/2x_performance_test/main.go +++ b/benchmark-script/2x_performance_test/main.go @@ -16,18 +16,20 @@ var ( fSSD = flag.Bool("ssd", false, "Given directory is ssd or not.") fileCount = flag.Int("file-count", 10, "Number of files to read") - FileSize = 512 * OneKB - OneKB = 1024 + fileSize = 512 * oneKB + oneKB = 1024 openLatency []int64 readLatency []int64 closeLatency []int64 totalReadLatency []int64 ) +// ReadFilesSequentially sequentially reads n (fileCount) number of +// files from a directory one by one. func ReadFilesSequentially(fileCount int) (err error) { startTime := time.Now() - b := make([]byte, FileSize*1024) + b := make([]byte, fileSize*1024) for i := 0; i < fileCount; i++ { @@ -75,6 +77,7 @@ func ReadFilesSequentially(fileCount int) (err error) { return } +// Report prints the statistical measurement of the given latencies. func Report(latency []int64, prefix string) { sort.Slice(latency, func(i, j int) bool { return latency[i] < latency[j] diff --git a/benchmark-script/analyse_scale_result/main.go b/benchmark-script/analyse_scale_result/main.go index 3429a5b..566e507 100644 --- a/benchmark-script/analyse_scale_result/main.go +++ b/benchmark-script/analyse_scale_result/main.go @@ -19,6 +19,7 @@ var ( forceDownload = flag.Bool("force-download", false, "Force download or not") ) +// DataRow represents one metrics. type DataRow struct { Timestamp int64 ReadLatency float64 diff --git a/benchmark-script/dynamic_delay_plotter/main.go b/benchmark-script/dynamic_delay_plotter/main.go index 2da7950..c43a09b 100644 --- a/benchmark-script/dynamic_delay_plotter/main.go +++ b/benchmark-script/dynamic_delay_plotter/main.go @@ -64,8 +64,6 @@ func actualSample(p *plot.Plot, dataRows []DataRow, d *util.Delay) { xValues[i] = float64(i) yValues1[i] = d.Value().Seconds() yValues2[i] = actualDelay.Seconds() - - //AddPoints(p, actualDelay.Seconds(), d.Value().Seconds()) } // Add line series for the first curve (sine) @@ -89,24 +87,15 @@ func actualSample(p *plot.Plot, dataRows []DataRow, d *util.Delay) { fmt.Println("Over threshold: ", samplesOverThreshold) } -func AddPoints(p *plot.Plot, x float64, y float64) { - // Create a slice of points (we'll have just one point) - pts := plotter.XYs{{X: x, Y: y}} // Adjust these coordinates as needed - - // Add the points to the plot - scatter, err := plotter.NewScatter(pts) - if err != nil { - panic(err) - } - p.Add(scatter) -} - +// DataRow represents one metrics. type DataRow struct { Timestamp int64 ReadLatency float64 Throughput float64 } +// GetDataRows parses all the CSV file present in a directory and return the +// list of DataRow. func GetDataRows(folder string) ([]DataRow, error) { // Store all data rows from all files var allDataRows []DataRow diff --git a/benchmark-script/pprof_test/main.go b/benchmark-script/pprof_test/main.go index 150f1a0..5f88870 100644 --- a/benchmark-script/pprof_test/main.go +++ b/benchmark-script/pprof_test/main.go @@ -16,7 +16,11 @@ import ( ) const ( + + // KiB means 1024 bytes. KiB = 1024 + + // MiB means 1024 KiB. MiB = 1024 * KiB ) @@ -76,6 +80,7 @@ func profileOnce(path string) (err error) { // // } +// ObjectAccessControlProjectTeam represents a team. type ObjectAccessControlProjectTeam struct { // ProjectNumber: The project number. ProjectNumber string `json:"projectNumber,omitempty"` @@ -100,7 +105,7 @@ type ObjectAccessControlProjectTeam struct { NullFields []string `json:"-"` } -// ObjectAccessControl: An access-control entry. +// ObjectAccessControl is an access-control entry. type ObjectAccessControl struct { // Bucket: The name of the bucket. Bucket string `json:"bucket,omitempty"` @@ -115,7 +120,7 @@ type ObjectAccessControl struct { // forms: // - user-userId // - user-email - // - group-groupId + // - group-groupID // - group-email // - domain-domain // - project-team-projectId @@ -128,8 +133,8 @@ type ObjectAccessControl struct { // example.com, the entity would be domain-example.com. Entity string `json:"entity,omitempty"` - // EntityId: The ID for the entity, if any. - EntityId string `json:"entityId,omitempty"` + // EntityID: The ID for the entity, if any. + EntityID string `json:"entityId,omitempty"` // Etag: HTTP 1.1 Entity tag for the access-control entry. Etag string `json:"etag,omitempty"` @@ -138,8 +143,8 @@ type ObjectAccessControl struct { // object. Generation int64 `json:"generation,omitempty,string"` - // Id: The ID of the access-control entry. - Id string `json:"id,omitempty"` + // ID: The ID of the access-control entry. + ID string `json:"id,omitempty"` // Kind: The kind of item this is. For object access control entries, // this is always storage#objectAccessControl. @@ -177,6 +182,8 @@ type ObjectAccessControl struct { // This may be used to include null fields in Patch requests. NullFields []string `json:"-"` } + +// Test is just a test struct for memory experiment. type Test struct { Name string ContentType string @@ -219,9 +226,10 @@ type Test struct { ContentDisposition string CustomTime string EventBasedHold bool - Acl []ObjectAccessControl + ACL []ObjectAccessControl } +// CloneMap just do deep copy of a map. func CloneMap(m map[string]string) map[string]string { //return &map[string]string{strings.Clone("key1"): strings.Clone("testddddddd"), @@ -234,13 +242,15 @@ func CloneMap(m map[string]string) map[string]string { return newMap } + +// GetObject returns a customized Test object. func GetObject() *Test { return &Test{ Name: strings.Clone("aa"), ContentType: "text/plane", Metadata: map[string]string{strings.Clone("key1"): strings.Clone("testddddddd"), strings.Clone("key2"): strings.Clone("testddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddhffffffffffffff")}, - Acl: []ObjectAccessControl{{}, {}, {}, {}, {}}, + ACL: []ObjectAccessControl{{}, {}, {}, {}, {}}, } } diff --git a/benchmark-script/read_operation/main.go b/benchmark-script/read_operation/main.go index 60fca57..77e94cf 100644 --- a/benchmark-script/read_operation/main.go +++ b/benchmark-script/read_operation/main.go @@ -24,6 +24,7 @@ var ( eG errgroup.Group + // OneKB means 1024 bytes. OneKB = 1024 fNumberOfRead = flag.Int("read-count", 1, "number of read iteration") diff --git a/benchmark-script/read_parallelly/main.go b/benchmark-script/read_parallelly/main.go index 4857910..19bf243 100644 --- a/benchmark-script/read_parallelly/main.go +++ b/benchmark-script/read_parallelly/main.go @@ -10,6 +10,7 @@ import ( const chunkSize = 1024 // Size of the chunk to read +// ReadFile reads a file from a given offset. func ReadFile(startOffset int64, file *os.File) { // Create a buffer to hold the chunk data buffer := make([]byte, chunkSize) @@ -18,13 +19,13 @@ func ReadFile(startOffset int64, file *os.File) { if err != nil && err != io.EOF { fmt.Println("Error reading chunk:", err) return + } + + if err == io.EOF { + fmt.Println("read completed with Error: ", err) } else { - if err == io.EOF { - fmt.Println("read completed with Error: ", err) - } else { - fmt.Println("content: ", string(buffer[:])) - fmt.Println("read completed, successfully with startOffset: ", startOffset) - } + fmt.Println("content: ", string(buffer[:])) + fmt.Println("read completed, successfully with startOffset: ", startOffset) } } diff --git a/benchmark-script/ssd_test/main.go b/benchmark-script/ssd_test/main.go index e0bea7a..16e3660 100644 --- a/benchmark-script/ssd_test/main.go +++ b/benchmark-script/ssd_test/main.go @@ -17,6 +17,7 @@ var ( eG errgroup.Group + // OneKB means 1024 bytes. OneKB = 1024 ) @@ -64,10 +65,6 @@ func runReadFileOperations() (err error) { return } -func MicroSecondsToMilliSecond(microSecond int64) float64 { - return 0.001 * float64(microSecond) -} - func main() { flag.Parse() diff --git a/benchmark-script/write_operations/main.go b/benchmark-script/write_operations/main.go index 7d26247..eb7f8fb 100644 --- a/benchmark-script/write_operations/main.go +++ b/benchmark-script/write_operations/main.go @@ -24,6 +24,7 @@ var ( eG errgroup.Group + // OneKB means 1024 bytes. OneKB = 1024 fFileSize = flag.Int("file-size", 1, "in KB") diff --git a/main.go b/main.go index 2e2b6c7..660a8d7 100644 --- a/main.go +++ b/main.go @@ -31,30 +31,29 @@ import ( ) var ( - GrpcConnPoolSize = 1 - MaxConnsPerHost = 100 - MaxIdleConnsPerHost = 100 + grpcConnPoolSize = 1 + maxConnsPerHost = 100 + maxIdleConnsPerHost = 100 + // MB means 1024 Kb. MB = 1024 * 1024 - NumOfWorker = flag.Int("worker", 48, "Number of concurrent worker to read") + numOfWorker = flag.Int("worker", 48, "Number of concurrent worker to read") - NumOfReadCallPerWorker = flag.Int("read-call-per-worker", 1000000, "Number of read call per worker") + numOfReadCallPerWorker = flag.Int("read-call-per-worker", 1000000, "Number of read call per worker") - MaxRetryDuration = 30 * time.Second + maxRetryDuration = 30 * time.Second - RetryMultiplier = 2.0 + retryMultiplier = 2.0 - BucketName = flag.String("bucket", "princer-working-dirs", "GCS bucket name.") + bucketName = flag.String("bucket", "princer-working-dirs", "GCS bucket name.") + // ProjectName denotes gcp project name. ProjectName = flag.String("project", "gcs-fuse-test", "GCP project name.") - clientProtocol = flag.String("client-protocol", "http", "Network protocol.") - - // ObjectNamePrefixObjectNameSuffix is the object name format. - // Here, worker id goes from <0 to NumberOfWorker>. - ObjectNamePrefix = "princer_100M_files/file_" - ObjectNameSuffix = "" + clientProtocol = flag.String("client-protocol", "http", "Network protocol.") + objectNamePrefix = "princer_100M_files/file_" + objectNameSuffix = "" tracerName = "princer-storage-benchmark" enableTracing = flag.Bool("enable-tracing", false, "Enable tracing with Cloud Trace export") @@ -64,13 +63,14 @@ var ( eG errgroup.Group ) -func CreateHttpClient(ctx context.Context, isHttp2 bool) (client *storage.Client, err error) { +// CreateHTTPClient create http storage client. +func CreateHTTPClient(ctx context.Context, isHTTP2 bool) (client *storage.Client, err error) { var transport *http.Transport // Using http1 makes the client more performant. - if !isHttp2 { + if !isHTTP2 { transport = &http.Transport{ - MaxConnsPerHost: MaxConnsPerHost, - MaxIdleConnsPerHost: MaxIdleConnsPerHost, + MaxConnsPerHost: maxConnsPerHost, + MaxIdleConnsPerHost: maxIdleConnsPerHost, // This disables HTTP/2 in transport. TLSNextProto: make( map[string]func(string, *tls.Conn) http.RoundTripper, @@ -80,7 +80,7 @@ func CreateHttpClient(ctx context.Context, isHttp2 bool) (client *storage.Client // For http2, change in MaxConnsPerHost doesn't affect the performance. transport = &http.Transport{ DisableKeepAlives: true, - MaxConnsPerHost: MaxConnsPerHost, + MaxConnsPerHost: maxConnsPerHost, ForceAttemptHTTP2: true, } } @@ -108,12 +108,13 @@ func CreateHttpClient(ctx context.Context, isHttp2 bool) (client *storage.Client return storage.NewClient(ctx, option.WithHTTPClient(httpClient)) } +// CreateGrpcClient creates grpc client. func CreateGrpcClient(ctx context.Context) (client *storage.Client, err error) { if err := os.Setenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS", "true"); err != nil { log.Fatalf("error setting direct path env var: %v", err) } - client, err = storage.NewGRPCClient(ctx, option.WithGRPCConnectionPool(GrpcConnPoolSize)) + client, err = storage.NewGRPCClient(ctx, option.WithGRPCConnectionPool(grpcConnPoolSize)) if err := os.Unsetenv("GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"); err != nil { log.Fatalf("error while unsetting direct path env var: %v", err) @@ -121,15 +122,16 @@ func CreateGrpcClient(ctx context.Context) (client *storage.Client, err error) { return } -func ReadObject(ctx context.Context, workerId int, bucketHandle *storage.BucketHandle) (err error) { +// ReadObject creates reader object corresponding to workerID with the help of bucketHandle. +func ReadObject(ctx context.Context, workerID int, bucketHandle *storage.BucketHandle) (err error) { - objectName := ObjectNamePrefix + strconv.Itoa(workerId) + ObjectNameSuffix + objectName := objectNamePrefix + strconv.Itoa(workerID) + objectNameSuffix - for i := 0; i < *NumOfReadCallPerWorker; i++ { + for i := 0; i < *numOfReadCallPerWorker; i++ { var span trace.Span traceCtx, span := otel.GetTracerProvider().Tracer(tracerName).Start(ctx, "ReadObject") span.SetAttributes( - attribute.KeyValue{Key: "bucket", Value: attribute.StringValue(*BucketName)}, + attribute.KeyValue{Key: "bucket", Value: attribute.StringValue(*bucketName)}, ) start := time.Now() object := bucketHandle.Object(objectName) @@ -180,7 +182,7 @@ func main() { var client *storage.Client var err error if *clientProtocol == "http" { - client, err = CreateHttpClient(ctx, false) + client, err = CreateHTTPClient(ctx, false) } else { client, err = CreateGrpcClient(ctx) } @@ -192,13 +194,13 @@ func main() { client.SetRetry( storage.WithBackoff(gax.Backoff{ - Max: MaxRetryDuration, - Multiplier: RetryMultiplier, + Max: maxRetryDuration, + Multiplier: retryMultiplier, }), storage.WithPolicy(storage.RetryAlways)) // assumes bucket already exist - bucketHandle := client.Bucket(*BucketName) + bucketHandle := client.Bucket(*bucketName) // Enable stack-driver exporter. registerLatencyView() @@ -211,12 +213,12 @@ func main() { defer closeSDExporter() // Run the actual workload - for i := 0; i < *NumOfWorker; i++ { + for i := 0; i < *numOfWorker; i++ { idx := i eG.Go(func() error { err = ReadObject(ctx, idx, bucketHandle) if err != nil { - err = fmt.Errorf("while reading object %v: %w", ObjectNamePrefix+strconv.Itoa(idx), err) + err = fmt.Errorf("while reading object %v: %w", objectNamePrefix+strconv.Itoa(idx), err) return err } return err diff --git a/util/dynamic_delay.go b/util/dynamic_delay.go index caec5cd..b16bd96 100644 --- a/util/dynamic_delay.go +++ b/util/dynamic_delay.go @@ -6,9 +6,9 @@ import ( "time" ) -// Package dynamicdelay calculates the delay at a fixed percentile, based on +// Dynamic delay calculates the delay at a fixed percentile, based on // delay samples. -// + // Delay is not goroutine-safe. type Delay struct { increaseFactor float64 @@ -64,7 +64,7 @@ func NewDelay(targetPercentile float64, increaseRate float64, initialDelay, minD }, nil } -// increase notes that the RPC took longer than the delay returned by Value. +// Increase notes that the RPC took longer than the delay returned by Value. func (d *Delay) Increase() { v := time.Duration(float64(d.value) * d.increaseFactor) if v > d.maxDelay { @@ -74,7 +74,7 @@ func (d *Delay) Increase() { } } -// decrease notes that the RPC completed before the delay returned by Value. +// Decrease notes that the RPC completed before the delay returned by Value. func (d *Delay) Decrease() { v := time.Duration(float64(d.value) * d.decreaseFactor) if v < d.minDelay { @@ -99,6 +99,7 @@ func (d *Delay) Value() time.Duration { return d.value } +// PrintDelay prints the state of Delay object. func (d *Delay) PrintDelay() { fmt.Println("IncreaseFactor: ", d.increaseFactor) fmt.Println("DecreaseFactor: ", d.decreaseFactor)