From 8014ecec1bb1eb2f44da1d89af7d646dfa91b3c9 Mon Sep 17 00:00:00 2001 From: Injun Song Date: Sat, 24 Feb 2024 20:45:56 +0900 Subject: [PATCH] perf(benchmark): use grpc.SharedBufferPool for grpc.DialOption When a client library parses incoming gRPC messages, it allocates new buffers frequently. This can result in the creation of a large number of heap objects. However, gRPC offers an experimental feature called the shared buffer pool that can be used to address this issue. This pull request (PR) aims to optimize the gRPC receiving path using the shared buffer pool. Various experiments have shown that this optimization leads to a decrease in CPU time of runtime.gcBgMarkWorkers, depending on the workload. Since the shared buffer pool is experimental, it is applied only to the benchmark. Refs: - https://pkg.go.dev/google.golang.org/grpc@v1.62.0/experimental#WithRecvBufferPool - https://pkg.go.dev/google.golang.org/grpc@v1.62.0#SharedBufferPool --- internal/benchmark/loader.go | 6 +- pkg/varlog/options.go | 8 +++ .../grpc/experimental/experimental.go | 65 +++++++++++++++++++ vendor/modules.txt | 1 + 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 vendor/google.golang.org/grpc/experimental/experimental.go diff --git a/internal/benchmark/loader.go b/internal/benchmark/loader.go index 57356081b..4c242a37b 100644 --- a/internal/benchmark/loader.go +++ b/internal/benchmark/loader.go @@ -13,6 +13,8 @@ import ( "go.uber.org/multierr" "golang.org/x/sync/errgroup" + "google.golang.org/grpc" + "google.golang.org/grpc/experimental" "github.com/kakao/varlog/pkg/types" "github.com/kakao/varlog/pkg/varlog" @@ -54,7 +56,9 @@ func NewLoader(cfg loaderConfig) (loader *Loader, err error) { if scli != nil { return scli, nil } - cli, err := varlog.Open(context.TODO(), loader.cid, loader.mraddrs) + cli, err := varlog.Open(context.TODO(), loader.cid, loader.mraddrs, varlog.WithGRPCDialOptions( + experimental.WithRecvBufferPool(grpc.NewSharedBufferPool()), + )) if err != nil { return nil, err } diff --git a/pkg/varlog/options.go b/pkg/varlog/options.go index eeb29b791..12a10bfe1 100644 --- a/pkg/varlog/options.go +++ b/pkg/varlog/options.go @@ -180,6 +180,14 @@ func WithGRPCInitialWindowSize(bytes int32) Option { }) } +// WithGRPCDialOptions sets the grpc dial options. +// See `google.golang.org/grpc.DialOption`. +func WithGRPCDialOptions(grpcDialOptions ...grpc.DialOption) Option { + return newOption(func(opts *options) { + opts.grpcDialOptions = append(opts.grpcDialOptions, grpcDialOptions...) + }) +} + const ( defaultRetryCount = 3 ) diff --git a/vendor/google.golang.org/grpc/experimental/experimental.go b/vendor/google.golang.org/grpc/experimental/experimental.go new file mode 100644 index 000000000..de7f13a22 --- /dev/null +++ b/vendor/google.golang.org/grpc/experimental/experimental.go @@ -0,0 +1,65 @@ +/* + * + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Package experimental is a collection of experimental features that might +// have some rough edges to them. Housing experimental features in this package +// results in a user accessing these APIs as `experimental.Foo`, thereby making +// it explicit that the feature is experimental and using them in production +// code is at their own risk. +// +// All APIs in this package are experimental. +package experimental + +import ( + "google.golang.org/grpc" + "google.golang.org/grpc/internal" +) + +// WithRecvBufferPool returns a grpc.DialOption that configures the use of +// bufferPool for parsing incoming messages on a grpc.ClientConn. Depending on +// the application's workload, this could result in reduced memory allocation. +// +// If you are unsure about how to implement a memory pool but want to utilize +// one, begin with grpc.NewSharedBufferPool. +// +// Note: The shared buffer pool feature will not be active if any of the +// following options are used: WithStatsHandler, EnableTracing, or binary +// logging. In such cases, the shared buffer pool will be ignored. +// +// Note: It is not recommended to use the shared buffer pool when compression is +// enabled. +func WithRecvBufferPool(bufferPool grpc.SharedBufferPool) grpc.DialOption { + return internal.WithRecvBufferPool.(func(grpc.SharedBufferPool) grpc.DialOption)(bufferPool) +} + +// RecvBufferPool returns a grpc.ServerOption that configures the server to use +// the provided shared buffer pool for parsing incoming messages. Depending on +// the application's workload, this could result in reduced memory allocation. +// +// If you are unsure about how to implement a memory pool but want to utilize +// one, begin with grpc.NewSharedBufferPool. +// +// Note: The shared buffer pool feature will not be active if any of the +// following options are used: StatsHandler, EnableTracing, or binary logging. +// In such cases, the shared buffer pool will be ignored. +// +// Note: It is not recommended to use the shared buffer pool when compression is +// enabled. +func RecvBufferPool(bufferPool grpc.SharedBufferPool) grpc.ServerOption { + return internal.RecvBufferPool.(func(grpc.SharedBufferPool) grpc.ServerOption)(bufferPool) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 294b7b607..8d86cbf7d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -557,6 +557,7 @@ google.golang.org/grpc/credentials/insecure google.golang.org/grpc/encoding google.golang.org/grpc/encoding/gzip google.golang.org/grpc/encoding/proto +google.golang.org/grpc/experimental google.golang.org/grpc/grpclog google.golang.org/grpc/health google.golang.org/grpc/health/grpc_health_v1