mirror of https://github.com/grpc/grpc-go.git
				
				
				
			
		
			
				
	
	
		
			185 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
 *
 | 
						|
 * Copyright 2016 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 main
 | 
						|
 | 
						|
import (
 | 
						|
	"flag"
 | 
						|
	"runtime"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"sync"
 | 
						|
	"syscall"
 | 
						|
	"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"
 | 
						|
	"google.golang.org/grpc/testdata"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	certFile = flag.String("tls_cert_file", "", "The TLS cert file")
 | 
						|
	keyFile  = flag.String("tls_key_file", "", "The TLS key file")
 | 
						|
)
 | 
						|
 | 
						|
type benchmarkServer struct {
 | 
						|
	port            int
 | 
						|
	cores           int
 | 
						|
	closeFunc       func()
 | 
						|
	mu              sync.RWMutex
 | 
						|
	lastResetTime   time.Time
 | 
						|
	rusageLastReset *syscall.Rusage
 | 
						|
}
 | 
						|
 | 
						|
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 {
 | 
						|
		if *certFile == "" {
 | 
						|
			*certFile = testdata.Path("server1.pem")
 | 
						|
		}
 | 
						|
		if *keyFile == "" {
 | 
						|
			*keyFile = testdata.Path("server1.key")
 | 
						|
		}
 | 
						|
		creds, err := credentials.NewServerTLSFromFile(*certFile, *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)
 | 
						|
	}
 | 
						|
 | 
						|
	rusage := new(syscall.Rusage)
 | 
						|
	syscall.Getrusage(syscall.RUSAGE_SELF, rusage)
 | 
						|
 | 
						|
	return &benchmarkServer{
 | 
						|
		port:            p,
 | 
						|
		cores:           numOfCores,
 | 
						|
		closeFunc:       closeFunc,
 | 
						|
		lastResetTime:   time.Now(),
 | 
						|
		rusageLastReset: rusage,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// getStats returns the stats for benchmark server.
 | 
						|
// It resets lastResetTime if argument reset is true.
 | 
						|
func (bs *benchmarkServer) getStats(reset bool) *testpb.ServerStats {
 | 
						|
	bs.mu.RLock()
 | 
						|
	defer bs.mu.RUnlock()
 | 
						|
	wallTimeElapsed := time.Since(bs.lastResetTime).Seconds()
 | 
						|
	rusageLatest := new(syscall.Rusage)
 | 
						|
	syscall.Getrusage(syscall.RUSAGE_SELF, rusageLatest)
 | 
						|
	uTimeElapsed, sTimeElapsed := cpuTimeDiff(bs.rusageLastReset, rusageLatest)
 | 
						|
 | 
						|
	if reset {
 | 
						|
		bs.lastResetTime = time.Now()
 | 
						|
		bs.rusageLastReset = rusageLatest
 | 
						|
	}
 | 
						|
	return &testpb.ServerStats{
 | 
						|
		TimeElapsed: wallTimeElapsed,
 | 
						|
		TimeUser:    uTimeElapsed,
 | 
						|
		TimeSystem:  sTimeElapsed,
 | 
						|
	}
 | 
						|
}
 |