174 lines
5.8 KiB
Go
174 lines
5.8 KiB
Go
/*
|
|
*
|
|
* Copyright 2016, Google Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above
|
|
* copyright notice, this list of conditions and the following disclaimer
|
|
* in the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Google Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
|
|
package main
|
|
|
|
import (
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/benchmark"
|
|
testpb "google.golang.org/grpc/benchmark/grpc_testing"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/grpclog"
|
|
)
|
|
|
|
var (
|
|
// File path related to google.golang.org/grpc.
|
|
certFile = "benchmark/server/testdata/server1.pem"
|
|
keyFile = "benchmark/server/testdata/server1.key"
|
|
)
|
|
|
|
type benchmarkServer struct {
|
|
port int
|
|
cores int
|
|
closeFunc func()
|
|
mu sync.RWMutex
|
|
lastResetTime time.Time
|
|
}
|
|
|
|
func printServerConfig(config *testpb.ServerConfig) {
|
|
// Some config options are ignored:
|
|
// - server type:
|
|
// will always start sync server
|
|
// - async server threads
|
|
// - core list
|
|
grpclog.Printf(" * server type: %v (ignored, always starts sync server)", config.ServerType)
|
|
grpclog.Printf(" * async server threads: %v (ignored)", config.AsyncServerThreads)
|
|
// TODO: use cores specified by CoreList when setting list of cores is supported in go.
|
|
grpclog.Printf(" * core list: %v (ignored)", config.CoreList)
|
|
|
|
grpclog.Printf(" - security params: %v", config.SecurityParams)
|
|
grpclog.Printf(" - core limit: %v", config.CoreLimit)
|
|
grpclog.Printf(" - port: %v", config.Port)
|
|
grpclog.Printf(" - payload config: %v", config.PayloadConfig)
|
|
}
|
|
|
|
func startBenchmarkServer(config *testpb.ServerConfig, serverPort int) (*benchmarkServer, error) {
|
|
printServerConfig(config)
|
|
|
|
// Use all cpu cores available on machine by default.
|
|
// TODO: Revisit this for the optimal default setup.
|
|
numOfCores := runtime.NumCPU()
|
|
if config.CoreLimit > 0 {
|
|
numOfCores = int(config.CoreLimit)
|
|
}
|
|
runtime.GOMAXPROCS(numOfCores)
|
|
|
|
var opts []grpc.ServerOption
|
|
|
|
// Sanity check for server type.
|
|
switch config.ServerType {
|
|
case testpb.ServerType_SYNC_SERVER:
|
|
case testpb.ServerType_ASYNC_SERVER:
|
|
case testpb.ServerType_ASYNC_GENERIC_SERVER:
|
|
default:
|
|
return nil, grpc.Errorf(codes.InvalidArgument, "unknow server type: %v", config.ServerType)
|
|
}
|
|
|
|
// Set security options.
|
|
if config.SecurityParams != nil {
|
|
creds, err := credentials.NewServerTLSFromFile(abs(certFile), abs(keyFile))
|
|
if err != nil {
|
|
grpclog.Fatalf("failed to generate credentials %v", err)
|
|
}
|
|
opts = append(opts, grpc.Creds(creds))
|
|
}
|
|
|
|
// Priority: config.Port > serverPort > default (0).
|
|
port := int(config.Port)
|
|
if port == 0 {
|
|
port = serverPort
|
|
}
|
|
|
|
// Create different benchmark server according to config.
|
|
var (
|
|
addr string
|
|
closeFunc func()
|
|
err error
|
|
)
|
|
if config.PayloadConfig != nil {
|
|
switch payload := config.PayloadConfig.Payload.(type) {
|
|
case *testpb.PayloadConfig_BytebufParams:
|
|
opts = append(opts, grpc.CustomCodec(byteBufCodec{}))
|
|
addr, closeFunc = benchmark.StartServer(benchmark.ServerInfo{
|
|
Addr: ":" + strconv.Itoa(port),
|
|
Type: "bytebuf",
|
|
Metadata: payload.BytebufParams.RespSize,
|
|
}, opts...)
|
|
case *testpb.PayloadConfig_SimpleParams:
|
|
addr, closeFunc = benchmark.StartServer(benchmark.ServerInfo{
|
|
Addr: ":" + strconv.Itoa(port),
|
|
Type: "protobuf",
|
|
}, opts...)
|
|
case *testpb.PayloadConfig_ComplexParams:
|
|
return nil, grpc.Errorf(codes.Unimplemented, "unsupported payload config: %v", config.PayloadConfig)
|
|
default:
|
|
return nil, grpc.Errorf(codes.InvalidArgument, "unknow payload config: %v", config.PayloadConfig)
|
|
}
|
|
} else {
|
|
// Start protobuf server if payload config is nil.
|
|
addr, closeFunc = benchmark.StartServer(benchmark.ServerInfo{
|
|
Addr: ":" + strconv.Itoa(port),
|
|
Type: "protobuf",
|
|
}, opts...)
|
|
}
|
|
|
|
grpclog.Printf("benchmark server listening at %v", addr)
|
|
addrSplitted := strings.Split(addr, ":")
|
|
p, err := strconv.Atoi(addrSplitted[len(addrSplitted)-1])
|
|
if err != nil {
|
|
grpclog.Fatalf("failed to get port number from server address: %v", err)
|
|
}
|
|
|
|
return &benchmarkServer{port: p, cores: numOfCores, closeFunc: closeFunc, lastResetTime: time.Now()}, nil
|
|
}
|
|
|
|
// getStats returns the stats for benchmark server.
|
|
// It resets lastResetTime if argument reset is true.
|
|
func (bs *benchmarkServer) getStats(reset bool) *testpb.ServerStats {
|
|
// TODO wall time, sys time, user time.
|
|
bs.mu.RLock()
|
|
defer bs.mu.RUnlock()
|
|
timeElapsed := time.Since(bs.lastResetTime).Seconds()
|
|
if reset {
|
|
bs.lastResetTime = time.Now()
|
|
}
|
|
return &testpb.ServerStats{TimeElapsed: timeElapsed, TimeUser: 0, TimeSystem: 0}
|
|
}
|