/* * * 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} }