├── CREDITS ├── protobuf ├── arpc │ ├── gen_code.sh │ ├── client │ │ ├── main.go │ │ └── arpc_client.go │ └── main.go ├── grpc │ ├── client │ │ ├── main.go │ │ └── grpc_client.go │ └── main.go ├── rpcx │ ├── client │ │ ├── main.go │ │ └── rpcx_client.go │ └── main.go ├── kitex │ ├── client │ │ ├── main.go │ │ └── kitex_client.go │ └── main.go ├── kitex-mux │ ├── client │ │ ├── main.go │ │ └── kitex_client.go │ └── main.go └── arpc-nbio │ ├── client │ ├── main.go │ └── arpc_nbio_client.go │ └── main.go ├── codec ├── thrift │ ├── gen_code.sh │ ├── kitex_gen │ │ └── echo │ │ │ ├── k-consts.go │ │ │ ├── echoserver │ │ │ ├── server.go │ │ │ ├── client.go │ │ │ └── echoserver.go │ │ │ └── streamserver │ │ │ ├── server.go │ │ │ ├── client.go │ │ │ └── streamserver.go │ └── echo.thrift └── protobuf │ ├── pbcodec │ └── protobuf.go │ ├── echo-gogo.proto │ ├── gen_code.sh │ ├── echo-kitex.proto │ ├── echo-grpc.proto │ └── kitex_gen │ └── echo │ ├── echo │ ├── server.go │ ├── client.go │ └── echo.go │ ├── secho │ ├── server.go │ ├── client.go │ └── secho.go │ └── echo-kitex.pb.go ├── docs └── images │ ├── pb_qps.png │ ├── pb_tp99.png │ ├── grpc_qps.png │ ├── grpc_tp99.png │ ├── grpc_tp999.png │ ├── pb_tp999.png │ ├── thrift_qps.png │ ├── thrift_tp99.png │ ├── thrift_tp999.png │ ├── streaming_qps.png │ ├── streaming_tp99.png │ └── streaming_tp999.png ├── scripts ├── kill_servers.sh ├── util.sh ├── reports │ ├── to_table.sh │ ├── grpc.csv │ ├── thrift.csv │ ├── to_csv.sh │ ├── pb.csv │ ├── streaming.csv │ ├── diff.py │ └── render_images.py ├── run_grpc_servers.sh ├── run_thrift_servers.sh ├── run_pb_servers.sh ├── run_grpc_clients.sh ├── run_pb_clients.sh ├── build_thrift.sh ├── build_grpc.sh ├── run_thrift_clients.sh ├── compare_report.sh ├── build_streaming.sh ├── build_pb.sh ├── build_generic.sh ├── benchmark_grpc.sh ├── benchmark_thrift.sh ├── benchmark_pb.sh ├── benchmark_streaming.sh ├── benchmark_generic.sh ├── base.sh └── benchmark_compare.sh ├── .licenserc.yaml ├── .github ├── CODEOWNERS └── workflows │ ├── push-check.yml │ └── codeql-analysis.yml ├── .gitignore ├── grpc ├── grpc │ ├── client │ │ ├── main.go │ │ └── grpc_client.go │ └── main.go └── kitex │ ├── client │ ├── main.go │ └── kitex_client.go │ └── main.go ├── generic ├── http │ ├── client │ │ ├── main.go │ │ └── kitex_client.go │ └── main.go ├── json │ └── client │ │ └── main.go ├── map │ ├── client │ │ ├── main.go │ │ └── kitex_client.go │ └── main.go ├── binary │ ├── client │ │ ├── main.go │ │ └── kitex_client.go │ └── main.go └── ordinary │ ├── client │ ├── main.go │ └── kitex_client.go │ └── main.go ├── perf ├── pprof.go ├── cpu │ ├── cpu_test.go │ └── cpu.go ├── recorder.go └── mem │ └── mem.go ├── runner ├── pool.go ├── processor.go ├── timer.go ├── limiter.go ├── counter.go ├── runner.go └── main.go ├── thrift ├── kitex-mux │ ├── client │ │ └── main.go │ └── main.go ├── kitex │ ├── client │ │ └── main.go │ └── main.go └── client.go ├── streaming ├── grpc │ ├── main.go │ └── client │ │ └── client.go ├── kitex_grpc │ ├── main.go │ └── client │ │ └── client.go ├── kitex_tts_lconn │ ├── main.go │ └── client │ │ └── client.go └── kitex_tts_mux │ ├── main.go │ └── client │ └── client.go └── CONTRIBUTING.md /CREDITS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /protobuf/arpc/gen_code.sh: -------------------------------------------------------------------------------- 1 | protoc --gogofaster_out=. ./pb_gen/echo.proto 2 | -------------------------------------------------------------------------------- /codec/thrift/gen_code.sh: -------------------------------------------------------------------------------- 1 | kitex -streamx -module github.com/cloudwego/kitex-benchmark ./echo.thrift 2 | -------------------------------------------------------------------------------- /docs/images/pb_qps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/pb_qps.png -------------------------------------------------------------------------------- /docs/images/pb_tp99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/pb_tp99.png -------------------------------------------------------------------------------- /docs/images/grpc_qps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/grpc_qps.png -------------------------------------------------------------------------------- /docs/images/grpc_tp99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/grpc_tp99.png -------------------------------------------------------------------------------- /docs/images/grpc_tp999.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/grpc_tp999.png -------------------------------------------------------------------------------- /docs/images/pb_tp999.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/pb_tp999.png -------------------------------------------------------------------------------- /docs/images/thrift_qps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/thrift_qps.png -------------------------------------------------------------------------------- /docs/images/thrift_tp99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/thrift_tp99.png -------------------------------------------------------------------------------- /docs/images/thrift_tp999.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/thrift_tp999.png -------------------------------------------------------------------------------- /docs/images/streaming_qps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/streaming_qps.png -------------------------------------------------------------------------------- /docs/images/streaming_tp99.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/streaming_tp99.png -------------------------------------------------------------------------------- /docs/images/streaming_tp999.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudwego/kitex-benchmark/HEAD/docs/images/streaming_tp999.png -------------------------------------------------------------------------------- /scripts/kill_servers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | pid=$(ps -ef | grep reciever | grep -v grep | awk '{print $2}') 5 | if [ -n "${pid}" ]; then 6 | kill -9 $pid 7 | fi 8 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/k-consts.go: -------------------------------------------------------------------------------- 1 | package echo 2 | 3 | // KitexUnusedProtection is used to prevent 'imported and not used' error. 4 | var KitexUnusedProtection = struct{}{} 5 | -------------------------------------------------------------------------------- /scripts/util.sh: -------------------------------------------------------------------------------- 1 | function check_supported_env() { 2 | case "$OSTYPE" in 3 | linux*) ;; 4 | darwin*) ;; 5 | *) echo "[ERROR] kitex benchmark is not supported on $OSTYPE"; exit 1;; 6 | esac 7 | } -------------------------------------------------------------------------------- /scripts/reports/to_table.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # table 4 | # usage: to_table.sh xxx.log 5 | grep TPS "$1" | awk -F '[ :,]+' '{print " "$2" 传输 "$4" "$6" "$8" "}' 6 | -------------------------------------------------------------------------------- /.licenserc.yaml: -------------------------------------------------------------------------------- 1 | header: 2 | license: 3 | spdx-id: Apache-2.0 4 | copyright-owner: CloudWeGo Authors 5 | 6 | paths: 7 | - '**/*.go' 8 | - '**/*.s' 9 | 10 | paths-ignore: 11 | - '**/codec/**/*.go' 12 | 13 | comment: on-failure 14 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # For more information, please refer to https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners 2 | 3 | * @cloudwego/kitex-reviewers @cloudwego/kitex-approvers @cloudwego/kitex-maintainers 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | .idea/ 17 | *.log 18 | output/ 19 | -------------------------------------------------------------------------------- /codec/protobuf/pbcodec/protobuf.go: -------------------------------------------------------------------------------- 1 | package pbcodec 2 | 3 | import pb "github.com/gogo/protobuf/proto" 4 | 5 | type ProtoBuffer struct{} 6 | 7 | func (c *ProtoBuffer) Marshal(v interface{}) ([]byte, error) { 8 | msg, _ := v.(pb.Message) 9 | return pb.Marshal(msg) 10 | } 11 | 12 | func (c *ProtoBuffer) Unmarshal(data []byte, v interface{}) error { 13 | msg, _ := v.(pb.Message) 14 | return pb.Unmarshal(data, msg) 15 | } 16 | -------------------------------------------------------------------------------- /codec/protobuf/echo-gogo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package protobuf; 3 | option go_package = "gogo"; 4 | 5 | //--------------------request & response-------------- 6 | 7 | message Request { 8 | string Action = 1; 9 | string Msg = 2; 10 | } 11 | 12 | message Response { 13 | string Action = 1; 14 | string Msg = 2; 15 | } 16 | 17 | //----------------------service------------------- 18 | service Echo { 19 | rpc echo (Request) returns (Response) { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /codec/protobuf/gen_code.sh: -------------------------------------------------------------------------------- 1 | # gogo-gen: rpcx, arpc 2 | rm -rf ./gogo_gen && mkdir ./gogo_gen 3 | protoc --gogofaster_out=./gogo_gen ./echo-gogo.proto 4 | 5 | # grpc-gen 6 | rm -rf ./grpc_gen && mkdir ./grpc_gen 7 | protoc --go_out=./grpc_gen --go-grpc_out=./grpc_gen --go_opt=paths=source_relative --go-grpc_opt=paths=source_relative ./echo-grpc.proto 8 | 9 | # kitex-gen 10 | rm -rf ./kitex_gen && mkdir ./kitex_gen 11 | kitex -streamx -type protobuf -module github.com/cloudwego/kitex-benchmark ./echo-kitex.proto 12 | -------------------------------------------------------------------------------- /scripts/reports/grpc.csv: -------------------------------------------------------------------------------- 1 | [GRPC],100,1024,103178.46,3.15,4.67 2 | [KITEX],100,1024,156167.24,1.73,2.11 3 | [GRPC],200,1024,110659.94,6.30,8.86 4 | [KITEX],200,1024,174196.34,2.68,3.28 5 | [GRPC],400,1024,114632.56,12.03,16.61 6 | [KITEX],400,1024,186687.22,4.68,5.83 7 | [GRPC],600,1024,111725.57,18.68,26.03 8 | [KITEX],600,1024,192008.45,6.90,8.75 9 | [GRPC],800,1024,113288.46,24.55,34.31 10 | [KITEX],800,1024,194567.60,9.18,12.14 11 | [GRPC],1000,1024,114054.24,30.59,42.94 12 | [KITEX],1000,1024,193970.54,11.57,15.79 -------------------------------------------------------------------------------- /scripts/reports/thrift.csv: -------------------------------------------------------------------------------- 1 | [KITEX],100,1024,228436.88,0.94,2.01 2 | [KITEX-MUX],100,1024,318029.12,1.04,1.47 3 | [KITEX],200,1024,228792.65,1.77,2.78 4 | [KITEX-MUX],200,1024,371721.91,1.69,2.12 5 | [KITEX],400,1024,231122.07,3.59,4.86 6 | [KITEX-MUX],400,1024,396606.46,2.63,3.31 7 | [KITEX],600,1024,229793.15,5.26,6.91 8 | [KITEX-MUX],600,1024,403082.74,3.57,4.47 9 | [KITEX],800,1024,229684.62,7.16,9.41 10 | [KITEX-MUX],800,1024,408929.84,4.55,5.67 11 | [KITEX],1000,1024,228594.34,9.17,11.78 12 | [KITEX-MUX],1000,1024,410350.53,5.54,7.03 -------------------------------------------------------------------------------- /scripts/run_grpc_servers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("grpc" "kitex") 5 | 6 | # build 7 | source $CURDIR/base.sh 8 | source $CURDIR/build_grpc.sh 9 | 10 | # benchmark 11 | source $CURDIR/kill_servers.sh 12 | core=0 13 | for ((i = 0; i < ${#repo[@]}; i++)); do 14 | rp=${repo[i]} 15 | 16 | # server start 17 | nohup taskset -c $core-$(($core + 3)) $output_dir/bin/${rp}_reciever >> $output_dir/log/nohup.log 2>&1 & 18 | echo "Server [$rp] running at cpu $core-$(($core + 3)) ..." 19 | core=$(($core + 4)) 20 | sleep 1 21 | done 22 | -------------------------------------------------------------------------------- /scripts/run_thrift_servers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("kitex" "kitex-mux") 5 | 6 | # build 7 | source $CURDIR/base.sh 8 | source $CURDIR/build_thrift.sh 9 | 10 | # benchmark 11 | source $CURDIR/kill_servers.sh 12 | core=0 13 | for ((i = 0; i < ${#repo[@]}; i++)); do 14 | rp=${repo[i]} 15 | 16 | # server start 17 | nohup taskset -c $core-$(($core + 3)) $output_dir/bin/${rp}_reciever >> $output_dir/log/nohup.log 2>&1 & 18 | echo "Server [$rp] running at cpu $core-$(($core + 3)) ..." 19 | core=$(($core + 4)) 20 | sleep 1 21 | done 22 | -------------------------------------------------------------------------------- /scripts/run_pb_servers.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("grpc" "kitex" "kitex-mux" "rpcx" "arpc") 5 | 6 | # build 7 | source $CURDIR/base.sh 8 | source $CURDIR/build_pb.sh 9 | 10 | # benchmark 11 | source $CURDIR/kill_servers.sh 12 | core=0 13 | for ((i = 0; i < ${#repo[@]}; i++)); do 14 | rp=${repo[i]} 15 | 16 | # server start 17 | nohup taskset -c $core-$(($core + 3)) $output/bin/${rp}_reciever >> $output/log/nohup.log 2>&1 & 18 | echo "Server [$rp] running at cpu $core-$(($core + 3)) ..." 19 | core=$(($core + 4)) 20 | sleep 1 21 | done 22 | -------------------------------------------------------------------------------- /codec/protobuf/echo-kitex.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package protobuf; 3 | option go_package = "echo"; 4 | 5 | //--------------------request & response-------------- 6 | 7 | message Request { 8 | string Action = 1; 9 | string Msg = 2; 10 | } 11 | 12 | message Response { 13 | string Action = 1; 14 | string Msg = 2; 15 | } 16 | 17 | //----------------------service------------------- 18 | service Echo { 19 | rpc echo (Request) returns (Response) { 20 | } 21 | } 22 | 23 | // === streaming === 24 | //----------------------service------------------- 25 | service SEcho { 26 | // bidirectional 27 | rpc echo (stream Request) returns (stream Response) { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /codec/protobuf/echo-grpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package protobuf; 3 | option go_package = "github.com/cloudwego/kitex-benchmark/common/protobuf"; 4 | 5 | //--------------------request & response-------------- 6 | 7 | message Request { 8 | string Action = 1; 9 | string Msg = 2; 10 | } 11 | 12 | message Response { 13 | string Action = 1; 14 | string Msg = 2; 15 | } 16 | 17 | //----------------------service------------------- 18 | service Echo { 19 | rpc echo (Request) returns (Response) { 20 | } 21 | } 22 | 23 | // === streaming === 24 | //----------------------service------------------- 25 | service SEcho { 26 | // bidirectional 27 | rpc echo (stream Request) returns (stream Response) { 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /scripts/run_grpc_clients.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("grpc" "kitex") 5 | ports=(8000 8006) 6 | ip=${IP:-"127.0.0.1"} 7 | 8 | # build 9 | source $CURDIR/base.sh 10 | source $CURDIR/build_grpc.sh 11 | 12 | # benchmark 13 | for b in ${body[@]}; do 14 | for c in ${concurrent[@]}; do 15 | for q in ${qps[@]}; do 16 | for ((i = 0; i < ${#repo[@]}; i++)); do 17 | rp=${repo[i]} 18 | addr="${ip}:${ports[i]}" 19 | 20 | # run client 21 | echo "Client [$rp] running with [$taskset_client]" 22 | $cmd_client $output_dir/bin/${rp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 23 | done 24 | done 25 | done 26 | done 27 | 28 | finish_cmd 29 | -------------------------------------------------------------------------------- /scripts/run_pb_clients.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("grpc" "kitex" "kitex-mux" "rpcx" "arpc") 5 | ports=(8000 8001 8002 8003 8004) 6 | ip=${IP:-"127.0.0.1"} 7 | 8 | # build 9 | source $CURDIR/base.sh 10 | source $CURDIR/build_pb.sh 11 | 12 | # benchmark 13 | for b in ${body[@]}; do 14 | for c in ${concurrent[@]}; do 15 | for q in ${qps[@]}; do 16 | for ((i = 0; i < ${#repo[@]}; i++)); do 17 | rp=${repo[i]} 18 | addr="${ip}:${ports[i]}" 19 | 20 | # run client 21 | echo "Client [$rp] running with [$taskset_client]" 22 | $cmd_client $output_dir/bin/${rp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 23 | done 24 | done 25 | done 26 | done 27 | 28 | finish_cmd 29 | -------------------------------------------------------------------------------- /scripts/reports/to_csv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # csv 4 | # usage: to_csv.sh xxx.log 5 | output_dir=$(dirname "$1") 6 | # Kind,Concurrency,Data_Size,TPS,AVG,P99,Server_CPU,Client_CPU 7 | grep TPS "$1" | awk '{print $2" "$13" "$11" "$4" "$6" "$8}' | awk '{gsub(/[:c=,(b=ms%]/, "")} 1' > $output_dir/tps.out 8 | grep '@Server' "$1" | grep CPU | awk '{print $14}' | awk '{gsub(/[%:]||AVG/, "")} 1' > $output_dir/server.out 9 | grep '@Client' "$1" | grep CPU | awk '{print $14}' | awk '{gsub(/[%:]||AVG/, "")} 1' > $output_dir/client.out 10 | # combine each line, replace space by comma 11 | awk '{ lines[FNR] = lines[FNR] $0 " " } END { for (i=1; i<=FNR; i++) print lines[i] }' $output_dir/tps.out $output_dir/server.out $output_dir/client.out | awk '{ print substr($0, 1, length($0)-1) }' | awk '{gsub(" ", ",")} 1' 12 | -------------------------------------------------------------------------------- /scripts/build_thrift.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | GOEXEC=${GOEXEC:-"go"} 5 | 6 | # clean 7 | if [ -z "$output_dir" ]; then 8 | echo "output_dir is empty" 9 | exit 1 10 | fi 11 | rm -rf $output_dir/bin/ && mkdir -p $output_dir/bin/ 12 | rm -rf $output_dir/log/ && mkdir -p $output_dir/log/ 13 | 14 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0 15 | $GOEXEC mod tidy 16 | 17 | # build clients 18 | $GOEXEC build -v -o $output_dir/bin/kitex_bencher $thrift_dir/kitex/client 19 | $GOEXEC build -v -o $output_dir/bin/kitex-mux_bencher $thrift_dir/kitex-mux/client 20 | 21 | # build servers 22 | $GOEXEC build -v -o $output_dir/bin/kitex_reciever $thrift_dir/kitex 23 | $GOEXEC build -v -o $output_dir/bin/kitex-mux_reciever $thrift_dir/kitex-mux 24 | -------------------------------------------------------------------------------- /scripts/build_grpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | GOEXEC=${GOEXEC:-"go"} 4 | 5 | # clean 6 | if [ -z "$output_dir" ]; then 7 | echo "output_dir is empty" 8 | exit 1 9 | fi 10 | rm -rf $output_dir/bin/ && mkdir -p $output_dir/bin/ 11 | rm -rf $output_dir/log/ && mkdir -p $output_dir/log/ 12 | 13 | # build kitex 14 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0 15 | $GOEXEC mod tidy 16 | $GOEXEC build -v -o $output_dir/bin/kitex_bencher $grpc_dir/kitex/client 17 | $GOEXEC build -v -o $output_dir/bin/kitex_reciever $grpc_dir/kitex 18 | 19 | # build others 20 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.14.2 21 | $GOEXEC mod tidy 22 | $GOEXEC build -v -o $output_dir/bin/grpc_bencher $grpc_dir/grpc/client 23 | $GOEXEC build -v -o $output_dir/bin/grpc_reciever $grpc_dir/grpc 24 | -------------------------------------------------------------------------------- /grpc/grpc/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GRPC", NewPBGrpcClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/arpc/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("ARPC", NewPBArpcClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/grpc/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GRPC", NewPBGrpcClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/rpcx/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("RPCX", NewPBRpcxClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/kitex/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("KITEX", NewPBKiteXClient) 26 | } 27 | -------------------------------------------------------------------------------- /generic/http/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GenericHTTP", NewGenericHTTPClient) 26 | } 27 | -------------------------------------------------------------------------------- /generic/json/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GenericJSON", NewGenericJSONClient) 26 | } 27 | -------------------------------------------------------------------------------- /generic/map/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GenericMap", NewGenericMapClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/kitex-mux/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("KITEX-MUX", NewPBKiteXClient) 26 | } 27 | -------------------------------------------------------------------------------- /generic/binary/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GenericBinary", NewGenericBinaryClient) 26 | } 27 | -------------------------------------------------------------------------------- /protobuf/arpc-nbio/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("ARPC-NBIO", NewPBArpcNbioClient) 26 | } 27 | -------------------------------------------------------------------------------- /generic/ordinary/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex-benchmark/runner" 21 | ) 22 | 23 | // main is use for routing. 24 | func main() { 25 | runner.Main("GenericOrdinary", NewGenericOrdinaryClient) 26 | } 27 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/echo/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | package echo 3 | 4 | import ( 5 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 6 | server "github.com/cloudwego/kitex/server" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler echo.Echo, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | options = append(options, server.WithCompatibleMiddlewareForUnary()) 15 | 16 | svr := server.NewServer(options...) 17 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | return svr 21 | } 22 | 23 | func RegisterService(svr server.Server, handler echo.Echo, opts ...server.RegisterOption) error { 24 | return svr.RegisterService(serviceInfo(), handler, opts...) 25 | } 26 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/secho/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | package secho 3 | 4 | import ( 5 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 6 | server "github.com/cloudwego/kitex/server" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler echo.SEcho, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | options = append(options, server.WithCompatibleMiddlewareForUnary()) 15 | 16 | svr := server.NewServer(options...) 17 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | return svr 21 | } 22 | 23 | func RegisterService(svr server.Server, handler echo.SEcho, opts ...server.RegisterOption) error { 24 | return svr.RegisterService(serviceInfo(), handler, opts...) 25 | } 26 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/echoserver/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | package echoserver 3 | 4 | import ( 5 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 6 | server "github.com/cloudwego/kitex/server" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler echo.EchoServer, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | options = append(options, server.WithCompatibleMiddlewareForUnary()) 15 | 16 | svr := server.NewServer(options...) 17 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | return svr 21 | } 22 | 23 | func RegisterService(svr server.Server, handler echo.EchoServer, opts ...server.RegisterOption) error { 24 | return svr.RegisterService(serviceInfo(), handler, opts...) 25 | } 26 | -------------------------------------------------------------------------------- /scripts/run_thrift_clients.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | repo=("kitex" "kitex-mux") 5 | ports=(8001 8002) 6 | ip=${IP:-"127.0.0.1"} 7 | 8 | # build 9 | source $CURDIR/base.sh 10 | source $CURDIR/build_thrift.sh 11 | 12 | # benchmark 13 | for b in ${body[@]}; do 14 | for c in ${concurrent[@]}; do 15 | for q in ${qps[@]}; do 16 | for ((i = 0; i < ${#repo[@]}; i++)); do 17 | rp=${repo[i]} 18 | addr="${ip}:${ports[i]}" 19 | 20 | # run client 21 | echo "Client [$rp] running with [$cmd_client]" 22 | $cmd_client $output_dir/bin/${rp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 23 | 24 | echo "client $rp running with $cmd_client" 25 | $cmd_client $output_dir/bin/${rp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 26 | done 27 | done 28 | done 29 | done 30 | 31 | finish_cmd 32 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/streamserver/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | package streamserver 3 | 4 | import ( 5 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 6 | server "github.com/cloudwego/kitex/server" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler echo.StreamServer, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | options = append(options, server.WithCompatibleMiddlewareForUnary()) 15 | 16 | svr := server.NewServer(options...) 17 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | return svr 21 | } 22 | 23 | func RegisterService(svr server.Server, handler echo.StreamServer, opts ...server.RegisterOption) error { 24 | return svr.RegisterService(serviceInfo(), handler, opts...) 25 | } 26 | -------------------------------------------------------------------------------- /scripts/compare_report.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This tool is designed to be used with `scripts/benchmark_compare.sh` which generates reports with 4 | # names like `old-xxx.csv` and `new-xxx.csv` in the `output/mmdd-HHMM-$type` directory. 5 | # Example: 6 | # `bash script/compare_result.sh output/0927-1401-thrift` 7 | 8 | cwd=`pwd` 9 | cd `dirname $0`/.. 10 | PROJECT_ROOT=`pwd` 11 | cd "$cwd" 12 | 13 | dir=${1} 14 | if [ -z "$dir" ];then 15 | echo "Usage: $0 " 16 | echo " directory can be absolute path or relative path" 17 | exit 1 18 | fi 19 | 20 | IFS='|' read -ra keys <<< "$2" 21 | no_title=0 22 | for key in "${keys[@]}"; do 23 | old="$dir/old-$key.csv" 24 | new="$dir/new-$key.csv" 25 | if [ "$no_title" -eq 0 ]; then 26 | python3 "$PROJECT_ROOT/scripts/reports/diff.py" "$old" "$new" "$key" 27 | no_title=1 28 | else 29 | python3 "$PROJECT_ROOT/scripts/reports/diff.py" "$old" "$new" "$key" "True" 30 | fi 31 | done 32 | -------------------------------------------------------------------------------- /.github/workflows/push-check.yml: -------------------------------------------------------------------------------- 1 | name: Push Check 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | 11 | - name: Set up Go 12 | uses: actions/setup-go@v5 13 | with: 14 | go-version: 1.16 15 | 16 | - uses: actions/cache@v3 17 | with: 18 | path: ~/go/pkg/mod 19 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 20 | restore-keys: | 21 | ${{ runner.os }}-go- 22 | 23 | - name: Check License Header 24 | uses: apache/skywalking-eyes/header@v0.4.0 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | 28 | # ignore lint and test since rpcx and kitex is not compatibly. 29 | # - name: Lint 30 | # run: | 31 | # test -z "$(gofmt -s -l .)" 32 | # go vet -stdmethods=false $(go list ./...) 33 | 34 | # - name: Unit Test 35 | # run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./... 36 | -------------------------------------------------------------------------------- /scripts/build_streaming.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | GOEXEC=${GOEXEC:-"go"} 4 | 5 | # clean 6 | rm -rf $output_dir/bin/ && mkdir -p $output_dir/bin/ 7 | rm -rf $output_dir/log/ && mkdir -p $output_dir/log/ 8 | 9 | # build grpc 10 | $GOEXEC mod tidy 11 | $GOEXEC build -v -o $output_dir/bin/grpc_bencher $streaming_dir/grpc/client 12 | $GOEXEC build -v -o $output_dir/bin/grpc_reciever $streaming_dir/grpc 13 | 14 | # build kitex_grpc 15 | $GOEXEC mod tidy 16 | $GOEXEC build -v -o $output_dir/bin/kitex_grpc_bencher $streaming_dir/kitex_grpc/client 17 | $GOEXEC build -v -o $output_dir/bin/kitex_grpc_reciever $streaming_dir/kitex_grpc 18 | 19 | # build kitex_tts_lconn 20 | $GOEXEC mod tidy 21 | $GOEXEC build -v -o $output_dir/bin/kitex_tts_lconn_bencher $streaming_dir/kitex_tts_lconn/client 22 | $GOEXEC build -v -o $output_dir/bin/kitex_tts_lconn_reciever $streaming_dir/kitex_tts_lconn 23 | 24 | # build kitex_tts_mux 25 | $GOEXEC mod tidy 26 | $GOEXEC build -v -o $output_dir/bin/kitex_tts_mux_bencher $streaming_dir/kitex_tts_mux/client 27 | $GOEXEC build -v -o $output_dir/bin/kitex_tts_mux_reciever $streaming_dir/kitex_tts_mux 28 | -------------------------------------------------------------------------------- /perf/pprof.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2021 CloudWeGo Authors 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package perf 18 | 19 | import ( 20 | "net/http" 21 | _ "net/http/pprof" 22 | "os" 23 | "runtime" 24 | "strconv" 25 | ) 26 | 27 | func init() { 28 | mrate, _ := strconv.Atoi(os.Getenv("GOMUTEXRATE")) 29 | brate, _ := strconv.Atoi(os.Getenv("GOBLOCKRATE")) 30 | if mrate > 0 { 31 | runtime.SetMutexProfileFraction(mrate) 32 | } 33 | if brate > 0 { 34 | runtime.SetBlockProfileRate(brate) 35 | } 36 | } 37 | 38 | func ServeMonitor(addr string) error { 39 | return http.ListenAndServe(addr, nil) 40 | } 41 | -------------------------------------------------------------------------------- /perf/cpu/cpu_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package cpu 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "testing" 23 | "time" 24 | ) 25 | 26 | func TestRecordUsage(t *testing.T) { 27 | ctx, finished := context.WithCancel(context.Background()) 28 | go func() { 29 | defer finished() 30 | sum := 0 31 | beginAt := time.Now() 32 | for { 33 | if time.Now().Sub(beginAt) > defaultInterval*5 { 34 | return 35 | } 36 | sum += 1 37 | } 38 | }() 39 | usage, err := RecordUsage(ctx) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | fmt.Println(usage.String()) 44 | } 45 | -------------------------------------------------------------------------------- /scripts/build_pb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | GOEXEC=${GOEXEC:-"go"} 4 | 5 | # clean 6 | if [ -z "$output_dir" ]; then 7 | echo "output_dir is empty" 8 | exit 1 9 | fi 10 | rm -rf $output_dir/bin/ && mkdir -p $output_dir/bin/ 11 | rm -rf $output_dir/log/ && mkdir -p $output_dir/log/ 12 | 13 | # build kitex 14 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0 15 | $GOEXEC mod tidy 16 | $GOEXEC build -v -o $output_dir/bin/kitex_bencher $pb_dir/kitex/client 17 | $GOEXEC build -v -o $output_dir/bin/kitex-mux_bencher $pb_dir/kitex-mux/client 18 | $GOEXEC build -v -o $output_dir/bin/kitex_reciever $pb_dir/kitex 19 | $GOEXEC build -v -o $output_dir/bin/kitex-mux_reciever $pb_dir/kitex-mux 20 | 21 | # build others 22 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.14.2 23 | $GOEXEC mod tidy 24 | $GOEXEC build -v -o $output_dir/bin/grpc_bencher $pb_dir/grpc/client 25 | $GOEXEC build -v -o $output_dir/bin/rpcx_bencher $pb_dir/rpcx/client 26 | $GOEXEC build -v -o $output_dir/bin/arpc_bencher $pb_dir/arpc/client 27 | $GOEXEC build -v -o $output_dir/bin/grpc_reciever $pb_dir/grpc 28 | $GOEXEC build -v -o $output_dir/bin/rpcx_reciever $pb_dir/rpcx 29 | $GOEXEC build -v -o $output_dir/bin/arpc_reciever $pb_dir/arpc 30 | -------------------------------------------------------------------------------- /scripts/reports/pb.csv: -------------------------------------------------------------------------------- 1 | [GRPC],100,1024,103720.78,3.13,4.61 2 | [KITEX],100,1024,204675.33,1.05,2.55 3 | [KITEX-MUX],100,1024,313450.58,1.05,1.47 4 | [RPCX],100,1024,140314.04,2.19,6.43 5 | [ARPC],100,1024,232090.86,1.48,2.34 6 | [GRPC],200,1024,108954.20,6.43,9.08 7 | [KITEX],200,1024,207167.59,1.95,2.97 8 | [KITEX-MUX],200,1024,369757.67,1.68,2.11 9 | [RPCX],200,1024,144220.55,4.33,12.96 10 | [ARPC],200,1024,234917.54,3.19,4.68 11 | [GRPC],400,1024,114187.93,12.06,16.80 12 | [KITEX],400,1024,207899.31,4.07,5.70 13 | [KITEX-MUX],400,1024,395538.21,2.59,3.28 14 | [RPCX],400,1024,147710.95,7.39,18.48 15 | [ARPC],400,1024,239090.05,6.40,8.85 16 | [GRPC],600,1024,111360.22,18.90,26.46 17 | [KITEX],600,1024,208425.18,6.01,7.89 18 | [KITEX-MUX],600,1024,400194.95,3.58,4.51 19 | [RPCX],600,1024,151463.46,10.43,22.01 20 | [ARPC],600,1024,243545.08,9.10,13.22 21 | [GRPC],800,1024,112430.96,24.47,33.70 22 | [KITEX],800,1024,206970.03,8.02,10.53 23 | [KITEX-MUX],800,1024,405509.20,4.53,5.78 24 | [RPCX],800,1024,154754.52,13.89,25.44 25 | [ARPC],800,1024,244427.36,12.21,18.27 26 | [GRPC],1000,1024,113516.96,30.23,41.89 27 | [KITEX],1000,1024,205161.64,10.34,12.88 28 | [KITEX-MUX],1000,1024,407641.77,5.53,7.12 29 | [RPCX],1000,1024,157159.25,17.07,29.18 30 | [ARPC],1000,1024,244999.20,15.25,22.67 -------------------------------------------------------------------------------- /runner/pool.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import "sync/atomic" 20 | 21 | // Pool implements a round-robin balanced object pool 22 | type Pool struct { 23 | clients []interface{} 24 | size uint64 25 | cursor uint64 26 | } 27 | 28 | func NewPool(factory func() interface{}, size int) *Pool { 29 | p := &Pool{ 30 | clients: make([]interface{}, 0, size), 31 | size: uint64(size), 32 | } 33 | for i := 0; i < size; i++ { 34 | p.clients = append(p.clients, factory()) 35 | } 36 | return p 37 | } 38 | 39 | func (p *Pool) Get() interface{} { 40 | return p.clients[atomic.AddUint64(&p.cursor, 1)%p.size] 41 | } 42 | -------------------------------------------------------------------------------- /scripts/build_generic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | GOEXEC=${GOEXEC:-"go"} 5 | 6 | # clean 7 | if [ -z "$output_dir" ]; then 8 | echo "output_dir is empty" 9 | exit 1 10 | fi 11 | rm -rf $output_dir/bin/ && mkdir -p $output_dir/bin/ 12 | rm -rf $output_dir/log/ && mkdir -p $output_dir/log/ 13 | 14 | $GOEXEC mod edit -replace=github.com/apache/thrift=github.com/apache/thrift@v0.13.0 15 | $GOEXEC mod tidy 16 | 17 | # build clients 18 | $GOEXEC build -v -o $output_dir/bin/generic_binary_bencher $generic_dir/binary/client 19 | $GOEXEC build -v -o $output_dir/bin/generic_http_bencher $generic_dir/http/client 20 | $GOEXEC build -v -o $output_dir/bin/generic_map_bencher $generic_dir/map/client 21 | $GOEXEC build -v -o $output_dir/bin/generic_json_bencher $generic_dir/json/client 22 | $GOEXEC build -v -o $output_dir/bin/generic_ordinary_bencher $generic_dir/ordinary/client 23 | 24 | # build servers 25 | $GOEXEC build -v -o $output_dir/bin/generic_binary_reciever $generic_dir/binary 26 | $GOEXEC build -v -o $output_dir/bin/generic_http_reciever $generic_dir/http 27 | $GOEXEC build -v -o $output_dir/bin/generic_map_reciever $generic_dir/map 28 | $GOEXEC build -v -o $output_dir/bin/generic_json_reciever $generic_dir/json 29 | $GOEXEC build -v -o $output_dir/bin/generic_ordinary_reciever $generic_dir/ordinary -------------------------------------------------------------------------------- /scripts/benchmark_grpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | 5 | echo "Checking whether the environment meets the requirements ..." 6 | source $CURDIR/base.sh 7 | echo "Check finished." 8 | 9 | srepo=("grpc" "kitex") 10 | crepo=("grpc" "kitex") 11 | ports=(8000 8006) 12 | 13 | echo "Building grpc services by exec build_grpc.sh..." 14 | source $CURDIR/build_grpc.sh 15 | echo "Build finished." 16 | # benchmark 17 | for b in ${body[@]}; do 18 | for c in ${concurrent[@]}; do 19 | for q in ${qps[@]}; do 20 | for ((i = 0; i < ${#srepo[@]}; i++)); do 21 | srp=${srepo[i]} 22 | crp=${crepo[i]} 23 | addr="127.0.0.1:${ports[i]}" 24 | kill_pid_listening_on_port ${ports[i]} 25 | # server start 26 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail." 27 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 28 | sleep 1 29 | echo "Server [$srp] running with [$cmd_server]" 30 | 31 | # run client 32 | echo "Client [$crp] running with [$cmd_client]" 33 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 34 | 35 | # stop server 36 | kill_pid_listening_on_port ${ports[i]} 37 | done 38 | done 39 | done 40 | done 41 | 42 | finish_cmd 43 | -------------------------------------------------------------------------------- /thrift/kitex-mux/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/cloudwego/kitex/client" 21 | "github.com/cloudwego/kitex/transport" 22 | 23 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 24 | "github.com/cloudwego/kitex-benchmark/runner" 25 | "github.com/cloudwego/kitex-benchmark/thrift" 26 | ) 27 | 28 | // main is use for routing. 29 | func main() { 30 | runner.Main("KITEX-MUX", newThriftKitexClient) 31 | } 32 | 33 | func newThriftKitexClient(opt *runner.Options) runner.Client { 34 | cli := echoserver.MustNewClient("test.echo.kitex", 35 | client.WithTransportProtocol(transport.Framed), 36 | client.WithHostPorts(opt.Address), 37 | client.WithMuxConnection(2)) 38 | return thrift.NewKitexClient(cli) 39 | } 40 | -------------------------------------------------------------------------------- /scripts/benchmark_thrift.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | 5 | echo "Checking whether the environment meets the requirements ..." 6 | source $CURDIR/base.sh 7 | echo "Check finished." 8 | 9 | srepo=("kitex" "kitex-mux") 10 | crepo=("kitex" "kitex-mux") 11 | ports=(8001 8002) 12 | 13 | echo "Building thrift services by exec build_thrift.sh ..." 14 | source $CURDIR/build_thrift.sh 15 | echo "Build finished." 16 | 17 | # benchmark 18 | for b in ${body[@]}; do 19 | for c in ${concurrent[@]}; do 20 | for q in ${qps[@]}; do 21 | for ((i = 0; i < ${#srepo[@]}; i++)); do 22 | srp=${srepo[i]} 23 | crp=${crepo[i]} 24 | addr="127.0.0.1:${ports[i]}" 25 | kill_pid_listening_on_port ${ports[i]} 26 | # server start 27 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail" 28 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 29 | sleep 1 30 | echo "Server [$srp] running with [$cmd_server]" 31 | 32 | # run client 33 | echo "Client [$crp-$method] running with [$cmd_client]" 34 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -method=$method -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 35 | 36 | # stop server 37 | kill_pid_listening_on_port ${ports[i]} 38 | done 39 | done 40 | done 41 | done 42 | 43 | finish_cmd 44 | -------------------------------------------------------------------------------- /scripts/benchmark_pb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | 5 | echo "Checking whether the environment meets the requirements ..." 6 | source $CURDIR/base.sh 7 | echo "Check finished." 8 | 9 | srepo=("grpc" "kitex" "kitex-mux" "rpcx" "arpc") 10 | crepo=("grpc" "kitex" "kitex-mux" "rpcx" "arpc") 11 | ports=(8000 8001 8002 8003 8004) 12 | 13 | echo "Building pb services by exec build_pb.sh..." 14 | source $CURDIR/build_pb.sh 15 | echo "Build finished." 16 | 17 | # benchmark 18 | for b in ${body[@]}; do 19 | for c in ${concurrent[@]}; do 20 | for q in ${qps[@]}; do 21 | for ((i = 0; i < ${#srepo[@]}; i++)); do 22 | srp=${srepo[i]} 23 | crp=${crepo[i]} 24 | addr="127.0.0.1:${ports[i]}" 25 | kill_pid_listening_on_port ${ports[i]} 26 | # server start 27 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail." 28 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 29 | sleep 1 30 | echo "Server [$srp] running with [$cmd_server]" 31 | 32 | # run client 33 | echo "Client [$crp] running with [$cmd_client]" 34 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 35 | 36 | # stop server 37 | kill_pid_listening_on_port ${ports[i]} 38 | done 39 | done 40 | done 41 | done 42 | 43 | finish_cmd 44 | -------------------------------------------------------------------------------- /scripts/reports/streaming.csv: -------------------------------------------------------------------------------- 1 | [GRPC],100,1024,283018.13,0.35,1.15,335.14,433.24 2 | [KITEX_GRPC],100,1024,377035.90,0.27,0.51,296.31,520.15 3 | [KITEX_TTS_LCONN],100,1024,219873.04,0.45,1.44,397.12,507.25 4 | [KITEX_TTS_MUX],100,1024,296940.33,0.34,1.01,373.12,443.90 5 | [GRPC],200,1024,308201.05,0.65,1.69,365.70,457.17 6 | [KITEX_GRPC],200,1024,481652.58,0.42,1.44,347.53,609.75 7 | [KITEX_TTS_LCONN],200,1024,218190.04,0.92,3.80,397.38,511.67 8 | [KITEX_TTS_MUX],200,1024,340073.64,0.59,2.27,379.05,468.00 9 | [GRPC],400,1024,330243.13,1.21,2.69,375.59,475.28 10 | [KITEX_GRPC],400,1024,500970.22,0.80,3.58,354.33,627.51 11 | [KITEX_TTS_LCONN],400,1024,213501.78,1.87,7.13,397.12,505.66 12 | [KITEX_TTS_MUX],400,1024,385933.96,1.04,3.90,382.28,479.44 13 | [GRPC],600,1024,338214.36,1.77,3.78,379.47,482.22 14 | [KITEX_GRPC],600,1024,506057.65,1.19,5.07,354.98,621.06 15 | [KITEX_TTS_LCONN],600,1024,204659.73,2.93,10.47,395.51,496.66 16 | [KITEX_TTS_MUX],600,1024,412654.29,1.45,5.24,385.38,491.43 17 | [GRPC],800,1024,341806.75,2.34,4.95,383.34,486.64 18 | [KITEX_GRPC],800,1024,487937.20,1.64,6.67,354.72,609.95 19 | [KITEX_TTS_LCONN],800,1024,192093.71,4.16,14.06,393.37,481.44 20 | [KITEX_TTS_MUX],800,1024,410191.88,1.95,6.75,386.91,482.48 21 | [GRPC],1000,1024,344077.20,2.91,6.16,385.99,485.91 22 | [KITEX_GRPC],1000,1024,488943.46,2.04,8.12,363.67,612.25 23 | [KITEX_TTS_LCONN],1000,1024,182551.43,5.48,17.81,391.96,473.09 24 | [KITEX_TTS_MUX],1000,1024,400281.65,2.50,8.47,386.74,476.95 -------------------------------------------------------------------------------- /grpc/kitex/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | "runtime/pprof" 23 | 24 | "github.com/cloudwego/kitex-benchmark/runner" 25 | ) 26 | 27 | // main is use for routing. 28 | func main() { 29 | if os.Getenv("KITEX_ENABLE_PROFILE") == "1" { 30 | fmt.Println("[Kitex profile is enabled]") 31 | // start cpu profile 32 | cpuProfile, _ := os.Create("output/benchmark-grpc-client-cpu.pprof") 33 | defer cpuProfile.Close() 34 | _ = pprof.StartCPUProfile(cpuProfile) 35 | defer pprof.StopCPUProfile() 36 | 37 | // heap profile after finish 38 | heapProfile, _ := os.Create("output/benchmark-grpc-client-mem.pprof") 39 | defer func() { 40 | _ = pprof.WriteHeapProfile(heapProfile) 41 | heapProfile.Close() 42 | }() 43 | } 44 | runner.Main("KITEX", NewKClient) 45 | } 46 | -------------------------------------------------------------------------------- /scripts/benchmark_streaming.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # benchmark params 5 | srepo=("grpc" "kitex_grpc" "kitex_tts_lconn" "kitex_tts_mux") 6 | crepo=("grpc" "kitex_grpc" "kitex_tts_lconn" "kitex_tts_mux") 7 | ports=(8000 8001 8002 8003) 8 | 9 | CURDIR=$(cd $(dirname $0); pwd) 10 | echo "Checking whether the environment meets the requirements ..." 11 | source $CURDIR/base.sh 12 | echo "Check finished." 13 | 14 | echo "Building streaming services by exec build_streaming.sh..." 15 | source $CURDIR/build_streaming.sh 16 | echo "Build finished." 17 | # benchmark 18 | for b in ${body[@]}; do 19 | for c in ${concurrent[@]}; do 20 | for q in ${qps[@]}; do 21 | for ((i = 0; i < ${#srepo[@]}; i++)); do 22 | srp=${srepo[i]} 23 | crp=${crepo[i]} 24 | addr="127.0.0.1:${ports[i]}" 25 | kill_pid_listening_on_port ${ports[i]} 26 | # server start 27 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail." 28 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 29 | sleep 1 30 | echo "Server [$srp] running with [$cmd_server]" 31 | 32 | # run client 33 | echo "Client [$crp] running with [$cmd_client]" 34 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 35 | 36 | # stop server 37 | kill_pid_listening_on_port ${ports[i]} 38 | done 39 | done 40 | done 41 | done 42 | 43 | finish_cmd 44 | -------------------------------------------------------------------------------- /scripts/benchmark_generic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | CURDIR=$(cd $(dirname $0); pwd) 4 | 5 | echo "Checking whether the environment meets the requirements ..." 6 | source $CURDIR/base.sh 7 | echo "Check finished." 8 | 9 | srepo=("generic_binary" "generic_http" "generic_json" "generic_map" "generic_ordinary") 10 | crepo=("generic_binary" "generic_http" "generic_json" "generic_map" "generic_ordinary") 11 | ports=(8000 8001 8002 8003 8004) 12 | 13 | echo "Building generic services by exec build_generic.sh ..." 14 | source $CURDIR/build_generic.sh 15 | echo "Build finished." 16 | 17 | # benchmark 18 | for b in ${body[@]}; do 19 | for c in ${concurrent[@]}; do 20 | for q in ${qps[@]}; do 21 | for ((i = 0; i < ${#srepo[@]}; i++)); do 22 | srp=${srepo[i]} 23 | crp=${crepo[i]} 24 | addr="127.0.0.1:${ports[i]}" 25 | kill_pid_listening_on_port ${ports[i]} 26 | # server start 27 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail" 28 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 29 | sleep 1 30 | echo "Server [$srp] running with [$cmd_server]" 31 | 32 | # run client 33 | echo "Client [$crp] running with [$cmd_client]" 34 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t --sleep=$sleep | $tee_cmd 35 | 36 | # stop server 37 | kill_pid_listening_on_port ${ports[i]} 38 | done 39 | done 40 | done 41 | done 42 | 43 | finish_cmd 44 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/echo/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | 3 | package echo 4 | 5 | import ( 6 | "context" 7 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 8 | client "github.com/cloudwego/kitex/client" 9 | callopt "github.com/cloudwego/kitex/client/callopt" 10 | ) 11 | 12 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 13 | type Client interface { 14 | Echo(ctx context.Context, Req *echo.Request, callOptions ...callopt.Option) (r *echo.Response, err error) 15 | } 16 | 17 | // NewClient creates a client for the service defined in IDL. 18 | func NewClient(destService string, opts ...client.Option) (Client, error) { 19 | var options []client.Option 20 | options = append(options, client.WithDestService(destService)) 21 | 22 | options = append(options, opts...) 23 | 24 | kc, err := client.NewClient(serviceInfo(), options...) 25 | if err != nil { 26 | return nil, err 27 | } 28 | return &kEchoClient{ 29 | kClient: newServiceClient(kc), 30 | }, nil 31 | } 32 | 33 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 34 | func MustNewClient(destService string, opts ...client.Option) Client { 35 | kc, err := NewClient(destService, opts...) 36 | if err != nil { 37 | panic(err) 38 | } 39 | return kc 40 | } 41 | 42 | type kEchoClient struct { 43 | *kClient 44 | } 45 | 46 | func (p *kEchoClient) Echo(ctx context.Context, Req *echo.Request, callOptions ...callopt.Option) (r *echo.Response, err error) { 47 | ctx = client.NewCtxWithCallOptions(ctx, callOptions) 48 | return p.kClient.Echo(ctx, Req) 49 | } 50 | -------------------------------------------------------------------------------- /protobuf/rpcx/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | 23 | "github.com/smallnest/rpcx/log" 24 | "github.com/smallnest/rpcx/server" 25 | 26 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 27 | "github.com/cloudwego/kitex-benchmark/perf" 28 | "github.com/cloudwego/kitex-benchmark/runner" 29 | ) 30 | 31 | const ( 32 | port = 8003 33 | ) 34 | 35 | type Echo struct{} 36 | 37 | var recorder = perf.NewRecorder("RPCX@Server") 38 | 39 | func (s *Echo) Echo(ctx context.Context, args *gogo.Request, reply *gogo.Response) error { 40 | action, msg := runner.ProcessRequest(recorder, args.Action, args.Msg) 41 | reply.Action =action 42 | reply.Msg = msg 43 | return nil 44 | } 45 | 46 | func main() { 47 | // start pprof server 48 | go func() { 49 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 50 | }() 51 | 52 | server.UsePool = true 53 | log.SetDummyLogger() 54 | 55 | s := server.NewServer() 56 | s.Register(new(Echo), "") 57 | s.Serve("tcp", fmt.Sprintf(":%d", port)) 58 | } 59 | -------------------------------------------------------------------------------- /codec/thrift/echo.thrift: -------------------------------------------------------------------------------- 1 | namespace go echo 2 | 3 | // Echo Args 4 | 5 | struct Request { 6 | 1: required string action, 7 | 2: required string msg, 8 | } 9 | 10 | struct Response { 11 | 1: required string action, 12 | 2: required string msg, 13 | } 14 | 15 | // EchoComplex Args 16 | 17 | struct SubMessage { 18 | 1: optional i64 id; 19 | 2: optional string value; 20 | } 21 | 22 | struct Message { 23 | 1: optional i64 id; 24 | 2: optional string value; 25 | 3: optional list subMessages; 26 | } 27 | 28 | // 复杂参数 29 | struct ComplexRequest { 30 | 1: required string action(api.path = 'action') 31 | 2: required string msg(api.header = 'msg') 32 | 3: required map msgMap(api.body = 'msgMap') 33 | 4: required list subMsgs(api.body = 'subMsgs') 34 | 5: optional set msgSet(api.body = 'msgSet') 35 | 6: required Message flagMsg(api.body = 'flagMsg') 36 | 7: optional string mockCost, 37 | } 38 | 39 | struct ComplexResponse { 40 | 1: required string action(api.header = 'action') 41 | 2: required string msg(api.header = 'msg') 42 | 3: required map msgMap(api.body = 'msgMap') 43 | 4: required list subMsgs(api.body = 'subMsgs') 44 | 5: optional set msgSet(api.body = 'msgSet') 45 | 6: required Message flagMsg(api.body = 'flagMsg') 46 | } 47 | 48 | service StreamServer { 49 | Response Echo(1: Request req) (streaming.mode="bidirectional"), 50 | } 51 | 52 | service EchoServer { 53 | Response Echo(1: Request req) 54 | ComplexResponse EchoComplex(1: ComplexRequest req)(api.post = '/echo/complex/:action', api.baseurl = 'example.com', api.param = 'true', api.serializer = 'json') 55 | } 56 | -------------------------------------------------------------------------------- /protobuf/arpc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/lesismal/arpc" 21 | "github.com/lesismal/arpc/codec" 22 | "github.com/lesismal/arpc/log" 23 | 24 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 25 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/pbcodec" 26 | "github.com/cloudwego/kitex-benchmark/perf" 27 | "github.com/cloudwego/kitex-benchmark/runner" 28 | ) 29 | 30 | const ( 31 | port = ":8004" 32 | ) 33 | 34 | var recorder = perf.NewRecorder("ARPC@Server") 35 | 36 | func Echo(ctx *arpc.Context) { 37 | args := &gogo.Request{} 38 | if err := ctx.Bind(args); err != nil { 39 | ctx.Error(err) 40 | return 41 | } 42 | 43 | action, msg := runner.ProcessRequest(recorder, args.Action, args.Msg) 44 | reply := &gogo.Response{ 45 | Action: action, 46 | Msg: msg, 47 | } 48 | ctx.Write(reply) 49 | } 50 | 51 | func main() { 52 | log.SetLevel(log.LevelNone) 53 | 54 | codec.DefaultCodec = &pbcodec.ProtoBuffer{} 55 | 56 | svr := arpc.NewServer() 57 | svr.Handler.EnablePool(true) 58 | svr.Handler.SetAsyncResponse(true) 59 | svr.Handler.Handle("Echo", Echo) 60 | 61 | svr.Run(port) 62 | } 63 | -------------------------------------------------------------------------------- /runner/processor.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "fmt" 21 | "strconv" 22 | "strings" 23 | "time" 24 | 25 | "github.com/cloudwego/kitex-benchmark/perf" 26 | ) 27 | 28 | const ( 29 | EchoAction = "echo" 30 | BeginAction = "begin" 31 | EndAction = "end" 32 | SleepAction = "sleep" 33 | ReportAction = "report" 34 | ) 35 | 36 | func ProcessRequest(recorder *perf.Recorder, action, msg string) (retAction, retMsg string) { 37 | switch action { 38 | case BeginAction: 39 | recorder.Begin() 40 | case EndAction: 41 | recorder.End() 42 | // report on server side 43 | recorder.Report() 44 | // send back server report to client 45 | return ReportAction, recorder.ReportString() 46 | case SleepAction: 47 | timeStr := strings.Split(msg, ",")[0] 48 | if n, err := strconv.Atoi(timeStr); err == nil { 49 | ms := time.Millisecond * time.Duration(n) 50 | if ms > 0 { 51 | time.Sleep(ms) 52 | } 53 | } 54 | default: 55 | // do business logic 56 | } 57 | 58 | return action, msg 59 | } 60 | 61 | func ProcessResponse(action, msg string) { 62 | switch action { 63 | case ReportAction: 64 | fmt.Print(msg) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /runner/timer.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "sync" 21 | "sync/atomic" 22 | "time" 23 | ) 24 | 25 | type Timer interface { 26 | Now() int64 27 | } 28 | 29 | // NewTimer returns a Timer. 30 | // window=0 means using the native timer. 31 | func NewTimer(window time.Duration) Timer { 32 | if window == 0 { 33 | return &nativeTimer{} 34 | } 35 | t := &timer{window: window} 36 | t.refresh() 37 | return t 38 | } 39 | 40 | // 全局 Timer, 共享时间周期, 并在到期时执行回调 41 | type timer struct { 42 | sync.Once 43 | now int64 44 | window time.Duration 45 | notify []func(now time.Time) 46 | } 47 | 48 | // refresh time 49 | func (t *timer) refresh() { 50 | t.Do(func() { 51 | atomic.StoreInt64(&t.now, time.Now().UnixNano()) 52 | go func() { 53 | for now := range time.Tick(t.window) { 54 | atomic.StoreInt64(&t.now, now.UnixNano()) 55 | } 56 | }() 57 | }) 58 | } 59 | 60 | func (t *timer) Window() time.Duration { 61 | return t.window 62 | } 63 | 64 | // Timer 为共享计时器, 减少系统时间调用 65 | func (t *timer) Now() int64 { 66 | return atomic.LoadInt64(&t.now) 67 | } 68 | 69 | type nativeTimer struct{} 70 | 71 | func (*nativeTimer) Now() int64 { 72 | return time.Now().UnixNano() 73 | } 74 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/echo-kitex.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | 3 | package echo 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/cloudwego/kitex/pkg/streaming" 9 | "github.com/cloudwego/prutal" 10 | ) 11 | 12 | type Request struct { 13 | Action string `protobuf:"bytes,1,opt,name=Action" json:"Action,omitempty"` 14 | Msg string `protobuf:"bytes,2,opt,name=Msg" json:"Msg,omitempty"` 15 | } 16 | 17 | func (x *Request) Reset() { *x = Request{} } 18 | 19 | func (x *Request) Marshal(in []byte) ([]byte, error) { return prutal.MarshalAppend(in, x) } 20 | 21 | func (x *Request) Unmarshal(in []byte) error { return prutal.Unmarshal(in, x) } 22 | 23 | func (x *Request) GetAction() string { 24 | if x != nil { 25 | return x.Action 26 | } 27 | return "" 28 | } 29 | 30 | func (x *Request) GetMsg() string { 31 | if x != nil { 32 | return x.Msg 33 | } 34 | return "" 35 | } 36 | 37 | type Response struct { 38 | Action string `protobuf:"bytes,1,opt,name=Action" json:"Action,omitempty"` 39 | Msg string `protobuf:"bytes,2,opt,name=Msg" json:"Msg,omitempty"` 40 | } 41 | 42 | func (x *Response) Reset() { *x = Response{} } 43 | 44 | func (x *Response) Marshal(in []byte) ([]byte, error) { return prutal.MarshalAppend(in, x) } 45 | 46 | func (x *Response) Unmarshal(in []byte) error { return prutal.Unmarshal(in, x) } 47 | 48 | func (x *Response) GetAction() string { 49 | if x != nil { 50 | return x.Action 51 | } 52 | return "" 53 | } 54 | 55 | func (x *Response) GetMsg() string { 56 | if x != nil { 57 | return x.Msg 58 | } 59 | return "" 60 | } 61 | 62 | type Echo interface { 63 | Echo(ctx context.Context, req *Request) (res *Response, err error) 64 | } 65 | 66 | type SEcho interface { 67 | Echo(ctx context.Context, stream SEcho_EchoServer) (err error) 68 | } 69 | 70 | type SEcho_EchoServer = streaming.BidiStreamingServer[Request, Response] 71 | -------------------------------------------------------------------------------- /runner/limiter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "sync" 21 | "sync/atomic" 22 | "time" 23 | ) 24 | 25 | // QPS 限制器 26 | type Limiter struct { 27 | sync.Once 28 | qps int64 // 总 qps 29 | now int64 30 | window time.Duration 31 | limit int64 // qps max per window 32 | } 33 | 34 | // 公用全局 Timer reset 减少开销, 但 AddNotify 无法回收, 因此不能频繁创建 Limiter 35 | // must use *Limiter, 否则配置会被复制导致失效 36 | func NewLimiter(maxQps int64, window time.Duration) *Limiter { 37 | limiter := &Limiter{ 38 | window: window, 39 | } 40 | limiter.Reset(maxQps) 41 | limiter.refresh() 42 | return limiter 43 | } 44 | 45 | // has race here but will not appear 46 | func (l *Limiter) Reset(maxQps int64) { 47 | l.limit = maxQps / int64(time.Second/window) 48 | l.reset() 49 | } 50 | 51 | // true 代表 超过上限, maxQps <= 0表示没有上限 52 | func (l *Limiter) QpsOverrun() bool { 53 | if l.limit <= 0 { 54 | return false 55 | } 56 | if cur := atomic.AddInt64(&l.qps, 1); cur > l.limit { 57 | return true 58 | } 59 | return false 60 | } 61 | 62 | func (l *Limiter) reset() { 63 | atomic.StoreInt64(&l.qps, 0) 64 | } 65 | 66 | func (l *Limiter) refresh() { 67 | l.Do(func() { 68 | go func() { 69 | for range time.Tick(l.window) { 70 | l.reset() 71 | } 72 | }() 73 | }) 74 | } 75 | -------------------------------------------------------------------------------- /protobuf/grpc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "google.golang.org/grpc" 26 | 27 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 28 | "github.com/cloudwego/kitex-benchmark/perf" 29 | "github.com/cloudwego/kitex-benchmark/runner" 30 | ) 31 | 32 | const ( 33 | port = 8000 34 | ) 35 | 36 | var recorder = perf.NewRecorder("GRPC@Server") 37 | 38 | type server struct { 39 | grpcg.UnimplementedEchoServer 40 | } 41 | 42 | func (s *server) Echo(ctx context.Context, req *grpcg.Request) (*grpcg.Response, error) { 43 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 44 | return &grpcg.Response{ 45 | Action: action, 46 | Msg: msg, 47 | }, nil 48 | } 49 | 50 | func main() { 51 | // start pprof server 52 | go func() { 53 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 54 | }() 55 | 56 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 57 | if err != nil { 58 | log.Fatalf("failed to listen: %v", err) 59 | } 60 | s := grpc.NewServer() 61 | grpcg.RegisterEchoServer(s, &server{}) 62 | log.Printf("server listening at %v", lis.Addr()) 63 | 64 | if err := s.Serve(lis); err != nil { 65 | log.Fatalf("failed to serve: %v", err) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /grpc/grpc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "google.golang.org/grpc" 26 | 27 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 28 | "github.com/cloudwego/kitex-benchmark/perf" 29 | "github.com/cloudwego/kitex-benchmark/runner" 30 | ) 31 | 32 | const ( 33 | port = 8000 34 | ) 35 | 36 | var recorder = perf.NewRecorder("GRPC@Server") 37 | 38 | type server struct { 39 | grpcg.UnimplementedEchoServer 40 | } 41 | 42 | func (s *server) Echo(ctx context.Context, req *grpcg.Request) (*grpcg.Response, error) { 43 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 44 | 45 | return &grpcg.Response{ 46 | Action: action, 47 | Msg: msg, 48 | }, nil 49 | } 50 | 51 | func main() { 52 | // start pprof server 53 | go func() { 54 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 55 | }() 56 | 57 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 58 | if err != nil { 59 | log.Fatalf("failed to listen: %v", err) 60 | } 61 | s := grpc.NewServer() 62 | grpcg.RegisterEchoServer(s, &server{}) 63 | log.Printf("server listening at %v", lis.Addr()) 64 | 65 | if err := s.Serve(lis); err != nil { 66 | log.Fatalf("failed to serve: %v", err) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/secho/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | 3 | package secho 4 | 5 | import ( 6 | "context" 7 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 8 | client "github.com/cloudwego/kitex/client" 9 | streamcall "github.com/cloudwego/kitex/client/callopt/streamcall" 10 | streaming "github.com/cloudwego/kitex/pkg/streaming" 11 | transport "github.com/cloudwego/kitex/transport" 12 | ) 13 | 14 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 15 | type Client interface { 16 | Echo(ctx context.Context, callOptions ...streamcall.Option) (stream SEcho_echoClient, err error) 17 | } 18 | 19 | type SEcho_echoClient streaming.BidiStreamingClient[echo.Request, echo.Response] 20 | 21 | // NewClient creates a client for the service defined in IDL. 22 | func NewClient(destService string, opts ...client.Option) (Client, error) { 23 | var options []client.Option 24 | options = append(options, client.WithDestService(destService)) 25 | 26 | options = append(options, client.WithTransportProtocol(transport.GRPC)) 27 | 28 | options = append(options, opts...) 29 | 30 | kc, err := client.NewClient(serviceInfo(), options...) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return &kSEchoClient{ 35 | kClient: newServiceClient(kc), 36 | }, nil 37 | } 38 | 39 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 40 | func MustNewClient(destService string, opts ...client.Option) Client { 41 | kc, err := NewClient(destService, opts...) 42 | if err != nil { 43 | panic(err) 44 | } 45 | return kc 46 | } 47 | 48 | type kSEchoClient struct { 49 | *kClient 50 | } 51 | 52 | func (p *kSEchoClient) Echo(ctx context.Context, callOptions ...streamcall.Option) (stream SEcho_echoClient, err error) { 53 | ctx = client.NewCtxWithCallOptions(ctx, streamcall.GetCallOptions(callOptions)) 54 | return p.kClient.Echo(ctx) 55 | } 56 | -------------------------------------------------------------------------------- /protobuf/kitex-mux/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | 23 | "github.com/cloudwego/kitex/client" 24 | 25 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 26 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 27 | "github.com/cloudwego/kitex-benchmark/runner" 28 | ) 29 | 30 | func NewPBKiteXClient(opt *runner.Options) runner.Client { 31 | cli := &pbKitexClient{} 32 | cli.client = echosvr.MustNewClient("test.echo.kitex-mux", 33 | client.WithHostPorts(opt.Address), 34 | // client.WithMuxConnection(opt.PoolSize)) 35 | // netpoll 设计上,2 个 connection 最优 36 | client.WithMuxConnection(2)) 37 | cli.reqPool = &sync.Pool{ 38 | New: func() interface{} { 39 | return &echo.Request{} 40 | }, 41 | } 42 | return cli 43 | } 44 | 45 | type pbKitexClient struct { 46 | client echosvr.Client 47 | reqPool *sync.Pool 48 | } 49 | 50 | func (cli *pbKitexClient) Send(method, action, msg string) error { 51 | ctx := context.Background() 52 | req := cli.reqPool.Get().(*echo.Request) 53 | defer cli.reqPool.Put(req) 54 | 55 | req.Msg = msg 56 | req.Action = action 57 | 58 | reply, err := cli.client.Echo(ctx, req) 59 | if reply != nil { 60 | runner.ProcessResponse(reply.Action, reply.Msg) 61 | } 62 | return err 63 | } 64 | -------------------------------------------------------------------------------- /protobuf/kitex/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/server" 26 | 27 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 28 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 29 | "github.com/cloudwego/kitex-benchmark/perf" 30 | "github.com/cloudwego/kitex-benchmark/runner" 31 | ) 32 | 33 | const ( 34 | port = 8001 35 | ) 36 | 37 | var recorder = perf.NewRecorder("KITEX@Server") 38 | 39 | // EchoImpl implements the last service interface defined in the IDL. 40 | type EchoImpl struct{} 41 | 42 | // Echo implements the EchoImpl interface. 43 | func (s *EchoImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 44 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 45 | return &echo.Response{ 46 | Action: action, 47 | Msg: msg, 48 | }, nil 49 | } 50 | 51 | func main() { 52 | // start pprof server 53 | go func() { 54 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 55 | }() 56 | 57 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 58 | svr := echosvr.NewServer(new(EchoImpl), server.WithServiceAddr(address)) 59 | 60 | err := svr.Run() 61 | if err != nil { 62 | log.Println(err.Error()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/streamserver/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | 3 | package streamserver 4 | 5 | import ( 6 | "context" 7 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 8 | client "github.com/cloudwego/kitex/client" 9 | streamcall "github.com/cloudwego/kitex/client/callopt/streamcall" 10 | streaming "github.com/cloudwego/kitex/pkg/streaming" 11 | transport "github.com/cloudwego/kitex/transport" 12 | ) 13 | 14 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 15 | type Client interface { 16 | Echo(ctx context.Context, callOptions ...streamcall.Option) (stream StreamServer_EchoClient, err error) 17 | } 18 | 19 | type StreamServer_EchoClient streaming.BidiStreamingClient[echo.Request, echo.Response] 20 | 21 | // NewClient creates a client for the service defined in IDL. 22 | func NewClient(destService string, opts ...client.Option) (Client, error) { 23 | var options []client.Option 24 | options = append(options, client.WithDestService(destService)) 25 | 26 | options = append(options, client.WithTransportProtocol(transport.TTHeaderStreaming)) 27 | 28 | options = append(options, opts...) 29 | 30 | kc, err := client.NewClient(serviceInfo(), options...) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return &kStreamServerClient{ 35 | kClient: newServiceClient(kc), 36 | }, nil 37 | } 38 | 39 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 40 | func MustNewClient(destService string, opts ...client.Option) Client { 41 | kc, err := NewClient(destService, opts...) 42 | if err != nil { 43 | panic(err) 44 | } 45 | return kc 46 | } 47 | 48 | type kStreamServerClient struct { 49 | *kClient 50 | } 51 | 52 | func (p *kStreamServerClient) Echo(ctx context.Context, callOptions ...streamcall.Option) (stream StreamServer_EchoClient, err error) { 53 | ctx = client.NewCtxWithCallOptions(ctx, streamcall.GetCallOptions(callOptions)) 54 | return p.kClient.Echo(ctx) 55 | } 56 | -------------------------------------------------------------------------------- /protobuf/kitex-mux/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/server" 26 | 27 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 28 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 29 | "github.com/cloudwego/kitex-benchmark/perf" 30 | "github.com/cloudwego/kitex-benchmark/runner" 31 | ) 32 | 33 | const ( 34 | port = 8002 35 | ) 36 | 37 | var recorder = perf.NewRecorder("KITEX-MUX@Server") 38 | 39 | // EchoImpl implements the last service interface defined in the IDL. 40 | type EchoImpl struct{} 41 | 42 | // Echo implements the EchoImpl interface. 43 | func (s *EchoImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 44 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 45 | return &echo.Response{ 46 | Action: action, 47 | Msg: msg, 48 | }, nil 49 | } 50 | 51 | func main() { 52 | // start pprof server 53 | go func() { 54 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 55 | }() 56 | 57 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 58 | svr := echosvr.NewServer( 59 | new(EchoImpl), 60 | server.WithServiceAddr(address), 61 | server.WithMuxTransport(), 62 | ) 63 | 64 | err := svr.Run() 65 | if err != nil { 66 | log.Println(err.Error()) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /protobuf/kitex/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | "time" 23 | 24 | "github.com/cloudwego/kitex/client" 25 | "github.com/cloudwego/kitex/pkg/connpool" 26 | 27 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 28 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 29 | "github.com/cloudwego/kitex-benchmark/runner" 30 | ) 31 | 32 | func NewPBKiteXClient(opt *runner.Options) runner.Client { 33 | cli := &pbKitexClient{} 34 | cli.client = echosvr.MustNewClient("test.echo.kitex", 35 | client.WithHostPorts(opt.Address), 36 | client.WithLongConnection( 37 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 38 | ) 39 | cli.reqPool = &sync.Pool{ 40 | New: func() interface{} { 41 | return &echo.Request{} 42 | }, 43 | } 44 | return cli 45 | } 46 | 47 | type pbKitexClient struct { 48 | client echosvr.Client 49 | reqPool *sync.Pool 50 | } 51 | 52 | func (cli *pbKitexClient) Send(method, action, msg string) error { 53 | ctx := context.Background() 54 | req := cli.reqPool.Get().(*echo.Request) 55 | defer cli.reqPool.Put(req) 56 | 57 | req.Action = action 58 | req.Msg = msg 59 | 60 | reply, err := cli.client.Echo(ctx, req) 61 | if reply != nil { 62 | runner.ProcessResponse(reply.Action, reply.Msg) 63 | } 64 | return err 65 | } 66 | -------------------------------------------------------------------------------- /grpc/kitex/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | 23 | "github.com/cloudwego/kitex/client" 24 | "github.com/cloudwego/kitex/pkg/klog" 25 | "github.com/cloudwego/kitex/transport" 26 | 27 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 28 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 29 | "github.com/cloudwego/kitex-benchmark/runner" 30 | ) 31 | 32 | func NewKClient(opt *runner.Options) runner.Client { 33 | klog.SetLevel(klog.LevelWarn) 34 | return &kClient{ 35 | client: echosvr.MustNewClient("test.echo.kitex", 36 | client.WithHostPorts(opt.Address), 37 | client.WithTransportProtocol(transport.GRPC), 38 | client.WithGRPCConnPoolSize(6), // the cpu cores of server is 4, and 4*3/2 = 6 39 | ), 40 | reqPool: &sync.Pool{ 41 | New: func() interface{} { 42 | return &echo.Request{} 43 | }, 44 | }, 45 | } 46 | } 47 | 48 | type kClient struct { 49 | client echosvr.Client 50 | reqPool *sync.Pool 51 | } 52 | 53 | func (cli *kClient) Send(method, action, msg string) error { 54 | ctx := context.Background() 55 | req := cli.reqPool.Get().(*echo.Request) 56 | defer cli.reqPool.Put(req) 57 | 58 | req.Action = action 59 | req.Msg = msg 60 | 61 | reply, err := cli.client.Echo(ctx, req) 62 | if reply != nil { 63 | runner.ProcessResponse(reply.Action, reply.Msg) 64 | } 65 | return err 66 | } 67 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/echoserver/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | 3 | package echoserver 4 | 5 | import ( 6 | "context" 7 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 8 | client "github.com/cloudwego/kitex/client" 9 | callopt "github.com/cloudwego/kitex/client/callopt" 10 | ) 11 | 12 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 13 | type Client interface { 14 | Echo(ctx context.Context, req *echo.Request, callOptions ...callopt.Option) (r *echo.Response, err error) 15 | EchoComplex(ctx context.Context, req *echo.ComplexRequest, callOptions ...callopt.Option) (r *echo.ComplexResponse, err error) 16 | } 17 | 18 | // NewClient creates a client for the service defined in IDL. 19 | func NewClient(destService string, opts ...client.Option) (Client, error) { 20 | var options []client.Option 21 | options = append(options, client.WithDestService(destService)) 22 | 23 | options = append(options, opts...) 24 | 25 | kc, err := client.NewClient(serviceInfo(), options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return &kEchoServerClient{ 30 | kClient: newServiceClient(kc), 31 | }, nil 32 | } 33 | 34 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 35 | func MustNewClient(destService string, opts ...client.Option) Client { 36 | kc, err := NewClient(destService, opts...) 37 | if err != nil { 38 | panic(err) 39 | } 40 | return kc 41 | } 42 | 43 | type kEchoServerClient struct { 44 | *kClient 45 | } 46 | 47 | func (p *kEchoServerClient) Echo(ctx context.Context, req *echo.Request, callOptions ...callopt.Option) (r *echo.Response, err error) { 48 | ctx = client.NewCtxWithCallOptions(ctx, callOptions) 49 | return p.kClient.Echo(ctx, req) 50 | } 51 | 52 | func (p *kEchoServerClient) EchoComplex(ctx context.Context, req *echo.ComplexRequest, callOptions ...callopt.Option) (r *echo.ComplexResponse, err error) { 53 | ctx = client.NewCtxWithCallOptions(ctx, callOptions) 54 | return p.kClient.EchoComplex(ctx, req) 55 | } 56 | -------------------------------------------------------------------------------- /grpc/grpc/client/grpc_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "log" 22 | "sync" 23 | "time" 24 | 25 | "google.golang.org/grpc" 26 | 27 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 28 | "github.com/cloudwego/kitex-benchmark/runner" 29 | ) 30 | 31 | func NewPBGrpcClient(opt *runner.Options) runner.Client { 32 | cli := &pbGrpcClient{} 33 | cli.reqPool = &sync.Pool{ 34 | New: func() interface{} { 35 | return &grpcg.Request{} 36 | }, 37 | } 38 | cli.connpool = runner.NewPool(func() interface{} { 39 | // Set up a connection to the server. 40 | conn, err := grpc.Dial(opt.Address, grpc.WithInsecure()) 41 | if err != nil { 42 | log.Fatalf("did not connect: %v", err) 43 | } 44 | return grpcg.NewEchoClient(conn) 45 | }, opt.PoolSize) 46 | return cli 47 | } 48 | 49 | type pbGrpcClient struct { 50 | reqPool *sync.Pool 51 | connpool *runner.Pool 52 | } 53 | 54 | func (cli *pbGrpcClient) Send(method, action, msg string) error { 55 | ctx := context.Background() 56 | req := cli.reqPool.Get().(*grpcg.Request) 57 | defer cli.reqPool.Put(req) 58 | 59 | req.Action = action 60 | req.Msg = msg 61 | 62 | pbcli := cli.connpool.Get().(grpcg.EchoClient) 63 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 64 | defer cancel() 65 | reply, err := pbcli.Echo(ctx, req) 66 | 67 | if reply != nil { 68 | runner.ProcessResponse(reply.Action, reply.Msg) 69 | } 70 | return err 71 | } 72 | -------------------------------------------------------------------------------- /protobuf/grpc/client/grpc_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "log" 22 | "sync" 23 | "time" 24 | 25 | "google.golang.org/grpc" 26 | 27 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 28 | "github.com/cloudwego/kitex-benchmark/runner" 29 | ) 30 | 31 | func NewPBGrpcClient(opt *runner.Options) runner.Client { 32 | cli := &pbGrpcClient{} 33 | cli.reqPool = &sync.Pool{ 34 | New: func() interface{} { 35 | return &grpcg.Request{} 36 | }, 37 | } 38 | cli.connpool = runner.NewPool(func() interface{} { 39 | // Set up a connection to the server. 40 | conn, err := grpc.Dial(opt.Address, grpc.WithInsecure()) 41 | if err != nil { 42 | log.Fatalf("did not connect: %v", err) 43 | } 44 | return grpcg.NewEchoClient(conn) 45 | }, opt.PoolSize) 46 | return cli 47 | } 48 | 49 | type pbGrpcClient struct { 50 | reqPool *sync.Pool 51 | connpool *runner.Pool 52 | } 53 | 54 | func (cli *pbGrpcClient) Send(method, action, msg string) error { 55 | ctx := context.Background() 56 | req := cli.reqPool.Get().(*grpcg.Request) 57 | defer cli.reqPool.Put(req) 58 | 59 | req.Action = action 60 | req.Msg = msg 61 | 62 | pbcli := cli.connpool.Get().(grpcg.EchoClient) 63 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 64 | defer cancel() 65 | reply, err := pbcli.Echo(ctx, req) 66 | 67 | if reply != nil { 68 | runner.ProcessResponse(reply.Action, reply.Msg) 69 | } 70 | return err 71 | } 72 | -------------------------------------------------------------------------------- /thrift/kitex/client/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "os" 22 | "runtime/pprof" 23 | "time" 24 | 25 | "github.com/cloudwego/kitex/client" 26 | "github.com/cloudwego/kitex/pkg/connpool" 27 | "github.com/cloudwego/kitex/transport" 28 | 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 30 | "github.com/cloudwego/kitex-benchmark/runner" 31 | "github.com/cloudwego/kitex-benchmark/thrift" 32 | ) 33 | 34 | // main is use for routing. 35 | func main() { 36 | if os.Getenv("KITEX_ENABLE_PROFILE") == "1" { 37 | fmt.Println("[Kitex profile is enabled]") 38 | // start cpu profile 39 | cpuProfile, _ := os.Create("output/benchmark-thrift-client-cpu.pprof") 40 | defer cpuProfile.Close() 41 | _ = pprof.StartCPUProfile(cpuProfile) 42 | defer pprof.StopCPUProfile() 43 | 44 | // heap profile after finish 45 | heapProfile, _ := os.Create("output/benchmark-thrift-client-mem.pprof") 46 | defer func() { 47 | _ = pprof.WriteHeapProfile(heapProfile) 48 | heapProfile.Close() 49 | }() 50 | } 51 | runner.Main("KITEX", NewThriftKitexClient) 52 | } 53 | 54 | func NewThriftKitexClient(opt *runner.Options) runner.Client { 55 | cli := echoserver.MustNewClient("test.echo.kitex", 56 | client.WithTransportProtocol(transport.Framed), 57 | client.WithHostPorts(opt.Address), 58 | client.WithLongConnection( 59 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 60 | ) 61 | return thrift.NewKitexClient(cli) 62 | } 63 | -------------------------------------------------------------------------------- /perf/recorder.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2021 CloudWeGo Authors 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | package perf 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "sync" 24 | 25 | "github.com/cloudwego/kitex-benchmark/perf/cpu" 26 | "github.com/cloudwego/kitex-benchmark/perf/mem" 27 | ) 28 | 29 | type Recorder struct { 30 | name string 31 | finish func() 32 | waiter sync.WaitGroup 33 | CpuUsage cpu.Usage 34 | MemUsage mem.Usage 35 | } 36 | 37 | func NewRecorder(name string) *Recorder { 38 | return &Recorder{ 39 | name: name, 40 | } 41 | } 42 | 43 | func (r *Recorder) Begin() { 44 | r.Reset() 45 | 46 | ctx, finish := context.WithCancel(context.Background()) 47 | r.finish = finish 48 | r.waiter.Add(2) 49 | go func() { 50 | defer r.waiter.Done() 51 | var err error 52 | r.CpuUsage, err = cpu.RecordUsage(ctx) 53 | if err != nil { 54 | log.Fatalf("recording cpu usage failed: %v", err) 55 | } 56 | }() 57 | go func() { 58 | defer r.waiter.Done() 59 | var err error 60 | r.MemUsage, err = mem.RecordUsage(ctx) 61 | if err != nil { 62 | log.Fatalf("recording mem usage failed: %v", err) 63 | } 64 | }() 65 | } 66 | 67 | func (r *Recorder) End() { 68 | r.finish() 69 | r.waiter.Wait() 70 | } 71 | 72 | func (r *Recorder) Reset() { 73 | r.finish = nil 74 | r.waiter = sync.WaitGroup{} 75 | r.CpuUsage = cpu.Usage{} 76 | r.MemUsage = mem.Usage{} 77 | } 78 | 79 | func (r *Recorder) ReportString() string { 80 | output := "" 81 | output += fmt.Sprintf("[%s] CPU Usage: %s\n", r.name, r.CpuUsage) 82 | output += fmt.Sprintf("[%s] Mem Usage: %s\n", r.name, r.MemUsage) 83 | return output 84 | } 85 | 86 | func (r *Recorder) Report() { 87 | fmt.Print(r.ReportString()) 88 | } 89 | -------------------------------------------------------------------------------- /protobuf/rpcx/client/rpcx_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | "time" 23 | 24 | "github.com/smallnest/rpcx/client" 25 | "github.com/smallnest/rpcx/protocol" 26 | 27 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 28 | "github.com/cloudwego/kitex-benchmark/runner" 29 | ) 30 | 31 | func NewPBRpcxClient(opt *runner.Options) runner.Client { 32 | cli := &pbRpcxClient{} 33 | cli.msg = string(opt.Body) 34 | cli.reqPool = &sync.Pool{ 35 | New: func() interface{} { 36 | return &gogo.Request{} 37 | }, 38 | } 39 | cli.respPool = &sync.Pool{ 40 | New: func() interface{} { 41 | return &gogo.Response{} 42 | }, 43 | } 44 | 45 | option := client.DefaultOption 46 | option.SerializeType = protocol.ProtoBuffer 47 | d, _ := client.NewPeer2PeerDiscovery("tcp@"+opt.Address, "") 48 | cli.clipool = client.NewXClientPool(opt.PoolSize, "Echo", client.Failtry, client.RandomSelect, d, option) 49 | return cli 50 | } 51 | 52 | type pbRpcxClient struct { 53 | msg string 54 | reqPool *sync.Pool 55 | respPool *sync.Pool 56 | clipool *client.XClientPool 57 | } 58 | 59 | func (cli *pbRpcxClient) Send(method, action, msg string) (err error) { 60 | args := cli.reqPool.Get().(*gogo.Request) 61 | reply := cli.respPool.Get().(*gogo.Response) 62 | defer cli.reqPool.Put(args) 63 | defer cli.respPool.Put(reply) 64 | 65 | args.Action = action 66 | args.Msg = msg 67 | 68 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 69 | defer cancel() 70 | 71 | xclient := cli.clipool.Get() 72 | err = xclient.Call(ctx, "Echo", args, reply) 73 | 74 | runner.ProcessResponse(reply.Action, reply.Msg) 75 | return err 76 | } 77 | -------------------------------------------------------------------------------- /perf/mem/mem.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package mem 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | "time" 24 | 25 | sigar "github.com/cloudfoundry/gosigar" 26 | ) 27 | 28 | const ( 29 | defaultInterval = time.Second * 3 30 | defaultRssThreshold = 1024 * 1024 // bytes 31 | ) 32 | 33 | type Usage struct { 34 | MaxRss uint64 35 | AvgRss uint64 36 | } 37 | 38 | func (u Usage) String() string { 39 | return fmt.Sprintf("AVG: %d MB, MAX: %d MB", u.AvgRss/1024/1024, u.MaxRss/1024/1024) 40 | } 41 | 42 | // RecordUsage return the final Usage when context canceled 43 | func RecordUsage(ctx context.Context) (usage Usage, err error) { 44 | pid := os.Getpid() 45 | return RecordUsageWithPid(ctx, pid) 46 | } 47 | 48 | // RecordUsageWithPid return the final Usage when context canceled 49 | func RecordUsageWithPid(ctx context.Context, pid int) (usage Usage, err error) { 50 | if _, err = os.FindProcess(pid); err != nil { 51 | return 52 | } 53 | var procMem = sigar.ProcMem{} 54 | var rssList []uint64 55 | var ticker = time.NewTicker(defaultInterval) 56 | defer ticker.Stop() 57 | for { 58 | if err = procMem.Get(pid); err != nil { 59 | return 60 | } 61 | rss := procMem.Resident 62 | if rss > defaultRssThreshold { 63 | rssList = append(rssList, rss) 64 | } 65 | 66 | select { 67 | case <-ctx.Done(): 68 | return calcUsage(rssList), nil 69 | case <-ticker.C: 70 | } 71 | } 72 | } 73 | 74 | func calcUsage(rssList []uint64) Usage { 75 | var totalRss, maxRss uint64 76 | for _, rss := range rssList { 77 | totalRss += rss 78 | if rss > maxRss { 79 | maxRss = rss 80 | } 81 | } 82 | return Usage{ 83 | MaxRss: maxRss, 84 | AvgRss: totalRss / uint64(len(rssList)), 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /streaming/grpc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | "log" 23 | "net" 24 | 25 | "google.golang.org/grpc" 26 | "google.golang.org/grpc/metadata" 27 | 28 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 29 | "github.com/cloudwego/kitex-benchmark/perf" 30 | "github.com/cloudwego/kitex-benchmark/runner" 31 | ) 32 | 33 | const ( 34 | port = 8000 35 | ) 36 | 37 | var recorder = perf.NewRecorder("GRPC@Server") 38 | 39 | type server struct { 40 | grpcg.UnimplementedSEchoServer 41 | } 42 | 43 | func (s *server) Echo(stream grpcg.SEcho_EchoServer) error { 44 | md, _ := metadata.FromIncomingContext(stream.Context()) 45 | if md == nil || len(md["header"]) == 0 || md["header"][0] != "hello" { 46 | return fmt.Errorf("invalid header: %v", md) 47 | } 48 | 49 | for { 50 | req, err := stream.Recv() 51 | if err != nil { 52 | if err == io.EOF { 53 | return nil 54 | } 55 | return err 56 | } 57 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 58 | err = stream.Send(&grpcg.Response{ 59 | Action: action, 60 | Msg: msg, 61 | }) 62 | if err != nil { 63 | log.Printf("stream send failed: %v\n", err) 64 | return err 65 | } 66 | } 67 | } 68 | 69 | func main() { 70 | // start pprof server 71 | go func() { 72 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 73 | }() 74 | 75 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 76 | if err != nil { 77 | log.Fatalf("failed to listen: %v", err) 78 | } 79 | s := grpc.NewServer() 80 | grpcg.RegisterSEchoServer(s, &server{}) 81 | log.Printf("server listening at %v", lis.Addr()) 82 | 83 | if err := s.Serve(lis); err != nil { 84 | log.Fatalf("failed to serve: %v", err) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /thrift/kitex-mux/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/server" 26 | 27 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 28 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 29 | "github.com/cloudwego/kitex-benchmark/perf" 30 | "github.com/cloudwego/kitex-benchmark/runner" 31 | ) 32 | 33 | const ( 34 | port = 8002 35 | ) 36 | 37 | // EchoServerImpl implements the last service interface defined in the IDL. 38 | type EchoServerImpl struct{} 39 | 40 | var recorder = perf.NewRecorder("KITEX-MUX@Server") 41 | 42 | func (s *EchoServerImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 43 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 44 | return &echo.Response{ 45 | Action: action, 46 | Msg: msg, 47 | }, nil 48 | } 49 | 50 | func (s *EchoServerImpl) EchoComplex(ctx context.Context, req *echo.ComplexRequest) (*echo.ComplexResponse, error) { 51 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 52 | return &echo.ComplexResponse{ 53 | Action: action, 54 | Msg: msg, 55 | MsgMap: req.MsgMap, 56 | SubMsgs: req.SubMsgs, 57 | MsgSet: req.MsgSet, 58 | FlagMsg: req.FlagMsg, 59 | }, nil 60 | } 61 | 62 | func main() { 63 | // start pprof server 64 | go func() { 65 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 66 | }() 67 | 68 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 69 | svr := echoserver.NewServer(new(EchoServerImpl), 70 | server.WithServiceAddr(address), 71 | server.WithMuxTransport()) 72 | 73 | err := svr.Run() 74 | if err != nil { 75 | log.Println(err.Error()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /streaming/kitex_grpc/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/metadata" 26 | "github.com/cloudwego/kitex/server" 27 | 28 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 29 | sechosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/secho" 30 | "github.com/cloudwego/kitex-benchmark/perf" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | const port = 8001 35 | 36 | var ( 37 | _ echo.SEcho = &EchoImpl{} 38 | 39 | recorder = perf.NewRecorder("KITEX_GRPC@Server") 40 | ) 41 | 42 | // EchoImpl implements the last service interface defined in the IDL. 43 | type EchoImpl struct{} 44 | 45 | // Echo implements the EchoImpl interface. 46 | func (s *EchoImpl) Echo(ctx context.Context, stream echo.SEcho_EchoServer) error { 47 | md, _ := metadata.FromIncomingContext(ctx) 48 | if md == nil || len(md["header"]) == 0 || md["header"][0] != "hello" { 49 | return fmt.Errorf("invalid header: %v", md) 50 | } 51 | 52 | for { 53 | req, err := stream.Recv(ctx) 54 | if err != nil { 55 | return err 56 | } 57 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 58 | 59 | err = stream.Send(ctx, &echo.Response{ 60 | Action: action, 61 | Msg: msg, 62 | }) 63 | if err != nil { 64 | return err 65 | } 66 | } 67 | } 68 | 69 | func main() { 70 | // start pprof server 71 | go func() { 72 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 73 | }() 74 | svr := sechosvr.NewServer( 75 | new(EchoImpl), 76 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4zero, Port: port}), 77 | ) 78 | 79 | if err := svr.Run(); err != nil { 80 | log.Println(err.Error()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /streaming/kitex_tts_lconn/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "io" 23 | "log" 24 | "net" 25 | 26 | "github.com/bytedance/gopkg/cloud/metainfo" 27 | "github.com/cloudwego/kitex/pkg/klog" 28 | "github.com/cloudwego/kitex/server" 29 | 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 31 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/streamserver" 32 | "github.com/cloudwego/kitex-benchmark/perf" 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | const port = 8002 37 | 38 | var ( 39 | _ echo.StreamServer = &StreamServerImpl{} 40 | recorder = perf.NewRecorder("KITEX_TTS_LCONN@Server") 41 | ) 42 | 43 | type StreamServerImpl struct{} 44 | 45 | func (si *StreamServerImpl) Echo(ctx context.Context, stream echo.StreamServer_EchoServer) error { 46 | v, _ := metainfo.GetValue(ctx, "header") 47 | if v != "hello" { 48 | return fmt.Errorf("invalid header: %v", v) 49 | } 50 | 51 | for { 52 | req, err := stream.Recv(ctx) 53 | if err == io.EOF { 54 | return nil 55 | } 56 | if err != nil { 57 | return err 58 | } 59 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 60 | 61 | resp := new(echo.Response) 62 | resp.Action = action 63 | resp.Msg = msg 64 | err = stream.Send(ctx, resp) 65 | if err != nil { 66 | return err 67 | } 68 | } 69 | } 70 | 71 | func main() { 72 | klog.SetLevel(klog.LevelWarn) 73 | // start pprof server 74 | go func() { 75 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 76 | }() 77 | 78 | svr := streamserver.NewServer( 79 | new(StreamServerImpl), 80 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4zero, Port: port}), 81 | ) 82 | if err := svr.Run(); err != nil { 83 | log.Println(err.Error()) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /streaming/kitex_tts_mux/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "io" 23 | "log" 24 | "net" 25 | 26 | "github.com/bytedance/gopkg/cloud/metainfo" 27 | "github.com/cloudwego/kitex/pkg/klog" 28 | "github.com/cloudwego/kitex/server" 29 | 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 31 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/streamserver" 32 | "github.com/cloudwego/kitex-benchmark/perf" 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | const port = 8003 37 | 38 | var ( 39 | _ echo.StreamServer = &StreamServerImpl{} 40 | recorder = perf.NewRecorder("KITEX_TTS_MUX@Server") 41 | ) 42 | 43 | type StreamServerImpl struct{} 44 | 45 | func (si *StreamServerImpl) Echo(ctx context.Context, stream echo.StreamServer_EchoServer) error { 46 | v, _ := metainfo.GetValue(ctx, "header") 47 | if v != "hello" { 48 | return fmt.Errorf("invalid header: %v", v) 49 | } 50 | 51 | for { 52 | req, err := stream.Recv(ctx) 53 | if err == io.EOF { 54 | return nil 55 | } 56 | if err != nil { 57 | return err 58 | } 59 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 60 | 61 | resp := new(echo.Response) 62 | resp.Action = action 63 | resp.Msg = msg 64 | err = stream.Send(ctx, resp) 65 | if err != nil { 66 | return err 67 | } 68 | } 69 | } 70 | 71 | func main() { 72 | klog.SetLevel(klog.LevelWarn) 73 | // start pprof server 74 | go func() { 75 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 76 | }() 77 | 78 | svr := streamserver.NewServer( 79 | new(StreamServerImpl), 80 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4zero, Port: port}), 81 | ) 82 | if err := svr.Run(); err != nil { 83 | log.Println(err.Error()) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /generic/ordinary/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/pkg/transmeta" 26 | "github.com/cloudwego/kitex/server" 27 | 28 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 30 | "github.com/cloudwego/kitex-benchmark/perf" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | const ( 35 | port = 8004 36 | ) 37 | 38 | var recorder = perf.NewRecorder("GenericOrdinary@Server") 39 | 40 | // EchoServerImpl implements the last service interface defined in the IDL. 41 | type EchoServerImpl struct{} 42 | 43 | // Echo implements the EchoServerImpl interface. 44 | func (s *EchoServerImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 45 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 46 | return &echo.Response{ 47 | Action: action, 48 | Msg: msg, 49 | }, nil 50 | } 51 | 52 | func (s *EchoServerImpl) EchoComplex(ctx context.Context, req *echo.ComplexRequest) (*echo.ComplexResponse, error) { 53 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 54 | return &echo.ComplexResponse{ 55 | Action: action, 56 | Msg: msg, 57 | MsgMap: req.MsgMap, 58 | SubMsgs: req.SubMsgs, 59 | MsgSet: req.MsgSet, 60 | FlagMsg: req.FlagMsg, 61 | }, nil 62 | } 63 | 64 | func main() { 65 | // start pprof server 66 | go func() { 67 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 68 | }() 69 | 70 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 71 | svr := echoserver.NewServer(new(EchoServerImpl), server.WithServiceAddr(address), server.WithMetaHandler(transmeta.ServerTTHeaderHandler)) 72 | 73 | err := svr.Run() 74 | if err != nil { 75 | log.Println(err.Error()) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /protobuf/arpc-nbio/client/arpc_nbio_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "net" 22 | "sync" 23 | "time" 24 | 25 | "github.com/lesismal/arpc" 26 | "github.com/lesismal/arpc/codec" 27 | "github.com/lesismal/arpc/log" 28 | 29 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 30 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/pbcodec" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | func NewPBArpcNbioClient(opt *runner.Options) runner.Client { 35 | log.SetLevel(log.LevelNone) 36 | 37 | cli := &pbArpcClient{} 38 | cli.msg = string(opt.Body) 39 | cli.reqPool = &sync.Pool{ 40 | New: func() interface{} { 41 | return &gogo.Request{} 42 | }, 43 | } 44 | cli.respPool = &sync.Pool{ 45 | New: func() interface{} { 46 | return &gogo.Response{} 47 | }, 48 | } 49 | 50 | codec.DefaultCodec = &pbcodec.ProtoBuffer{} 51 | pool, err := arpc.NewClientPool(func() (net.Conn, error) { 52 | return net.DialTimeout("tcp", opt.Address, time.Second*5) 53 | }, opt.PoolSize) 54 | if err != nil { 55 | panic(err) 56 | } 57 | 58 | cli.clipool = pool 59 | 60 | return cli 61 | } 62 | 63 | type pbArpcClient struct { 64 | msg string 65 | reqPool *sync.Pool 66 | respPool *sync.Pool 67 | clipool *arpc.ClientPool 68 | } 69 | 70 | func (cli *pbArpcClient) Send(method, action, msg string) (err error) { 71 | args := cli.reqPool.Get().(*gogo.Request) 72 | reply := cli.respPool.Get().(*gogo.Response) 73 | defer cli.reqPool.Put(args) 74 | defer cli.respPool.Put(reply) 75 | 76 | args.Action = action 77 | args.Msg = msg 78 | 79 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 80 | defer cancel() 81 | 82 | client := cli.clipool.Next() 83 | err = client.CallWith(ctx, "Echo", args, reply) 84 | 85 | runner.ProcessResponse(reply.Action, reply.Msg) 86 | return err 87 | } 88 | -------------------------------------------------------------------------------- /streaming/grpc/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "log" 23 | "sync" 24 | 25 | "google.golang.org/grpc" 26 | "google.golang.org/grpc/metadata" 27 | 28 | grpcg "github.com/cloudwego/kitex-benchmark/codec/protobuf/grpc_gen" 29 | "github.com/cloudwego/kitex-benchmark/runner" 30 | ) 31 | 32 | func NewGrpcClient(opt *runner.Options) runner.Client { 33 | conn, err := grpc.Dial(opt.Address, grpc.WithInsecure()) 34 | if err != nil { 35 | log.Fatalf("did not connect: %v", err) 36 | } 37 | client := grpcg.NewSEchoClient(conn) 38 | return &grpcClient{ 39 | client: client, 40 | streampool: &sync.Pool{New: func() interface{} { 41 | ctx := metadata.AppendToOutgoingContext(context.Background(), "header", "hello") 42 | stream, err := client.Echo(ctx) 43 | if err != nil { 44 | log.Printf("client new stream failed: %v", err) 45 | return nil 46 | } 47 | return stream 48 | }}, 49 | reqPool: &sync.Pool{ 50 | New: func() interface{} { 51 | return &grpcg.Request{} 52 | }, 53 | }, 54 | } 55 | } 56 | 57 | type grpcClient struct { 58 | client grpcg.SEchoClient 59 | streampool *sync.Pool 60 | reqPool *sync.Pool 61 | } 62 | 63 | func (cli *grpcClient) Send(method, action, msg string) (err error) { 64 | req := cli.reqPool.Get().(*grpcg.Request) 65 | defer cli.reqPool.Put(req) 66 | 67 | stream, ok := cli.streampool.Get().(grpcg.SEcho_EchoClient) 68 | if !ok { 69 | return errors.New("new stream error") 70 | } 71 | defer cli.streampool.Put(stream) 72 | req.Action = action 73 | req.Msg = msg 74 | if err := stream.Send(req); err != nil { 75 | return err 76 | } 77 | resp, err := stream.Recv() 78 | if err != nil { 79 | return err 80 | } 81 | runner.ProcessResponse(resp.Action, resp.Msg) 82 | return nil 83 | } 84 | 85 | func main() { 86 | runner.Main("GRPC", NewGrpcClient) 87 | } 88 | -------------------------------------------------------------------------------- /generic/http/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/pkg/transmeta" 26 | "github.com/cloudwego/kitex/server" 27 | 28 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 30 | "github.com/cloudwego/kitex-benchmark/perf" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | const ( 35 | port = 8001 36 | ) 37 | 38 | var recorder = perf.NewRecorder("GenericHTTP@Server") 39 | 40 | // EchoServerImpl implements the last service interface defined in the IDL. 41 | type EchoServerImpl struct{} 42 | 43 | // Echo implements the EchoServerImpl interface. 44 | func (s *EchoServerImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 45 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 46 | 47 | return &echo.Response{ 48 | Action: action, 49 | Msg: msg, 50 | }, nil 51 | } 52 | 53 | func (s *EchoServerImpl) EchoComplex(ctx context.Context, req *echo.ComplexRequest) (*echo.ComplexResponse, error) { 54 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 55 | 56 | return &echo.ComplexResponse{ 57 | Action: action, 58 | Msg: msg, 59 | MsgMap: req.MsgMap, 60 | SubMsgs: req.SubMsgs, 61 | MsgSet: req.MsgSet, 62 | FlagMsg: req.FlagMsg, 63 | }, nil 64 | } 65 | 66 | func main() { 67 | // start pprof server 68 | go func() { 69 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 70 | }() 71 | 72 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 73 | svr := echoserver.NewServer(new(EchoServerImpl), server.WithServiceAddr(address), server.WithMetaHandler(transmeta.ServerTTHeaderHandler)) 74 | 75 | err := svr.Run() 76 | if err != nil { 77 | log.Println(err.Error()) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /protobuf/arpc/client/arpc_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "net" 22 | "sync" 23 | "time" 24 | 25 | "github.com/lesismal/arpc" 26 | "github.com/lesismal/arpc/codec" 27 | "github.com/lesismal/arpc/log" 28 | 29 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 30 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/pbcodec" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | func NewPBArpcClient(opt *runner.Options) runner.Client { 35 | log.SetLevel(log.LevelNone) 36 | 37 | cli := &pbArpcClient{} 38 | cli.msg = string(opt.Body) 39 | cli.reqPool = &sync.Pool{ 40 | New: func() interface{} { 41 | return &gogo.Request{} 42 | }, 43 | } 44 | cli.respPool = &sync.Pool{ 45 | New: func() interface{} { 46 | return &gogo.Response{} 47 | }, 48 | } 49 | 50 | arpc.EnablePool(true) 51 | codec.DefaultCodec = &pbcodec.ProtoBuffer{} 52 | pool, err := arpc.NewClientPool(func() (net.Conn, error) { 53 | return net.DialTimeout("tcp", opt.Address, time.Second*5) 54 | }, opt.PoolSize) 55 | if err != nil { 56 | panic(err) 57 | } 58 | 59 | cli.clipool = pool 60 | 61 | return cli 62 | } 63 | 64 | type pbArpcClient struct { 65 | msg string 66 | reqPool *sync.Pool 67 | respPool *sync.Pool 68 | clipool *arpc.ClientPool 69 | } 70 | 71 | func (cli *pbArpcClient) Send(method, action, msg string) (err error) { 72 | args := cli.reqPool.Get().(*gogo.Request) 73 | reply := cli.respPool.Get().(*gogo.Response) 74 | defer cli.reqPool.Put(args) 75 | defer cli.respPool.Put(reply) 76 | 77 | args.Action = action 78 | args.Msg = msg 79 | 80 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 81 | defer cancel() 82 | 83 | client := cli.clipool.Next() 84 | err = client.CallWith(ctx, "Echo", args, reply) 85 | 86 | runner.ProcessResponse(reply.Action, reply.Msg) 87 | return err 88 | } 89 | -------------------------------------------------------------------------------- /grpc/kitex/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | "os" 25 | "runtime/pprof" 26 | 27 | "github.com/cloudwego/kitex/server" 28 | 29 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 30 | echosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/echo" 31 | "github.com/cloudwego/kitex-benchmark/perf" 32 | "github.com/cloudwego/kitex-benchmark/runner" 33 | ) 34 | 35 | const port = 8006 36 | 37 | var ( 38 | _ echo.Echo = &EchoImpl{} 39 | 40 | recorder = perf.NewRecorder("KITEX@Server") 41 | ) 42 | 43 | // EchoImpl implements the last service interface defined in the IDL. 44 | type EchoImpl struct{} 45 | 46 | // Echo implements the EchoImpl interface. 47 | func (s *EchoImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 48 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 49 | return &echo.Response{ 50 | Action: action, 51 | Msg: msg, 52 | }, nil 53 | } 54 | 55 | func main() { 56 | if os.Getenv("KITEX_ENABLE_PROFILE") == "1" { 57 | fmt.Println("[Kitex profile is enabled]") 58 | // start cpu profile 59 | cpuProfile, _ := os.Create("output/benchmark-grpc-server-cpu.pprof") 60 | defer cpuProfile.Close() 61 | _ = pprof.StartCPUProfile(cpuProfile) 62 | defer pprof.StopCPUProfile() 63 | 64 | // heap profile after finish 65 | heapProfile, _ := os.Create("output/benchmark-grpc-server-mem.pprof") 66 | defer func() { 67 | _ = pprof.WriteHeapProfile(heapProfile) 68 | heapProfile.Close() 69 | }() 70 | } 71 | // start pprof server 72 | go func() { 73 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 74 | }() 75 | svr := echosvr.NewServer( 76 | new(EchoImpl), 77 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4zero, Port: port}), 78 | ) 79 | 80 | if err := svr.Run(); err != nil { 81 | log.Println(err.Error()) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/streamserver/streamserver.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | 3 | package streamserver 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 9 | client "github.com/cloudwego/kitex/client" 10 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 11 | streaming "github.com/cloudwego/kitex/pkg/streaming" 12 | ) 13 | 14 | var errInvalidMessageType = errors.New("invalid message type for service method handler") 15 | 16 | var serviceMethods = map[string]kitex.MethodInfo{ 17 | "Echo": kitex.NewMethodInfo( 18 | echoHandler, 19 | newStreamServerEchoArgs, 20 | newStreamServerEchoResult, 21 | false, 22 | kitex.WithStreamingMode(kitex.StreamingBidirectional), 23 | ), 24 | } 25 | 26 | var ( 27 | streamServerServiceInfo = NewServiceInfo() 28 | ) 29 | 30 | // for server 31 | func serviceInfo() *kitex.ServiceInfo { 32 | return streamServerServiceInfo 33 | } 34 | 35 | // NewServiceInfo creates a new ServiceInfo 36 | func NewServiceInfo() *kitex.ServiceInfo { 37 | return newServiceInfo() 38 | } 39 | 40 | func newServiceInfo() *kitex.ServiceInfo { 41 | serviceName := "StreamServer" 42 | handlerType := (*echo.StreamServer)(nil) 43 | extra := map[string]interface{}{ 44 | "PackageName": "echo", 45 | } 46 | svcInfo := &kitex.ServiceInfo{ 47 | ServiceName: serviceName, 48 | HandlerType: handlerType, 49 | Methods: serviceMethods, 50 | PayloadCodec: kitex.Thrift, 51 | KiteXGenVersion: "v0.12.3", 52 | Extra: extra, 53 | } 54 | return svcInfo 55 | } 56 | 57 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 58 | st, err := streaming.GetServerStreamFromArg(arg) 59 | if err != nil { 60 | return err 61 | } 62 | stream := streaming.NewBidiStreamingServer[echo.Request, echo.Response](st) 63 | return handler.(echo.StreamServer).Echo(ctx, stream) 64 | } 65 | 66 | func newStreamServerEchoArgs() interface{} { 67 | return echo.NewStreamServerEchoArgs() 68 | } 69 | 70 | func newStreamServerEchoResult() interface{} { 71 | return echo.NewStreamServerEchoResult() 72 | } 73 | 74 | type kClient struct { 75 | c client.Client 76 | sc client.Streaming 77 | } 78 | 79 | func newServiceClient(c client.Client) *kClient { 80 | return &kClient{ 81 | c: c, 82 | sc: c.(client.Streaming), 83 | } 84 | } 85 | 86 | func (p *kClient) Echo(ctx context.Context) (StreamServer_EchoClient, error) { 87 | st, err := p.sc.StreamX(ctx, "Echo") 88 | if err != nil { 89 | return nil, err 90 | } 91 | stream := streaming.NewBidiStreamingClient[echo.Request, echo.Response](st) 92 | return stream, nil 93 | } 94 | -------------------------------------------------------------------------------- /generic/map/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/kitex/pkg/generic" 26 | "github.com/cloudwego/kitex/pkg/kerrors" 27 | "github.com/cloudwego/kitex/pkg/transmeta" 28 | "github.com/cloudwego/kitex/server" 29 | "github.com/cloudwego/kitex/server/genericserver" 30 | 31 | "github.com/cloudwego/kitex-benchmark/perf" 32 | "github.com/cloudwego/kitex-benchmark/runner" 33 | ) 34 | 35 | const ( 36 | port = 8003 37 | ) 38 | 39 | var recorder = perf.NewRecorder("GenericMap@Server") 40 | 41 | type GenericServerImpl struct{} 42 | 43 | func (s *GenericServerImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { 44 | switch method { 45 | case "Echo": 46 | req := request.(map[string]interface{}) 47 | action, msg := runner.ProcessRequest(recorder, req["action"].(string), req["msg"].(string)) 48 | return map[string]interface{}{ 49 | "action": action, 50 | "msg": msg, 51 | }, nil 52 | case "EchoComplex": 53 | req := request.(map[string]interface{}) 54 | action, msg := runner.ProcessRequest(recorder, req["action"].(string), req["msg"].(string)) 55 | return map[string]interface{}{ 56 | "action": action, 57 | "msg": msg, 58 | "msgMap": req["msgMap"], 59 | "subMsgs": req["subMsgs"], 60 | "msgSet": req["msgSet"], 61 | "flagMsg": req["flagMsg"], 62 | }, nil 63 | } 64 | return nil, kerrors.NewBizStatusError(404, "not found") 65 | } 66 | 67 | func main() { 68 | // start pprof server 69 | go func() { 70 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 71 | }() 72 | 73 | // CurDir: ./scripts 74 | p, err := generic.NewThriftFileProvider("./codec/thrift/echo.thrift") 75 | if err != nil { 76 | panic(err) 77 | } 78 | g, err := generic.MapThriftGeneric(p) 79 | if err != nil { 80 | panic(err) 81 | } 82 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 83 | svr := genericserver.NewServer(new(GenericServerImpl), g, server.WithServiceAddr(address), server.WithMetaHandler(transmeta.ServerTTHeaderHandler)) 84 | 85 | err = svr.Run() 86 | if err != nil { 87 | log.Println(err.Error()) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /runner/counter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "fmt" 21 | "time" 22 | 23 | "github.com/montanaflynn/stats" 24 | ) 25 | 26 | // 计数器 27 | type Counter struct { 28 | Total int64 // 总调用次数(limiter) 29 | Failed int64 // 失败次数 30 | costs []int64 // 耗时统计 31 | } 32 | 33 | func NewCounter() *Counter { 34 | return &Counter{ 35 | costs: make([]int64, 0, 1024*16), // 预分配内存, 减少扩容 36 | } 37 | } 38 | 39 | func (c *Counter) AddRecord(err error, cost int64) { 40 | c.costs = append(c.costs, cost) 41 | c.Total++ 42 | if err != nil { 43 | c.Failed++ 44 | } 45 | } 46 | 47 | func (c *Counter) Report(title string, totalns int64, concurrent int, duration int64, echoSize int) error { 48 | ms, sec := int64(time.Millisecond), int64(time.Second) 49 | logInfo("[%s]: finish benching [%s], took %d ms for %d requests", title, time.Now().String(), totalns/ms, c.Total) 50 | logInfo("[%s]: requests total: %d, failed: %d", title, c.Total, c.Failed) 51 | 52 | var tps float64 53 | if totalns < sec { 54 | tps = float64(c.Total*sec) / float64(totalns) 55 | } else { 56 | tps = float64(c.Total) / (float64(totalns) / float64(sec)) 57 | } 58 | 59 | var sum float64 60 | costs := make([]float64, len(c.costs)) 61 | for i := range c.costs { 62 | costs[i] = float64(c.costs[i]) 63 | sum += float64(c.costs[i]) 64 | } 65 | avg := sum / float64(len(c.costs)) 66 | tp99, _ := stats.Percentile(costs, 99) 67 | tp999, _ := stats.Percentile(costs, 99.9) 68 | 69 | var result string 70 | if tp999/1000 < 1 { 71 | result = fmt.Sprintf("[%s]: TPS: %.2f, AVG: %.2fus, TP99: %.2fus, TP999: %.2fus (b=%d Byte, c=%d, qps=%d, t=%ds)", 72 | title, tps, avg/1000, tp99/1000, tp999/1000, echoSize, concurrent, qps, duration) 73 | } else { 74 | result = fmt.Sprintf("[%s]: TPS: %.2f, AVG: %.2fms, TP99: %.2fms, TP999: %.2fms (b=%d Byte, c=%d, qps=%d, t=%ds)", 75 | title, tps, avg/1000000, tp99/1000000, tp999/1000000, echoSize, concurrent, qps, duration) 76 | } 77 | logInfo(result) 78 | return nil 79 | } 80 | 81 | const blueLayout = "\x1B[1;36;40m%s\x1B[0m" 82 | 83 | var infoTitle = "Info: " 84 | 85 | func logInfo(format string, a ...interface{}) { 86 | s := fmt.Sprintf(format, a...) 87 | fmt.Println(infoTitle + s) 88 | } 89 | -------------------------------------------------------------------------------- /streaming/kitex_grpc/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "log" 23 | "sync" 24 | 25 | "github.com/cloudwego/kitex/client" 26 | "github.com/cloudwego/kitex/pkg/klog" 27 | "github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/metadata" 28 | "github.com/cloudwego/kitex/transport" 29 | 30 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 31 | sechosvr "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo/secho" 32 | "github.com/cloudwego/kitex-benchmark/runner" 33 | ) 34 | 35 | func NewKClient(opt *runner.Options) runner.Client { 36 | klog.SetLevel(klog.LevelWarn) 37 | c := sechosvr.MustNewClient("test.echo.kitex", 38 | client.WithHostPorts(opt.Address), 39 | client.WithTransportProtocol(transport.GRPC), 40 | client.WithGRPCConnPoolSize(1), 41 | ) 42 | cli := &kClient{ 43 | client: c, 44 | streampool: &sync.Pool{ 45 | New: func() interface{} { 46 | ctx := metadata.AppendToOutgoingContext(context.Background(), "header", "hello") 47 | stream, err := c.Echo(ctx) 48 | if err != nil { 49 | log.Printf("client new stream failed: %v", err) 50 | return nil 51 | } 52 | return stream 53 | }, 54 | }, 55 | reqPool: &sync.Pool{ 56 | New: func() interface{} { 57 | return &echo.Request{} 58 | }, 59 | }, 60 | } 61 | return cli 62 | } 63 | 64 | type kClient struct { 65 | client sechosvr.Client 66 | streampool *sync.Pool 67 | reqPool *sync.Pool 68 | } 69 | 70 | func (cli *kClient) Send(method, action, msg string) error { 71 | req := cli.reqPool.Get().(*echo.Request) 72 | defer cli.reqPool.Put(req) 73 | 74 | stream, ok := cli.streampool.Get().(sechosvr.SEcho_echoClient) 75 | if !ok { 76 | return errors.New("new stream error") 77 | } 78 | defer cli.streampool.Put(stream) 79 | req.Action = action 80 | req.Msg = msg 81 | err := stream.Send(stream.Context(), req) 82 | if err != nil { 83 | return err 84 | } 85 | resp, err := stream.Recv(stream.Context()) 86 | if err != nil { 87 | return err 88 | } 89 | runner.ProcessResponse(resp.Action, resp.Msg) 90 | return nil 91 | } 92 | 93 | // main is use for routing. 94 | func main() { 95 | runner.Main("KITEX_GRPC", NewKClient) 96 | } 97 | -------------------------------------------------------------------------------- /scripts/reports/diff.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | import sys 4 | 5 | '''CSV Format Example 6 | Kind,Concurrency,Data_Size,TPS,AVG,P99,Server_CPU,Client_CPU 7 | [GRPC],100,1024,101152.29,3.36,5.30,188.04,423.07 8 | ''' 9 | 10 | 11 | class bcolors: 12 | HEADER = '\033[95m' 13 | OKBLUE = '\033[94m' 14 | OKCYAN = '\033[96m' 15 | OKGREEN = '\033[92m' 16 | WARNING = '\033[93m' 17 | FAIL = '\033[91m' 18 | ENDC = '\033[0m' 19 | BOLD = '\033[1m' 20 | UNDERLINE = '\033[4m' 21 | 22 | 23 | def diff(from_csv, to_csv, benchmark_type, no_title): 24 | from_reader = list(csv.reader(open(from_csv))) 25 | to_reader = csv.reader(open(to_csv)) 26 | title = ['Kind', 'Concurrency', 'Data_Size', 'QPS', 'AVG', 'P99', 'Server_CPU', 'Client_CPU'] 27 | results = [] 28 | 29 | for line_num, line in enumerate(to_reader): 30 | result = [] 31 | if benchmark_type != "": 32 | result.append("["+benchmark_type+"]") # kind 33 | else: 34 | result.append(line[0]) # kind 35 | result.append(line[1]) # concurrency 36 | result.append(line[2]) # data size 37 | 38 | result.append(diff_cell(from_reader[line_num][3], line[3])) # tps 39 | result.append(diff_cell(from_reader[line_num][4], line[4])) # avg 40 | result.append(diff_cell(from_reader[line_num][5], line[5])) # p99 41 | result.append(diff_cell(from_reader[line_num][6], line[6])) # Server CPU 42 | result.append(diff_cell(from_reader[line_num][7], line[7])) # Client CPU 43 | 44 | results.append(result) 45 | 46 | results.sort(key=lambda result: result[0]) 47 | if not no_title: 48 | results.insert(0, title) 49 | print_csv(results) 50 | 51 | 52 | def diff_cell(old, now): 53 | old, now = float(old), float(now) 54 | percent = (now - old) / old * 100 55 | flag = '+' if percent >= 0 else '' 56 | return '{}{}({}{:.1f}%){}'.format(now, bcolors.WARNING, flag, percent, bcolors.ENDC) 57 | 58 | 59 | def print_csv(results): 60 | cell_size = 15 61 | for line in results: 62 | result = [] 63 | for cell in line: 64 | padding = cell_size - len(cell) 65 | if padding <= 0: 66 | padding = 5 67 | cell += ' ' * padding 68 | result.append(cell) 69 | print(''.join(result)) 70 | 71 | 72 | def main(): 73 | if len(sys.argv) < 3: 74 | print('''Usage: 75 | diff.py {baseline.csv} {current.csv} 76 | ''') 77 | return 78 | from_csv = sys.argv[1] 79 | to_csv = sys.argv[2] 80 | if len(sys.argv) < 4: 81 | benchmark_type = "" 82 | else: 83 | benchmark_type = sys.argv[3] 84 | if len(sys.argv) < 5: 85 | no_title = False 86 | else: 87 | no_title = sys.argv[4] == "True" 88 | diff(from_csv, to_csv, benchmark_type, no_title) 89 | 90 | 91 | if __name__ == '__main__': 92 | main() 93 | -------------------------------------------------------------------------------- /thrift/kitex/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | "os" 25 | "runtime/pprof" 26 | 27 | "github.com/cloudwego/kitex/server" 28 | 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 31 | "github.com/cloudwego/kitex-benchmark/perf" 32 | "github.com/cloudwego/kitex-benchmark/runner" 33 | ) 34 | 35 | const ( 36 | port = 8001 37 | ) 38 | 39 | var recorder = perf.NewRecorder("KITEX@Server") 40 | 41 | // EchoServerImpl implements the last service interface defined in the IDL. 42 | type EchoServerImpl struct{} 43 | 44 | func (s *EchoServerImpl) Echo(ctx context.Context, req *echo.Request) (*echo.Response, error) { 45 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 46 | return &echo.Response{ 47 | Action: action, 48 | Msg: msg, 49 | }, nil 50 | } 51 | 52 | func (s *EchoServerImpl) EchoComplex(ctx context.Context, req *echo.ComplexRequest) (*echo.ComplexResponse, error) { 53 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 54 | return &echo.ComplexResponse{ 55 | Action: action, 56 | Msg: msg, 57 | MsgMap: req.MsgMap, 58 | SubMsgs: req.SubMsgs, 59 | MsgSet: req.MsgSet, 60 | FlagMsg: req.FlagMsg, 61 | }, nil 62 | } 63 | 64 | func main() { 65 | if os.Getenv("KITEX_ENABLE_PROFILE") == "1" { 66 | fmt.Println("[Kitex profile is enabled]") 67 | // start cpu profile 68 | cpuProfile, _ := os.Create("output/benchmark-thrift-server-cpu.pprof") 69 | defer cpuProfile.Close() 70 | _ = pprof.StartCPUProfile(cpuProfile) 71 | defer pprof.StopCPUProfile() 72 | 73 | // heap profile after finish 74 | heapProfile, _ := os.Create("output/benchmark-thrift-server-mem.pprof") 75 | defer func() { 76 | _ = pprof.WriteHeapProfile(heapProfile) 77 | heapProfile.Close() 78 | }() 79 | } 80 | // start pprof server 81 | go func() { 82 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 83 | }() 84 | 85 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 86 | svr := echoserver.NewServer(new(EchoServerImpl), server.WithServiceAddr(address)) 87 | 88 | err := svr.Run() 89 | if err != nil { 90 | log.Println(err.Error()) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /scripts/base.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # benchmark params 5 | t=30 6 | method="echo" 7 | body=(1024) 8 | concurrent=(100) 9 | qps=(0) 10 | sleep=0 11 | # NOTICE: if you want to dump profile, set "enable_profile" to 1 12 | enable_profile=0 13 | if [ $enable_profile -eq 1 ]; then 14 | export KITEX_ENABLE_PROFILE=1 15 | fi 16 | 17 | CURDIR=$(cd $(dirname $0); pwd) 18 | 19 | source $CURDIR/util.sh && check_supported_env 20 | 21 | if ! [ -x "$(command -v taskset)" ]; then 22 | echo "Error: taskset is not installed." >&2 23 | exit 1 24 | fi 25 | 26 | # cpu binding 27 | nprocs=$(getconf _NPROCESSORS_ONLN) 28 | if [ $nprocs -lt 4 ]; then 29 | echo "Error: your environment should have at least 4 processors" 30 | exit 1 31 | elif [ $nprocs -gt 20 ]; then 32 | nprocs=20 33 | fi 34 | scpu=$((nprocs > 16 ? 4 : nprocs / 4)) # max is 4 cpus 35 | ccpu=$((nprocs-scpu)) 36 | scpu_cmd="taskset -c 0-$((scpu-1))" 37 | ccpu_cmd="taskset -c ${scpu}-$((ccpu-1))" 38 | if [ -x "$(command -v numactl)" ]; then 39 | # use numa affinity 40 | node0=$(numactl -H | grep "node 0" | head -n 1 | cut -f "4-$((3+scpu))" -d ' ' --output-delimiter ',') 41 | node1=$(numactl -H | grep "node 1" | head -n 1 | cut -f "4-$((3+ccpu))" -d ' ' --output-delimiter ',') 42 | scpu_cmd="numactl -C ${node0} -m 0" 43 | ccpu_cmd="numactl -C ${node1} -m 1" 44 | fi 45 | 46 | # GO 47 | GOEXEC=${GOEXEC:-"go"} 48 | GOROOT=$GOROOT 49 | 50 | USER=$(whoami) 51 | REPORT=${REPORT:-"$(date +%F-%H-%M)"} 52 | 53 | nice_cmd='' 54 | tee_cmd="tee -a output/${REPORT}.log" 55 | function finish_cmd() { 56 | # to csv report 57 | ./scripts/reports/to_csv.sh output/"$REPORT.log" > output/"$REPORT".csv 58 | echo "output reports: output/$REPORT.log, output/$REPORT.csv" 59 | cat ./output/"$REPORT.csv" 60 | } 61 | if [ "$USER" == "root" ]; then 62 | nice_cmd='nice -n -20' 63 | fi 64 | cmd_server="${nice_cmd} ${scpu_cmd}" 65 | cmd_client="${nice_cmd} ${ccpu_cmd}" 66 | 67 | # set dirs 68 | output_dir=$CURDIR/../output 69 | pb_dir=$CURDIR/../protobuf 70 | thrift_dir=$CURDIR/../thrift 71 | grpc_dir=$CURDIR/../grpc 72 | streaming_dir=$CURDIR/../streaming 73 | generic_dir=$CURDIR/../generic 74 | 75 | function kill_pid_listening_on_port() { 76 | port=$1 77 | if [ -z "$port" ]; then 78 | echo "invalid port" 79 | exit 1 80 | fi 81 | pids=`lsof -i ":$port" | grep LISTEN | awk '{print $2}' | uniq` 82 | 83 | for p in $pids; do 84 | echo "Sending termination signal to $p..." 85 | kill -s SIGTERM $p # Send SIGTERM signal to the processes 86 | done 87 | 88 | # Give the processes a certain amount of time to 89 | # handle the signal before forcibly terminating them. 90 | sleep 2 91 | 92 | # Ignore errors because the processes may not exist. 93 | set +e 94 | for p in $pids; do 95 | echo killing $p... 96 | kill $p 97 | done 98 | sleep 1 99 | set -e 100 | } 101 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ develop, main ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ develop ] 20 | schedule: 21 | - cron: '35 21 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'go' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] 37 | # Learn more: 38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 39 | 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v4 43 | 44 | - name: Set up Go 45 | uses: actions/setup-go@v5 46 | with: 47 | go-version: 1.16 48 | 49 | - uses: actions/cache@v3 50 | with: 51 | path: ~/go/pkg/mod 52 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 53 | restore-keys: | 54 | ${{ runner.os }}-go- 55 | 56 | # Initializes the CodeQL tools for scanning. 57 | - name: Initialize CodeQL 58 | uses: github/codeql-action/init@v1 59 | with: 60 | languages: ${{ matrix.language }} 61 | # If you wish to specify custom queries, you can do so here or in a config file. 62 | # By default, queries listed here will override any specified in a config file. 63 | # Prefix the list here with "+" to use these queries and those in the config file. 64 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 65 | 66 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 67 | # If this step fails, then you should remove it and run the build manually (see below) 68 | - name: Autobuild 69 | uses: github/codeql-action/autobuild@v1 70 | 71 | # ℹ️ Command-line programs to run using the OS shell. 72 | # 📚 https://git.io/JvXDl 73 | 74 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 75 | # and modify them (or add more) to build your code if your project 76 | # uses a compiled language 77 | 78 | #- run: | 79 | # make bootstrap 80 | # make release 81 | 82 | - name: Perform CodeQL Analysis 83 | uses: github/codeql-action/analyze@v1 84 | -------------------------------------------------------------------------------- /scripts/reports/render_images.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import sys 3 | 4 | kind = "streaming" 5 | 6 | 7 | # 0-name, 1-concurrency, 2-size, 3-qps, 6-p99, 7-p999 8 | def parse_data(file): 9 | import csv 10 | csv_reader = csv.reader(open(file)) 11 | lines = [] 12 | for line in csv_reader: 13 | lines.append(line) 14 | x_label, x_ticks = parse_x(lines=lines) 15 | print(x_label, x_ticks) 16 | 17 | y_qps = parse_y(lines=lines, idx=3) 18 | print(y_qps) 19 | plot_data(title="QPS (higher is better)", xlabel=x_label, ylabel="qps", x_ticks=x_ticks, ys=y_qps) 20 | 21 | y_p99 = parse_y(lines=lines, idx=4, times=1000) 22 | print(y_p99) 23 | plot_data(title="TP99 (lower is better)", xlabel=x_label, ylabel="latency(us)", x_ticks=x_ticks, ys=y_p99) 24 | 25 | y_p999 = parse_y(lines=lines, idx=5, times=1000) 26 | print(y_p999) 27 | plot_data(title="TP999 (lower is better)", xlabel=x_label, ylabel="latency(us)", x_ticks=x_ticks, ys=y_p999) 28 | 29 | 30 | # 并发相同比 size; size 相同比并发 31 | def parse_x(lines): 32 | l = len(lines) 33 | idx = 1 34 | x_label = "concurrency" 35 | if lines[0][1] == lines[l - 1][1]: 36 | idx = 2 37 | x_label = "echo size(Byte)" 38 | x_list = [] 39 | x_key = lines[0][0] 40 | for line in lines: 41 | if line[0] == x_key: 42 | x_list.append(int(line[idx])) 43 | return x_label, x_list 44 | 45 | 46 | def parse_y(lines, idx, times=1): 47 | y_dict = {} 48 | for line in lines: 49 | name = line[0] 50 | y_line = y_dict.get(name, []) 51 | n = float(line[idx]) * times 52 | y_line.append(int(n)) 53 | # y_line.append(int(line[idx])) 54 | y_dict[name] = y_line 55 | return y_dict 56 | 57 | 58 | # TODO 59 | color_dict = { 60 | "[KITEX]": "royalblue", 61 | "[KITEX-MUX]": "darkorange", 62 | "[RPCX]": "purple", 63 | "[GRPC]": "pink", 64 | "[KITEX_GRPC]": "#6F1862", 65 | "[KITEX_TTS_LCONN]": "#C5B8D3", 66 | "[KITEX_TTS_MUX]": "#D7E58C", 67 | } 68 | 69 | 70 | # ys={"$net":[]number} 71 | def plot_data(title, xlabel, ylabel, x_ticks, ys): 72 | plt.figure(figsize=(8, 5)) 73 | # bmh、ggplot、dark_background、fivethirtyeight 和 grayscale 74 | plt.style.use('grayscale') 75 | plt.title(title) 76 | 77 | plt.xlabel(xlabel) 78 | plt.ylabel(ylabel) 79 | 80 | # x 轴示数 81 | plt.xticks(range(len(x_ticks)), x_ticks) 82 | 83 | for k, v in ys.items(): 84 | color = color_dict.get(k) 85 | if color != "": 86 | plt.plot(v, label=k, linewidth=2, color=color) 87 | else: 88 | plt.plot(v, label=k, linewidth=2) 89 | 90 | # y 轴从 0 开始 91 | bottom, top = plt.ylim() 92 | plt.ylim(bottom=0, top=1.2 * top) 93 | 94 | plt.legend(prop={'size': 12}) 95 | plt.savefig("{0}_{1}.png".format(kind, title.split(" ")[0].lower())) 96 | # plt.show() 97 | 98 | 99 | if __name__ == '__main__': 100 | if len(sys.argv) > 1: 101 | kind = sys.argv[1] 102 | parse_data(file="{0}.csv".format(kind)) 103 | -------------------------------------------------------------------------------- /generic/ordinary/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | "time" 23 | 24 | "github.com/cloudwego/kitex/client" 25 | "github.com/cloudwego/kitex/pkg/connpool" 26 | "github.com/cloudwego/kitex/pkg/transmeta" 27 | "github.com/cloudwego/kitex/transport" 28 | 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | var ( 35 | subMsg1 = &echo.SubMessage{ 36 | Id: &(&struct{ x int64 }{int64(123)}).x, 37 | Value: &(&struct{ x string }{"hello"}).x, 38 | } 39 | subMsg2 = &echo.SubMessage{ 40 | Id: &(&struct{ x int64 }{int64(321)}).x, 41 | Value: &(&struct{ x string }{"world"}).x, 42 | } 43 | msg1 = &echo.Message{ 44 | Id: &(&struct{ x int64 }{int64(123)}).x, 45 | Value: &(&struct{ x string }{"hello"}).x, 46 | SubMessages: []*echo.SubMessage{subMsg1, subMsg2}, 47 | } 48 | msg2 = &echo.Message{ 49 | Id: &(&struct{ x int64 }{int64(321)}).x, 50 | Value: &(&struct{ x string }{"world"}).x, 51 | SubMessages: []*echo.SubMessage{subMsg2, subMsg1}, 52 | } 53 | ) 54 | 55 | func NewGenericOrdinaryClient(opt *runner.Options) runner.Client { 56 | cli := &genericOrdinaryClient{} 57 | cli.client = echoserver.MustNewClient("test.echo.kitex", 58 | client.WithTransportProtocol(transport.TTHeader), 59 | client.WithHostPorts(opt.Address), 60 | client.WithMetaHandler(transmeta.ClientTTHeaderHandler), 61 | client.WithLongConnection( 62 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 63 | ) 64 | cli.reqPool = &sync.Pool{ 65 | New: func() interface{} { 66 | return &echo.ComplexRequest{ 67 | MsgMap: map[string]*echo.SubMessage{ 68 | "v1": subMsg1, 69 | "v2": subMsg2, 70 | }, 71 | SubMsgs: []*echo.SubMessage{subMsg1, subMsg2}, 72 | MsgSet: []*echo.Message{msg1, msg2}, 73 | FlagMsg: msg1, 74 | } 75 | }, 76 | } 77 | return cli 78 | } 79 | 80 | type genericOrdinaryClient struct { 81 | client echoserver.Client 82 | reqPool *sync.Pool 83 | } 84 | 85 | func (cli *genericOrdinaryClient) Send(method, action, msg string) error { 86 | ctx := context.Background() 87 | req := cli.reqPool.Get().(*echo.ComplexRequest) 88 | defer cli.reqPool.Put(req) 89 | 90 | req.Action = action 91 | req.Msg = msg 92 | 93 | reply, err := cli.client.EchoComplex(ctx, req) 94 | if reply != nil { 95 | runner.ProcessResponse(reply.Action, reply.Msg) 96 | } 97 | return err 98 | } 99 | -------------------------------------------------------------------------------- /streaming/kitex_tts_lconn/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "io" 23 | "log" 24 | "sync" 25 | 26 | "github.com/bytedance/gopkg/cloud/metainfo" 27 | "github.com/cloudwego/kitex/client" 28 | "github.com/cloudwego/kitex/pkg/klog" 29 | "github.com/cloudwego/kitex/pkg/remote/trans/ttstream" 30 | 31 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 32 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/streamserver" 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | func NewKClient(opt *runner.Options) runner.Client { 37 | klog.SetLevel(klog.LevelWarn) 38 | c, err := streamserver.NewClient( 39 | "test.echo.kitex", 40 | client.WithHostPorts(opt.Address), 41 | client.WithTTHeaderStreamingOptions(client.WithTTHeaderStreamingTransportOptions(ttstream.WithClientLongConnPool(ttstream.DefaultLongConnConfig))), 42 | ) 43 | if err != nil { 44 | log.Fatal(err) 45 | } 46 | cli := &kClient{ 47 | client: c, 48 | streampool: &sync.Pool{ 49 | New: func() interface{} { 50 | ctx := metainfo.WithValue(context.Background(), "header", "hello") 51 | stream, err := c.Echo(ctx) 52 | if err != nil { 53 | log.Printf("client new stream failed: %v", err) 54 | return nil 55 | } 56 | return stream 57 | }, 58 | }, 59 | reqPool: &sync.Pool{ 60 | New: func() interface{} { 61 | return &echo.Request{} 62 | }, 63 | }, 64 | } 65 | return cli 66 | } 67 | 68 | type kClient struct { 69 | client streamserver.Client 70 | streampool *sync.Pool 71 | reqPool *sync.Pool 72 | } 73 | 74 | func (cli *kClient) Send(method, action, msg string) error { 75 | req := cli.reqPool.Get().(*echo.Request) 76 | defer cli.reqPool.Put(req) 77 | 78 | st := cli.streampool.Get() 79 | if st == nil { 80 | return errors.New("new stream from streampool failed") 81 | } 82 | stream, ok := st.(streamserver.StreamServer_EchoClient) 83 | if !ok { 84 | return errors.New("new stream error") 85 | } 86 | defer cli.streampool.Put(stream) 87 | 88 | ctx := context.Background() 89 | req.Action = action 90 | req.Msg = msg 91 | err := stream.Send(ctx, req) 92 | if err != nil { 93 | return err 94 | } 95 | 96 | resp, err := stream.Recv(ctx) 97 | if err != nil && !errors.Is(err, io.EOF) { 98 | return err 99 | } 100 | runner.ProcessResponse(resp.Action, resp.Msg) 101 | return nil 102 | } 103 | 104 | // main is use for routing. 105 | func main() { 106 | runner.Main("KITEX_TTS_LCONN", NewKClient) 107 | } 108 | -------------------------------------------------------------------------------- /streaming/kitex_tts_mux/client/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "io" 23 | "log" 24 | "sync" 25 | 26 | "github.com/bytedance/gopkg/cloud/metainfo" 27 | "github.com/cloudwego/kitex/client" 28 | "github.com/cloudwego/kitex/pkg/klog" 29 | "github.com/cloudwego/kitex/pkg/remote/trans/ttstream" 30 | 31 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 32 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/streamserver" 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | func NewKClient(opt *runner.Options) runner.Client { 37 | klog.SetLevel(klog.LevelWarn) 38 | 39 | c, err := streamserver.NewClient( 40 | "test.echo.kitex", 41 | client.WithHostPorts(opt.Address), 42 | client.WithTTHeaderStreamingOptions(client.WithTTHeaderStreamingTransportOptions(ttstream.WithClientMuxConnPool(ttstream.MuxConnConfig{PoolSize: 4}))), 43 | ) 44 | if err != nil { 45 | log.Fatal(err) 46 | } 47 | cli := &kClient{ 48 | client: c, 49 | streampool: &sync.Pool{ 50 | New: func() interface{} { 51 | ctx := metainfo.WithValue(context.Background(), "header", "hello") 52 | stream, err := c.Echo(ctx) 53 | if err != nil { 54 | log.Printf("client new stream failed: %v", err) 55 | return nil 56 | } 57 | return stream 58 | }, 59 | }, 60 | reqPool: &sync.Pool{ 61 | New: func() interface{} { 62 | return &echo.Request{} 63 | }, 64 | }, 65 | } 66 | return cli 67 | } 68 | 69 | type kClient struct { 70 | client streamserver.Client 71 | streampool *sync.Pool 72 | reqPool *sync.Pool 73 | } 74 | 75 | func (cli *kClient) Send(method, action, msg string) error { 76 | req := cli.reqPool.Get().(*echo.Request) 77 | defer cli.reqPool.Put(req) 78 | 79 | st := cli.streampool.Get() 80 | if st == nil { 81 | return errors.New("new stream from streampool failed") 82 | } 83 | stream, ok := st.(streamserver.StreamServer_EchoClient) 84 | if !ok { 85 | return errors.New("new stream error") 86 | } 87 | defer cli.streampool.Put(stream) 88 | 89 | ctx := context.Background() 90 | req.Action = action 91 | req.Msg = msg 92 | err := stream.Send(ctx, req) 93 | if err != nil { 94 | return err 95 | } 96 | 97 | resp, err := stream.Recv(ctx) 98 | if err != nil && !errors.Is(err, io.EOF) { 99 | return err 100 | } 101 | runner.ProcessResponse(resp.Action, resp.Msg) 102 | return nil 103 | } 104 | 105 | // main is use for routing. 106 | func main() { 107 | runner.Main("KITEX_TTS_MUX", NewKClient) 108 | } 109 | -------------------------------------------------------------------------------- /perf/cpu/cpu.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package cpu 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "os" 23 | "sort" 24 | "time" 25 | 26 | sigar "github.com/cloudfoundry/gosigar" 27 | ) 28 | 29 | const ( 30 | defaultInterval = time.Second * 1 31 | defaultUsageThreshold = 10 // % 32 | ) 33 | 34 | type Usage struct { 35 | Min float64 36 | Max float64 37 | Avg float64 38 | P50 float64 39 | P90 float64 40 | P99 float64 41 | } 42 | 43 | func (u Usage) String() string { 44 | return fmt.Sprintf( 45 | "MIN: %0.2f%%, TP50: %0.2f%%, TP90: %0.2f%%, TP99: %0.2f%%, MAX: %0.2f%%, AVG:%0.2f%%", 46 | u.Min, u.P50, u.P90, u.P99, u.Max, u.Avg, 47 | ) 48 | } 49 | 50 | // RecordUsage return the final Usage when context canceled 51 | func RecordUsage(ctx context.Context) (Usage, error) { 52 | pid := os.Getpid() 53 | return RecordUsageWithPid(ctx, pid) 54 | } 55 | 56 | // RecordUsageWithPid return the final Usage when context canceled 57 | func RecordUsageWithPid(ctx context.Context, pid int) (usage Usage, err error) { 58 | if _, err = os.FindProcess(pid); err != nil { 59 | return 60 | } 61 | 62 | var cpuUsageList []float64 63 | var procCpu = sigar.ProcCpu{} 64 | var ticker = time.NewTicker(defaultInterval) 65 | defer ticker.Stop() 66 | for { 67 | if err = procCpu.Get(pid); err != nil { 68 | return 69 | } 70 | 71 | cpuUsage := procCpu.Percent * 100 72 | if cpuUsage > defaultUsageThreshold { 73 | cpuUsageList = append(cpuUsageList, cpuUsage) 74 | } 75 | 76 | select { 77 | case <-ctx.Done(): 78 | return calcUsage(cpuUsageList), nil 79 | case <-ticker.C: 80 | } 81 | } 82 | } 83 | 84 | func calcUsage(stats []float64) Usage { 85 | if len(stats) == 0 { 86 | return Usage{} 87 | } 88 | 89 | sort.Float64s(stats) 90 | length := len(stats) 91 | if length > 3 { 92 | stats = stats[1 : length-1] 93 | length = length - 2 94 | } 95 | fLen := float64(len(stats)) 96 | tp50Index := int(fLen * 0.5) 97 | tp90Index := int(fLen * 0.9) 98 | tp99Index := int(fLen * 0.99) 99 | 100 | var usage Usage 101 | if tp50Index > 0 { 102 | usage.P50 = stats[tp50Index-1] 103 | } 104 | if tp90Index > tp50Index { 105 | usage.P90 = stats[tp90Index-1] 106 | } else { 107 | usage.P90 = usage.P50 108 | } 109 | if tp99Index > tp90Index { 110 | usage.P99 = stats[tp99Index-1] 111 | } else { 112 | usage.P99 = usage.P90 113 | } 114 | 115 | var sum float64 116 | for _, cost := range stats { 117 | sum += cost 118 | } 119 | usage.Avg = sum / fLen 120 | 121 | usage.Min = stats[0] 122 | usage.Max = stats[length-1] 123 | 124 | return usage 125 | } 126 | -------------------------------------------------------------------------------- /generic/binary/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "log" 23 | "net" 24 | 25 | "github.com/cloudwego/gopkg/protocol/thrift" 26 | "github.com/cloudwego/kitex/pkg/transmeta" 27 | "github.com/cloudwego/kitex/server" 28 | "github.com/cloudwego/kitex/server/genericserver" 29 | 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 31 | "github.com/cloudwego/kitex-benchmark/perf" 32 | "github.com/cloudwego/kitex-benchmark/runner" 33 | ) 34 | 35 | const ( 36 | port = 8000 37 | ) 38 | 39 | var recorder = perf.NewRecorder("GenericBinary@Server") 40 | 41 | // EchoServerImpl implements the last service interface defined in the IDL. 42 | type EchoServerImpl struct{} 43 | 44 | func (s EchoServerImpl) DefaultHandler(ctx context.Context, service, method string, request interface{}) (response interface{}, err error) { 45 | switch method { 46 | case "Echo": 47 | args := &echo.EchoServerEchoArgs{} 48 | if err = thrift.FastUnmarshal(request.([]byte), args); err != nil { 49 | return nil, err 50 | } 51 | req := args.Req 52 | if req == nil { 53 | return nil, fmt.Errorf("req is nil") 54 | } 55 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 56 | resp := &echo.Response{ 57 | Action: action, 58 | Msg: msg, 59 | } 60 | return thrift.FastMarshal(&echo.EchoServerEchoResult{Success: resp}), nil 61 | case "EchoComplex": 62 | args := &echo.EchoServerEchoComplexArgs{} 63 | if err = thrift.FastUnmarshal(request.([]byte), args); err != nil { 64 | return nil, err 65 | } 66 | req := args.Req 67 | if req == nil { 68 | return nil, fmt.Errorf("req is nil") 69 | } 70 | action, msg := runner.ProcessRequest(recorder, req.Action, req.Msg) 71 | return thrift.FastMarshal(&echo.EchoServerEchoComplexResult{Success: &echo.ComplexResponse{ 72 | Action: action, 73 | Msg: msg, 74 | MsgMap: req.MsgMap, 75 | SubMsgs: req.SubMsgs, 76 | MsgSet: req.MsgSet, 77 | FlagMsg: req.FlagMsg, 78 | }}), nil 79 | default: 80 | return nil, fmt.Errorf("unknown method: %s", method) 81 | } 82 | } 83 | 84 | func main() { 85 | // start pprof server 86 | go func() { 87 | perf.ServeMonitor(fmt.Sprintf(":%d", port+10000)) 88 | }() 89 | 90 | address := &net.UnixAddr{Net: "tcp", Name: fmt.Sprintf(":%d", port)} 91 | svr := genericserver.NewUnknownServiceOrMethodServer(&genericserver.UnknownServiceOrMethodHandler{ 92 | DefaultHandler: EchoServerImpl{}.DefaultHandler, 93 | }, server.WithServiceAddr(address), server.WithMetaHandler(transmeta.ServerTTHeaderHandler)) 94 | 95 | err := svr.Run() 96 | if err != nil { 97 | log.Println(err.Error()) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /generic/map/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | "time" 23 | 24 | "github.com/cloudwego/kitex/client" 25 | "github.com/cloudwego/kitex/client/genericclient" 26 | "github.com/cloudwego/kitex/pkg/connpool" 27 | "github.com/cloudwego/kitex/pkg/generic" 28 | "github.com/cloudwego/kitex/pkg/transmeta" 29 | "github.com/cloudwego/kitex/transport" 30 | 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | var ( 35 | subMsg1 = map[string]interface{}{ 36 | "id": int64(123), 37 | "value": "hello", 38 | } 39 | subMsg2 = map[string]interface{}{ 40 | "id": int64(321), 41 | "value": "world", 42 | } 43 | msg1 = map[string]interface{}{ 44 | "id": int64(123), 45 | "value": "hello", 46 | "subMessages": []interface{}{subMsg1, subMsg2}, 47 | } 48 | msg2 = map[string]interface{}{ 49 | "id": int64(321), 50 | "value": "world", 51 | "subMessages": []interface{}{subMsg2, subMsg1}, 52 | } 53 | ) 54 | 55 | func NewGenericMapClient(opt *runner.Options) runner.Client { 56 | p, err := generic.NewThriftFileProvider("./codec/thrift/echo.thrift") 57 | if err != nil { 58 | panic(err) 59 | } 60 | // 构造map 请求和返回类型的泛化调用 61 | g, err := generic.MapThriftGeneric(p) 62 | if err != nil { 63 | panic(err) 64 | } 65 | cli := &genericMapClient{} 66 | cli.client, err = genericclient.NewClient("test.echo.kitex", g, 67 | client.WithTransportProtocol(transport.TTHeader), 68 | client.WithHostPorts(opt.Address), 69 | client.WithMetaHandler(transmeta.ClientTTHeaderHandler), 70 | client.WithLongConnection( 71 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 72 | ) 73 | if err != nil { 74 | panic(err) 75 | } 76 | cli.reqPool = &sync.Pool{ 77 | New: func() interface{} { 78 | return map[string]interface{}{ 79 | "msgMap": map[interface{}]interface{}{ 80 | "v1": subMsg1, 81 | "v2": subMsg2, 82 | }, 83 | "subMsgs": []interface{}{subMsg1, subMsg2}, 84 | "msgSet": []interface{}{msg1, msg2}, 85 | "flagMsg": msg1, 86 | } 87 | }, 88 | } 89 | return cli 90 | } 91 | 92 | type genericMapClient struct { 93 | client genericclient.Client 94 | reqPool *sync.Pool 95 | } 96 | 97 | func (cli *genericMapClient) Send(method, action, msg string) error { 98 | ctx := context.Background() 99 | req := cli.reqPool.Get().(map[string]interface{}) 100 | defer cli.reqPool.Put(req) 101 | 102 | req["action"] = action 103 | req["msg"] = msg 104 | 105 | reply, err := cli.client.GenericCall(ctx, "EchoComplex", req) 106 | if reply != nil { 107 | repl := reply.(map[string]interface{}) 108 | runner.ProcessResponse(repl["action"].(string), repl["msg"].(string)) 109 | } 110 | return err 111 | } 112 | -------------------------------------------------------------------------------- /protobuf/arpc-nbio/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "os" 21 | "os/signal" 22 | "syscall" 23 | "time" 24 | 25 | "github.com/lesismal/arpc" 26 | "github.com/lesismal/arpc/codec" 27 | "github.com/lesismal/arpc/log" 28 | "github.com/lesismal/nbio" 29 | nlog "github.com/lesismal/nbio/logging" 30 | 31 | gogo "github.com/cloudwego/kitex-benchmark/codec/protobuf/gogo_gen" 32 | "github.com/cloudwego/kitex-benchmark/codec/protobuf/pbcodec" 33 | "github.com/cloudwego/kitex-benchmark/perf" 34 | "github.com/cloudwego/kitex-benchmark/runner" 35 | ) 36 | 37 | const ( 38 | port = ":8005" 39 | ) 40 | 41 | var recorder = perf.NewRecorder("ARPC-NBIO@Server") 42 | 43 | func Echo(ctx *arpc.Context) { 44 | args := &gogo.Request{} 45 | 46 | if err := ctx.Bind(args); err != nil { 47 | ctx.Error(err) 48 | return 49 | } 50 | 51 | action, msg := runner.ProcessRequest(recorder, args.Action, args.Msg) 52 | reply := &gogo.Response{ 53 | Action: action, 54 | Msg: msg, 55 | } 56 | ctx.Write(reply) 57 | } 58 | 59 | func main() { 60 | log.SetLevel(log.LevelNone) 61 | nlog.SetLogger(log.DefaultLogger) 62 | 63 | codec.DefaultCodec = &pbcodec.ProtoBuffer{} 64 | 65 | handler.SetAsyncWrite(false) 66 | handler.SetAsyncResponse(true) 67 | handler.Handle("Echo", Echo) 68 | 69 | g := nbio.NewGopher(nbio.Config{ 70 | Network: "tcp", 71 | Addrs: []string{port}, 72 | }) 73 | 74 | g.OnOpen(onOpen) 75 | g.OnData(onData) 76 | 77 | err := g.Start() 78 | if err != nil { 79 | log.Error("Start failed: %v", err) 80 | } 81 | defer g.Stop() 82 | 83 | time.Sleep(time.Second / 10) 84 | 85 | quit := make(chan os.Signal) 86 | signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) 87 | <-quit 88 | } 89 | 90 | var handler = arpc.NewHandler() 91 | 92 | // Session . 93 | type Session struct { 94 | Client *arpc.Client 95 | Buffer []byte 96 | } 97 | 98 | func onOpen(c *nbio.Conn) { 99 | client := &arpc.Client{Conn: c, Codec: codec.DefaultCodec, Handler: handler} 100 | session := &Session{ 101 | Client: client, 102 | Buffer: nil, 103 | } 104 | c.SetSession(session) 105 | } 106 | 107 | func onData(c *nbio.Conn, data []byte) { 108 | iSession := c.Session() 109 | if iSession == nil { 110 | c.Close() 111 | return 112 | } 113 | session := iSession.(*Session) 114 | session.Buffer = append(session.Buffer, data...) 115 | for len(session.Buffer) >= arpc.HeadLen { 116 | headBuf := session.Buffer[:4] 117 | header := arpc.Header(headBuf) 118 | if len(session.Buffer) < arpc.HeadLen+header.BodyLen() { 119 | return 120 | } 121 | 122 | msg := &arpc.Message{Buffer: session.Buffer[:arpc.HeadLen+header.BodyLen()]} 123 | session.Buffer = session.Buffer[arpc.HeadLen+header.BodyLen():] 124 | handler.OnMessage(session.Client, msg) 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /runner/runner.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "errors" 21 | "sync" 22 | "sync/atomic" 23 | "time" 24 | 25 | "github.com/cloudwego/kitex/pkg/kerrors" 26 | "github.com/cloudwego/kitex/pkg/klog" 27 | "github.com/juju/ratelimit" 28 | ) 29 | 30 | // 为了流量更均匀, 时间间隔设置为 10ms 31 | const window = 10 * time.Millisecond 32 | 33 | // 单次测试 34 | type RunOnce func() error 35 | 36 | type Runner struct { 37 | counters []*Counter // 计数器 38 | timer Timer // 计时器 39 | } 40 | 41 | func NewRunner() *Runner { 42 | r := &Runner{} 43 | if qps == 0 { 44 | r.timer = NewTimer(time.Microsecond) 45 | } else { 46 | r.timer = NewTimer(0) 47 | } 48 | return r 49 | } 50 | 51 | func (r *Runner) benching(onceFn RunOnce, concurrent, qps int, duration int64) { 52 | var wg sync.WaitGroup 53 | wg.Add(concurrent) 54 | r.counters = nil 55 | var qpsLimiter *ratelimit.Bucket 56 | if qps > 0 { 57 | qpsLimiter = ratelimit.NewBucketWithRate(float64(qps), int64(concurrent)) 58 | } 59 | var stopped uint32 60 | time.AfterFunc(time.Duration(duration)*time.Second, func() { 61 | atomic.StoreUint32(&stopped, 1) 62 | }) 63 | for i := 0; i < concurrent; i++ { 64 | c := NewCounter() 65 | r.counters = append(r.counters, c) 66 | go func(c *Counter) { 67 | defer wg.Done() 68 | for { 69 | if atomic.LoadUint32(&stopped) == 1 { 70 | break 71 | } 72 | if qpsLimiter != nil { 73 | qpsLimiter.Wait(1) 74 | } 75 | begin := r.timer.Now() 76 | err := onceFn() 77 | end := r.timer.Now() 78 | if err != nil { 79 | if errors.Is(err, kerrors.ErrCircuitBreak) { 80 | klog.Warnf("No.%d request failed: %v, circuit break happens, stop test!", c.Total, err) 81 | break 82 | } 83 | klog.Warnf("No.%d request failed: %v", c.Total, err) 84 | } 85 | cost := end - begin 86 | c.AddRecord(err, cost) 87 | } 88 | }(c) 89 | } 90 | wg.Wait() 91 | } 92 | 93 | func (r *Runner) Warmup(onceFn RunOnce, concurrent, qps int, duration int64) { 94 | r.benching(onceFn, concurrent, qps, duration) 95 | } 96 | 97 | // 并发测试 98 | func (r *Runner) Run(title string, onceFn RunOnce, concurrent, qps int, duration int64, echoSize, sleepTime int) { 99 | logInfo( 100 | "%s start benching [%s], concurrent: %d, qps: %d, duration: %ds, sleep: %d", 101 | "["+title+"]", time.Now().String(), concurrent, qps, duration, sleepTime, 102 | ) 103 | 104 | start := r.timer.Now() 105 | r.benching(onceFn, concurrent, qps, duration) 106 | stop := r.timer.Now() 107 | totalCounter := NewCounter() 108 | for _, c := range r.counters { 109 | totalCounter.Total += c.Total 110 | totalCounter.Failed += c.Failed 111 | totalCounter.costs = append(totalCounter.costs, c.costs...) 112 | } 113 | totalCounter.Report(title, stop-start, concurrent, duration, echoSize) 114 | } 115 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | ## Your First Pull Request 4 | We use github for our codebase. You can start by reading [How To Pull Request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests). 5 | 6 | ## Without Semantic Versioning 7 | We keep the stable code in branch `main` like `golang.org/x`. Development base on branch `develop`. And we promise the **Forward Compatibility** by adding new package directory with suffix `v2/v3` when code has break changes. 8 | 9 | ## Branch Organization 10 | We use [git-flow](https://nvie.com/posts/a-successful-git-branching-model/) as our branch organization, as known as [FDD](https://en.wikipedia.org/wiki/Feature-driven_development) 11 | 12 | ## Bugs 13 | ### 1. How to Find Known Issues 14 | We are using [Github Issues](https://github.com/cloudwego/kitex/issues) for our public bugs. We keep a close eye on this and try to make it clear when we have an internal fix in progress. Before filing a new task, try to make sure your problem doesn’t already exist. 15 | 16 | ### 2. Reporting New Issues 17 | Providing a reduced test code is a recommended way for reporting issues. Then can placed in: 18 | - Just in issues 19 | - [Golang Playground](https://play.golang.org/) 20 | 21 | ### 3. Security Bugs 22 | Please do not report the safe disclosure of bugs to public issues. Contact us by [Support Email](mailto:conduct@cloudwego.io) 23 | 24 | ## How to Get in Touch 25 | - [Email](mailto:conduct@cloudwego.io) 26 | 27 | ## Submit a Pull Request 28 | Before you submit your Pull Request (PR) consider the following guidelines: 29 | 1. Search [GitHub](https://github.com/cloudwego/kitex/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate existing efforts. 30 | 2. Be sure that an issue describes the problem you're fixing, or documents the design for the feature you'd like to add. Discussing the design upfront helps to ensure that we're ready to accept your work. 31 | 3. [Fork](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo) the cloudwego/kitex repo. 32 | 4. In your forked repository, make your changes in a new git branch: 33 | ``` 34 | git checkout -b my-fix-branch develop 35 | ``` 36 | 5. Create your patch, including appropriate test cases. 37 | 6. Follow our [Style Guides](#code-style-guides). 38 | 7. Commit your changes using a descriptive commit message that follows [AngularJS Git Commit Message Conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit). 39 | Adherence to these conventions is necessary because release notes are automatically generated from these messages. 40 | 8. Push your branch to GitHub: 41 | ``` 42 | git push origin my-fix-branch 43 | ``` 44 | 9. In GitHub, send a pull request to `kitex:develop` 45 | 46 | ## Contribution Prerequisites 47 | - Our development environment keeps up with [Go Official](https://golang.org/project/). 48 | - You need fully checking with lint tools before submit your pull request. [gofmt](https://golang.org/pkg/cmd/gofmt/) and [golangci-lint](https://github.com/golangci/golangci-lint) 49 | - You are familiar with [Github](https://github.com) 50 | - Maybe you need familiar with [Actions](https://github.com/features/actions)(our default workflow tool). 51 | 52 | ## Code Style Guides 53 | Also see [Pingcap General advice](https://pingcap.github.io/style-guide/general.html). 54 | 55 | Good resources: 56 | - [Effective Go](https://golang.org/doc/effective_go) 57 | - [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments) 58 | - [Uber Go Style Guide](https://github.com/uber-go/guide/blob/master/style.md) 59 | -------------------------------------------------------------------------------- /runner/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package runner 18 | 19 | import ( 20 | "flag" 21 | "fmt" 22 | "log" 23 | "strconv" 24 | 25 | "github.com/cloudwego/kitex-benchmark/perf" 26 | ) 27 | 28 | var ( 29 | address string 30 | echoSize int 31 | method string 32 | duration int64 33 | concurrent int 34 | qps int 35 | poolSize int 36 | sleepTime int 37 | warmup int64 38 | ) 39 | 40 | type Options struct { 41 | Address string 42 | Body []byte 43 | PoolSize int 44 | } 45 | 46 | type ClientNewer func(opt *Options) Client 47 | 48 | type Client interface { 49 | // Send implement client's custom RPC call logic 50 | Send(method, action, msg string) (err error) 51 | } 52 | 53 | type Response struct { 54 | Action string 55 | Msg string 56 | } 57 | 58 | func initFlags() { 59 | flag.StringVar(&address, "addr", "127.0.0.1:8000", "client call address") 60 | flag.StringVar(&method, "method", "echo", "RPC method in (echo, echoComplex)") 61 | flag.IntVar(&echoSize, "b", 1024, "echo size once") 62 | flag.IntVar(&concurrent, "c", 100, "call concurrent") 63 | flag.IntVar(&qps, "qps", 0, "call qps") 64 | flag.Int64Var(&duration, "t", 60, "call duration, in seconds") 65 | flag.IntVar(&poolSize, "pool", 10, "conn poll size") 66 | flag.IntVar(&sleepTime, "sleep", 0, "sleep time for every request handler") 67 | flag.Int64Var(&warmup, "warmup", 2, "warmup time before benching, in seconds") 68 | flag.Parse() 69 | } 70 | 71 | func Main(name string, newer ClientNewer) { 72 | initFlags() 73 | 74 | // start pprof server 75 | go func() { 76 | err := perf.ServeMonitor(":18888") 77 | if err != nil { 78 | fmt.Printf("perf monitor server start failed: %v\n", err) 79 | } else { 80 | fmt.Printf("perf monitor server start success\n") 81 | } 82 | }() 83 | 84 | r := NewRunner() 85 | 86 | opt := &Options{ 87 | Address: address, 88 | PoolSize: poolSize, 89 | } 90 | cli := newer(opt) 91 | payload := string(make([]byte, echoSize)) 92 | action := EchoAction 93 | if sleepTime > 0 { 94 | action = SleepAction 95 | st := strconv.Itoa(sleepTime) 96 | payload = fmt.Sprintf("%s,%s", st, payload[len(st)+1:]) 97 | } 98 | handler := func() error { return cli.Send(method, action, payload) } 99 | 100 | // === warming === 101 | r.Warmup(handler, concurrent, qps, warmup) 102 | 103 | // === beginning === 104 | if err := cli.Send(method, BeginAction, "empty"); err != nil { 105 | log.Fatalf("beginning server failed: %v", err) 106 | } 107 | recorder := perf.NewRecorder(fmt.Sprintf("%s@Client", name)) 108 | recorder.Begin() 109 | 110 | // === benching === 111 | r.Run(name, handler, concurrent, qps, duration, echoSize, sleepTime) 112 | 113 | // == ending === 114 | recorder.End() 115 | if err := cli.Send(method, EndAction, "empty"); err != nil { 116 | log.Fatalf("ending server failed: %v", err) 117 | } 118 | 119 | // === reporting === 120 | recorder.Report() // report client 121 | fmt.Printf("\n\n") 122 | } 123 | -------------------------------------------------------------------------------- /generic/binary/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2025 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "sync" 22 | "time" 23 | 24 | "github.com/cloudwego/gopkg/protocol/thrift" 25 | "github.com/cloudwego/kitex/client" 26 | "github.com/cloudwego/kitex/client/genericclient" 27 | "github.com/cloudwego/kitex/pkg/connpool" 28 | "github.com/cloudwego/kitex/pkg/generic" 29 | "github.com/cloudwego/kitex/pkg/transmeta" 30 | "github.com/cloudwego/kitex/transport" 31 | 32 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | var ( 37 | subMsg1 = &echo.SubMessage{ 38 | Id: &(&struct{ x int64 }{int64(123)}).x, 39 | Value: &(&struct{ x string }{"hello"}).x, 40 | } 41 | subMsg2 = &echo.SubMessage{ 42 | Id: &(&struct{ x int64 }{int64(321)}).x, 43 | Value: &(&struct{ x string }{"world"}).x, 44 | } 45 | msg1 = &echo.Message{ 46 | Id: &(&struct{ x int64 }{int64(123)}).x, 47 | Value: &(&struct{ x string }{"hello"}).x, 48 | SubMessages: []*echo.SubMessage{subMsg1, subMsg2}, 49 | } 50 | msg2 = &echo.Message{ 51 | Id: &(&struct{ x int64 }{int64(321)}).x, 52 | Value: &(&struct{ x string }{"world"}).x, 53 | SubMessages: []*echo.SubMessage{subMsg2, subMsg1}, 54 | } 55 | ) 56 | 57 | func NewGenericBinaryClient(opt *runner.Options) runner.Client { 58 | cli := &genericBinaryClient{} 59 | var err error 60 | cli.client, err = genericclient.NewClient("test.echo.kitex", generic.BinaryThriftGenericV2("EchoServer"), 61 | client.WithTransportProtocol(transport.TTHeader), 62 | client.WithHostPorts(opt.Address), 63 | client.WithMetaHandler(transmeta.ClientTTHeaderHandler), 64 | client.WithLongConnection( 65 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 66 | ) 67 | if err != nil { 68 | panic(err) 69 | } 70 | cli.reqPool = &sync.Pool{ 71 | New: func() interface{} { 72 | return &echo.ComplexRequest{ 73 | MsgMap: map[string]*echo.SubMessage{ 74 | "v1": subMsg1, 75 | "v2": subMsg2, 76 | }, 77 | SubMsgs: []*echo.SubMessage{subMsg1, subMsg2}, 78 | MsgSet: []*echo.Message{msg1, msg2}, 79 | FlagMsg: msg1, 80 | } 81 | }, 82 | } 83 | return cli 84 | } 85 | 86 | type genericBinaryClient struct { 87 | client genericclient.Client 88 | reqPool *sync.Pool 89 | } 90 | 91 | func (cli *genericBinaryClient) Send(method, action, msg string) error { 92 | ctx := context.Background() 93 | req := cli.reqPool.Get().(*echo.ComplexRequest) 94 | defer cli.reqPool.Put(req) 95 | 96 | req.Action = action 97 | req.Msg = msg 98 | 99 | args := &echo.EchoServerEchoComplexArgs{ 100 | Req: req, 101 | } 102 | reply, err := cli.client.GenericCall(ctx, "EchoComplex", thrift.FastMarshal(args)) 103 | if reply != nil { 104 | result := &echo.EchoServerEchoComplexResult{} 105 | if err = thrift.FastUnmarshal(reply.([]byte), result); err != nil { 106 | return err 107 | } 108 | runner.ProcessResponse(result.Success.Action, result.Success.Msg) 109 | } 110 | return err 111 | } 112 | -------------------------------------------------------------------------------- /thrift/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package thrift 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "strconv" 23 | "strings" 24 | "sync" 25 | 26 | "github.com/bytedance/gopkg/lang/fastrand" 27 | "github.com/cloudwego/kitex-tests/pkg/utils" 28 | 29 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 30 | "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo/echoserver" 31 | "github.com/cloudwego/kitex-benchmark/runner" 32 | ) 33 | 34 | type kitexClient struct { 35 | client echoserver.Client 36 | } 37 | 38 | func NewKitexClient(client echoserver.Client) *kitexClient { 39 | c := new(kitexClient) 40 | c.client = client 41 | return c 42 | } 43 | 44 | func (cli *kitexClient) Send(method, action, msg string) error { 45 | switch strings.ToLower(method) { 46 | case "echo": 47 | return cli.echo(action, msg) 48 | case "echocomplex": 49 | return cli.echoComplex(action, msg) 50 | default: 51 | return fmt.Errorf("unknown method: %s", method) 52 | } 53 | } 54 | 55 | var echoReqPool = sync.Pool{ 56 | New: func() interface{} { 57 | return &echo.Request{} 58 | }, 59 | } 60 | 61 | func (cli *kitexClient) echo(action, msg string) error { 62 | ctx := context.Background() 63 | req := echoReqPool.Get().(*echo.Request) 64 | defer echoReqPool.Put(req) 65 | 66 | req.Action = action 67 | req.Msg = msg 68 | 69 | reply, err := cli.client.Echo(ctx, req) 70 | if reply != nil { 71 | runner.ProcessResponse(reply.Action, reply.Msg) 72 | } 73 | return err 74 | } 75 | 76 | var echoComplexReqPool = sync.Pool{ 77 | New: func() interface{} { 78 | return &echo.ComplexRequest{} 79 | }, 80 | } 81 | 82 | func (cli *kitexClient) echoComplex(action, msg string) error { 83 | req := createComplexRequest(action, msg) 84 | 85 | reply, err := cli.client.EchoComplex(context.Background(), req) 86 | if reply != nil { 87 | runner.ProcessResponse(reply.Action, reply.Msg) 88 | } 89 | return err 90 | } 91 | 92 | func createComplexRequest(action, msg string) *echo.ComplexRequest { 93 | req := echoComplexReqPool.Get().(*echo.ComplexRequest) 94 | defer echoComplexReqPool.Put(req) 95 | 96 | id := int64(fastrand.Int31n(100)) 97 | smallSubMsg := &echo.SubMessage{ 98 | Id: &id, 99 | Value: ptr(utils.RandomString(10)), 100 | } 101 | subMsg1K := &echo.SubMessage{ 102 | Id: &id, 103 | Value: ptr(utils.RandomString(1024)), 104 | } 105 | 106 | subMsgList2Items := []*echo.SubMessage{smallSubMsg, smallSubMsg} 107 | 108 | message := &echo.Message{ 109 | Id: &id, 110 | Value: ptr(utils.RandomString(1024)), 111 | SubMessages: subMsgList2Items, 112 | } 113 | 114 | msgMap := make(map[string]*echo.SubMessage) 115 | for i := 0; i < 5; i++ { 116 | msgMap[strconv.Itoa(i)] = subMsg1K 117 | } 118 | 119 | subMsgList100Items := make([]*echo.SubMessage, 100) 120 | for i := 0; i < len(subMsgList100Items); i++ { 121 | subMsgList100Items[i] = smallSubMsg 122 | } 123 | 124 | req.Action = action 125 | req.Msg = msg 126 | req.MsgMap = msgMap 127 | req.SubMsgs = subMsgList100Items 128 | req.MsgSet = []*echo.Message{message} 129 | req.FlagMsg = message 130 | 131 | return req 132 | } 133 | 134 | func ptr[T any](v T) *T { return &v } 135 | -------------------------------------------------------------------------------- /codec/thrift/kitex_gen/echo/echoserver/echoserver.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.12.3. DO NOT EDIT. 2 | 3 | package echoserver 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | echo "github.com/cloudwego/kitex-benchmark/codec/thrift/kitex_gen/echo" 9 | client "github.com/cloudwego/kitex/client" 10 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 11 | ) 12 | 13 | var errInvalidMessageType = errors.New("invalid message type for service method handler") 14 | 15 | var serviceMethods = map[string]kitex.MethodInfo{ 16 | "Echo": kitex.NewMethodInfo( 17 | echoHandler, 18 | newEchoServerEchoArgs, 19 | newEchoServerEchoResult, 20 | false, 21 | kitex.WithStreamingMode(kitex.StreamingNone), 22 | ), 23 | "EchoComplex": kitex.NewMethodInfo( 24 | echoComplexHandler, 25 | newEchoServerEchoComplexArgs, 26 | newEchoServerEchoComplexResult, 27 | false, 28 | kitex.WithStreamingMode(kitex.StreamingNone), 29 | ), 30 | } 31 | 32 | var ( 33 | echoServerServiceInfo = NewServiceInfo() 34 | ) 35 | 36 | // for server 37 | func serviceInfo() *kitex.ServiceInfo { 38 | return echoServerServiceInfo 39 | } 40 | 41 | // NewServiceInfo creates a new ServiceInfo 42 | func NewServiceInfo() *kitex.ServiceInfo { 43 | return newServiceInfo() 44 | } 45 | 46 | func newServiceInfo() *kitex.ServiceInfo { 47 | serviceName := "EchoServer" 48 | handlerType := (*echo.EchoServer)(nil) 49 | extra := map[string]interface{}{ 50 | "PackageName": "echo", 51 | } 52 | svcInfo := &kitex.ServiceInfo{ 53 | ServiceName: serviceName, 54 | HandlerType: handlerType, 55 | Methods: serviceMethods, 56 | PayloadCodec: kitex.Thrift, 57 | KiteXGenVersion: "v0.12.3", 58 | Extra: extra, 59 | } 60 | return svcInfo 61 | } 62 | 63 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 64 | realArg := arg.(*echo.EchoServerEchoArgs) 65 | realResult := result.(*echo.EchoServerEchoResult) 66 | success, err := handler.(echo.EchoServer).Echo(ctx, realArg.Req) 67 | if err != nil { 68 | return err 69 | } 70 | realResult.Success = success 71 | return nil 72 | } 73 | 74 | func newEchoServerEchoArgs() interface{} { 75 | return echo.NewEchoServerEchoArgs() 76 | } 77 | 78 | func newEchoServerEchoResult() interface{} { 79 | return echo.NewEchoServerEchoResult() 80 | } 81 | 82 | func echoComplexHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 83 | realArg := arg.(*echo.EchoServerEchoComplexArgs) 84 | realResult := result.(*echo.EchoServerEchoComplexResult) 85 | success, err := handler.(echo.EchoServer).EchoComplex(ctx, realArg.Req) 86 | if err != nil { 87 | return err 88 | } 89 | realResult.Success = success 90 | return nil 91 | } 92 | 93 | func newEchoServerEchoComplexArgs() interface{} { 94 | return echo.NewEchoServerEchoComplexArgs() 95 | } 96 | 97 | func newEchoServerEchoComplexResult() interface{} { 98 | return echo.NewEchoServerEchoComplexResult() 99 | } 100 | 101 | type kClient struct { 102 | c client.Client 103 | sc client.Streaming 104 | } 105 | 106 | func newServiceClient(c client.Client) *kClient { 107 | return &kClient{ 108 | c: c, 109 | sc: c.(client.Streaming), 110 | } 111 | } 112 | 113 | func (p *kClient) Echo(ctx context.Context, req *echo.Request) (r *echo.Response, err error) { 114 | var _args echo.EchoServerEchoArgs 115 | _args.Req = req 116 | var _result echo.EchoServerEchoResult 117 | if err = p.c.Call(ctx, "Echo", &_args, &_result); err != nil { 118 | return 119 | } 120 | return _result.GetSuccess(), nil 121 | } 122 | 123 | func (p *kClient) EchoComplex(ctx context.Context, req *echo.ComplexRequest) (r *echo.ComplexResponse, err error) { 124 | var _args echo.EchoServerEchoComplexArgs 125 | _args.Req = req 126 | var _result echo.EchoServerEchoComplexResult 127 | if err = p.c.Call(ctx, "EchoComplex", &_args, &_result); err != nil { 128 | return 129 | } 130 | return _result.GetSuccess(), nil 131 | } 132 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/echo/echo.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | 3 | package echo 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 9 | client "github.com/cloudwego/kitex/client" 10 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 11 | proto "github.com/cloudwego/prutal" 12 | ) 13 | 14 | var errInvalidMessageType = errors.New("invalid message type for service method handler") 15 | 16 | var serviceMethods = map[string]kitex.MethodInfo{ 17 | "echo": kitex.NewMethodInfo( 18 | echoHandler, 19 | newEchoArgs, 20 | newEchoResult, 21 | false, 22 | kitex.WithStreamingMode(kitex.StreamingUnary), 23 | ), 24 | } 25 | 26 | var ( 27 | echoServiceInfo = NewServiceInfo() 28 | ) 29 | 30 | // for server 31 | func serviceInfo() *kitex.ServiceInfo { 32 | return echoServiceInfo 33 | } 34 | 35 | // NewServiceInfo creates a new ServiceInfo 36 | func NewServiceInfo() *kitex.ServiceInfo { 37 | return newServiceInfo() 38 | } 39 | 40 | func newServiceInfo() *kitex.ServiceInfo { 41 | serviceName := "Echo" 42 | handlerType := (*echo.Echo)(nil) 43 | extra := map[string]interface{}{ 44 | "PackageName": "protobuf", 45 | } 46 | svcInfo := &kitex.ServiceInfo{ 47 | ServiceName: serviceName, 48 | HandlerType: handlerType, 49 | Methods: serviceMethods, 50 | PayloadCodec: kitex.Protobuf, 51 | KiteXGenVersion: "v0.14.1", 52 | Extra: extra, 53 | } 54 | return svcInfo 55 | } 56 | 57 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 58 | s := arg.(*EchoArgs) 59 | success, err := handler.(echo.Echo).Echo(ctx, s.Req) 60 | if err != nil { 61 | return err 62 | } 63 | realResult := result.(*EchoResult) 64 | realResult.Success = success 65 | return nil 66 | } 67 | 68 | func newEchoArgs() interface{} { 69 | return &EchoArgs{} 70 | } 71 | 72 | func newEchoResult() interface{} { 73 | return &EchoResult{} 74 | } 75 | 76 | type EchoArgs struct { 77 | Req *echo.Request 78 | } 79 | 80 | func (p *EchoArgs) Marshal(out []byte) ([]byte, error) { 81 | if !p.IsSetReq() { 82 | return out, nil 83 | } 84 | return proto.Marshal(p.Req) 85 | } 86 | 87 | func (p *EchoArgs) Unmarshal(in []byte) error { 88 | msg := new(echo.Request) 89 | if err := proto.Unmarshal(in, msg); err != nil { 90 | return err 91 | } 92 | p.Req = msg 93 | return nil 94 | } 95 | 96 | var EchoArgs_Req_DEFAULT *echo.Request 97 | 98 | func (p *EchoArgs) GetReq() *echo.Request { 99 | if !p.IsSetReq() { 100 | return EchoArgs_Req_DEFAULT 101 | } 102 | return p.Req 103 | } 104 | 105 | func (p *EchoArgs) IsSetReq() bool { 106 | return p.Req != nil 107 | } 108 | 109 | func (p *EchoArgs) GetFirstArgument() interface{} { 110 | return p.Req 111 | } 112 | 113 | type EchoResult struct { 114 | Success *echo.Response 115 | } 116 | 117 | var EchoResult_Success_DEFAULT *echo.Response 118 | 119 | func (p *EchoResult) Marshal(out []byte) ([]byte, error) { 120 | if !p.IsSetSuccess() { 121 | return out, nil 122 | } 123 | return proto.Marshal(p.Success) 124 | } 125 | 126 | func (p *EchoResult) Unmarshal(in []byte) error { 127 | msg := new(echo.Response) 128 | if err := proto.Unmarshal(in, msg); err != nil { 129 | return err 130 | } 131 | p.Success = msg 132 | return nil 133 | } 134 | 135 | func (p *EchoResult) GetSuccess() *echo.Response { 136 | if !p.IsSetSuccess() { 137 | return EchoResult_Success_DEFAULT 138 | } 139 | return p.Success 140 | } 141 | 142 | func (p *EchoResult) SetSuccess(x interface{}) { 143 | p.Success = x.(*echo.Response) 144 | } 145 | 146 | func (p *EchoResult) IsSetSuccess() bool { 147 | return p.Success != nil 148 | } 149 | 150 | func (p *EchoResult) GetResult() interface{} { 151 | return p.Success 152 | } 153 | 154 | type kClient struct { 155 | c client.Client 156 | sc client.Streaming 157 | } 158 | 159 | func newServiceClient(c client.Client) *kClient { 160 | return &kClient{ 161 | c: c, 162 | sc: c.(client.Streaming), 163 | } 164 | } 165 | 166 | func (p *kClient) Echo(ctx context.Context, Req *echo.Request) (r *echo.Response, err error) { 167 | var _args EchoArgs 168 | _args.Req = Req 169 | var _result EchoResult 170 | if err = p.c.Call(ctx, "echo", &_args, &_result); err != nil { 171 | return 172 | } 173 | return _result.GetSuccess(), nil 174 | } 175 | -------------------------------------------------------------------------------- /codec/protobuf/kitex_gen/echo/secho/secho.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.14.1. DO NOT EDIT. 2 | 3 | package secho 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | echo "github.com/cloudwego/kitex-benchmark/codec/protobuf/kitex_gen/echo" 9 | client "github.com/cloudwego/kitex/client" 10 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 11 | streaming "github.com/cloudwego/kitex/pkg/streaming" 12 | proto "github.com/cloudwego/prutal" 13 | ) 14 | 15 | var errInvalidMessageType = errors.New("invalid message type for service method handler") 16 | 17 | var serviceMethods = map[string]kitex.MethodInfo{ 18 | "echo": kitex.NewMethodInfo( 19 | echoHandler, 20 | newEchoArgs, 21 | newEchoResult, 22 | false, 23 | kitex.WithStreamingMode(kitex.StreamingBidirectional), 24 | ), 25 | } 26 | 27 | var ( 28 | sEchoServiceInfo = NewServiceInfo() 29 | ) 30 | 31 | // for server 32 | func serviceInfo() *kitex.ServiceInfo { 33 | return sEchoServiceInfo 34 | } 35 | 36 | // NewServiceInfo creates a new ServiceInfo 37 | func NewServiceInfo() *kitex.ServiceInfo { 38 | return newServiceInfo() 39 | } 40 | 41 | func newServiceInfo() *kitex.ServiceInfo { 42 | serviceName := "SEcho" 43 | handlerType := (*echo.SEcho)(nil) 44 | extra := map[string]interface{}{ 45 | "PackageName": "protobuf", 46 | } 47 | svcInfo := &kitex.ServiceInfo{ 48 | ServiceName: serviceName, 49 | HandlerType: handlerType, 50 | Methods: serviceMethods, 51 | PayloadCodec: kitex.Protobuf, 52 | KiteXGenVersion: "v0.14.1", 53 | Extra: extra, 54 | } 55 | return svcInfo 56 | } 57 | 58 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 59 | st, err := streaming.GetServerStreamFromArg(arg) 60 | if err != nil { 61 | return err 62 | } 63 | stream := streaming.NewBidiStreamingServer[echo.Request, echo.Response](st) 64 | return handler.(echo.SEcho).Echo(ctx, stream) 65 | } 66 | 67 | func newEchoArgs() interface{} { 68 | return &EchoArgs{} 69 | } 70 | 71 | func newEchoResult() interface{} { 72 | return &EchoResult{} 73 | } 74 | 75 | type EchoArgs struct { 76 | Req *echo.Request 77 | } 78 | 79 | func (p *EchoArgs) Marshal(out []byte) ([]byte, error) { 80 | if !p.IsSetReq() { 81 | return out, nil 82 | } 83 | return proto.Marshal(p.Req) 84 | } 85 | 86 | func (p *EchoArgs) Unmarshal(in []byte) error { 87 | msg := new(echo.Request) 88 | if err := proto.Unmarshal(in, msg); err != nil { 89 | return err 90 | } 91 | p.Req = msg 92 | return nil 93 | } 94 | 95 | var EchoArgs_Req_DEFAULT *echo.Request 96 | 97 | func (p *EchoArgs) GetReq() *echo.Request { 98 | if !p.IsSetReq() { 99 | return EchoArgs_Req_DEFAULT 100 | } 101 | return p.Req 102 | } 103 | 104 | func (p *EchoArgs) IsSetReq() bool { 105 | return p.Req != nil 106 | } 107 | 108 | func (p *EchoArgs) GetFirstArgument() interface{} { 109 | return p.Req 110 | } 111 | 112 | type EchoResult struct { 113 | Success *echo.Response 114 | } 115 | 116 | var EchoResult_Success_DEFAULT *echo.Response 117 | 118 | func (p *EchoResult) Marshal(out []byte) ([]byte, error) { 119 | if !p.IsSetSuccess() { 120 | return out, nil 121 | } 122 | return proto.Marshal(p.Success) 123 | } 124 | 125 | func (p *EchoResult) Unmarshal(in []byte) error { 126 | msg := new(echo.Response) 127 | if err := proto.Unmarshal(in, msg); err != nil { 128 | return err 129 | } 130 | p.Success = msg 131 | return nil 132 | } 133 | 134 | func (p *EchoResult) GetSuccess() *echo.Response { 135 | if !p.IsSetSuccess() { 136 | return EchoResult_Success_DEFAULT 137 | } 138 | return p.Success 139 | } 140 | 141 | func (p *EchoResult) SetSuccess(x interface{}) { 142 | p.Success = x.(*echo.Response) 143 | } 144 | 145 | func (p *EchoResult) IsSetSuccess() bool { 146 | return p.Success != nil 147 | } 148 | 149 | func (p *EchoResult) GetResult() interface{} { 150 | return p.Success 151 | } 152 | 153 | type kClient struct { 154 | c client.Client 155 | sc client.Streaming 156 | } 157 | 158 | func newServiceClient(c client.Client) *kClient { 159 | return &kClient{ 160 | c: c, 161 | sc: c.(client.Streaming), 162 | } 163 | } 164 | 165 | func (p *kClient) Echo(ctx context.Context) (SEcho_echoClient, error) { 166 | st, err := p.sc.StreamX(ctx, "echo") 167 | if err != nil { 168 | return nil, err 169 | } 170 | stream := streaming.NewBidiStreamingClient[echo.Request, echo.Response](st) 171 | return stream, nil 172 | } 173 | -------------------------------------------------------------------------------- /generic/http/client/kitex_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 CloudWeGo Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "bytes" 21 | "context" 22 | "fmt" 23 | "net/http" 24 | "time" 25 | 26 | "github.com/cloudwego/kitex/client" 27 | "github.com/cloudwego/kitex/client/genericclient" 28 | "github.com/cloudwego/kitex/pkg/connpool" 29 | "github.com/cloudwego/kitex/pkg/generic" 30 | "github.com/cloudwego/kitex/pkg/transmeta" 31 | "github.com/cloudwego/kitex/transport" 32 | 33 | "github.com/cloudwego/kitex-benchmark/runner" 34 | ) 35 | 36 | var requestData = []byte(` 37 | { 38 | "msgMap":{ 39 | "v1":{ 40 | "id":123, 41 | "value":"hello" 42 | }, 43 | "v2":{ 44 | "id":321, 45 | "value":"world" 46 | } 47 | }, 48 | "subMsgs":[ 49 | { 50 | "id":123, 51 | "value":"hello" 52 | }, 53 | { 54 | "id":321, 55 | "value":"world" 56 | } 57 | ], 58 | "msgSet":[ 59 | { 60 | "id":123, 61 | "value":"hello", 62 | "subMessages":[ 63 | { 64 | "id":123, 65 | "value":"hello" 66 | }, 67 | { 68 | "id":321, 69 | "value":"world" 70 | } 71 | ] 72 | }, 73 | { 74 | "id":321, 75 | "value":"world", 76 | "subMessages":[ 77 | { 78 | "id":321, 79 | "value":"world" 80 | }, 81 | { 82 | "id":123, 83 | "value":"hello" 84 | } 85 | ] 86 | } 87 | ], 88 | "flagMsg":{ 89 | "id":123, 90 | "value":"hello", 91 | "subMessages":[ 92 | { 93 | "id":123, 94 | "value":"hello" 95 | }, 96 | { 97 | "id":321, 98 | "value":"world" 99 | } 100 | ] 101 | } 102 | } 103 | `) 104 | 105 | func NewGenericHTTPClient(opt *runner.Options) runner.Client { 106 | p, err := generic.NewThriftFileProvider("./codec/thrift/echo.thrift") 107 | if err != nil { 108 | panic(err) 109 | } 110 | // 构造http 请求和返回类型的泛化调用 111 | g, err := generic.HTTPThriftGeneric(p) 112 | if err != nil { 113 | panic(err) 114 | } 115 | cli := &genericHTTPClient{} 116 | cli.client, err = genericclient.NewClient("test.echo.kitex", g, 117 | client.WithTransportProtocol(transport.TTHeader), 118 | client.WithHostPorts(opt.Address), 119 | client.WithMetaHandler(transmeta.ClientTTHeaderHandler), 120 | client.WithLongConnection( 121 | connpool.IdleConfig{MaxIdlePerAddress: 1000, MaxIdleGlobal: 1000, MaxIdleTimeout: time.Minute}), 122 | ) 123 | if err != nil { 124 | panic(err) 125 | } 126 | return cli 127 | } 128 | 129 | type genericHTTPClient struct { 130 | client genericclient.Client 131 | } 132 | 133 | func (cli *genericHTTPClient) Send(method, action, msg string) error { 134 | ctx := context.Background() 135 | 136 | url := fmt.Sprintf("http://example.com/echo/complex/%s", action) 137 | httpRequest, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(requestData)) 138 | if err != nil { 139 | return err 140 | } 141 | httpRequest.Header.Set("msg", msg) 142 | 143 | // send the request 144 | customReq, err := generic.FromHTTPRequest(httpRequest) 145 | if err != nil { 146 | return err 147 | } 148 | 149 | reply, err := cli.client.GenericCall(ctx, "", customReq) 150 | if reply != nil { 151 | resp := reply.(*generic.HTTPResponse) 152 | runner.ProcessResponse(resp.Header.Get("action"), resp.Header.Get("msg")) 153 | } 154 | return err 155 | } 156 | -------------------------------------------------------------------------------- /scripts/benchmark_compare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Usage: 4 | # `bash script/benchmark_compare.sh $old $new` 5 | # Where old/new could be branch name, tag or commit hash. For example: 6 | # `bash script/benchmark_compare.sh v0.7.1 develop` 7 | # It will invoke the script/benchmark_$type.sh to run on the two versions of Kitex. 8 | # The $type variable could be "thrift", "grpc" or "pb", as is listed in the `$types` variable below. 9 | # 10 | # When it finishes, the reports are saved under `output/mmdd-HHMM-$type/`. Take `output/0927-1401-thrift` 11 | # as example, you can now run: 12 | # `bash script/compare_result.sh output/0927-1401-thrift` 13 | # to get the difference of two reports. 14 | 15 | cd `dirname $0`/.. 16 | PROJECT_ROOT=`pwd` 17 | 18 | source $PROJECT_ROOT/scripts/util.sh && check_supported_env 19 | 20 | old=$1 21 | new=$2 22 | 23 | if [ -z "$old" -o -z "$new" ]; then 24 | echo "Usage: $0 " 25 | echo " old/new could be branch name, tag or commit hash." 26 | echo " e.g. $0 v1.13.1 develop" 27 | exit 1 28 | fi 29 | 30 | function log_prefix() { 31 | echo -n "[`date '+%Y-%m-%d %H:%M:%S'`] " 32 | } 33 | 34 | function prepare_old() { 35 | git checkout go.mod go.sum 36 | go get -v github.com/cloudwego/kitex@$old 37 | go mod tidy 38 | } 39 | 40 | function prepare_new() { 41 | git checkout go.mod go.sum 42 | go get -v github.com/cloudwego/kitex@$new 43 | go mod tidy 44 | } 45 | 46 | function benchmark() { 47 | ( # use subshell to remove dirty env/variables 48 | build=$1 49 | srp=$2 50 | crp=$2 51 | port=$3 52 | # base 53 | source $PROJECT_ROOT/scripts/base.sh 54 | # build 55 | source $build 56 | # benchmark 57 | for b in ${body[@]}; do 58 | for c in ${concurrent[@]}; do 59 | for q in ${qps[@]}; do 60 | addr="127.0.0.1:${port}" 61 | kill_pid_listening_on_port ${port} 62 | # server start 63 | echo "Starting server [$srp], if failed please check [output/log/nohup.log] for detail." 64 | nohup $cmd_server $output_dir/bin/${srp}_reciever >> $output_dir/log/nohup.log 2>&1 & 65 | sleep 1 66 | echo "Server [$srp] running with [$cmd_server]" 67 | 68 | # run client 69 | echo "Client [$crp] running with [$cmd_client]" 70 | $cmd_client $output_dir/bin/${crp}_bencher -addr="$addr" -b=$b -c=$c -qps=$q -t=$t | $tee_cmd 71 | 72 | # stop server 73 | kill_pid_listening_on_port ${port} 74 | done 75 | done 76 | done 77 | 78 | finish_cmd 79 | ) 80 | } 81 | 82 | function compare() { 83 | type=$1 84 | build=$2 85 | repo=$3 86 | port=$4 87 | mkdir -p $PROJECT_ROOT/output/$report_dir 88 | log_prefix; echo "Begin comparing $type..." 89 | 90 | # old 91 | log_prefix; echo "Benchmark $type @ $old (old)" 92 | export REPORT=$report_dir/old-$type 93 | prepare_old 94 | time benchmark $build $repo $port 95 | 96 | # new 97 | log_prefix; echo "Benchmark $type @ $new (new)" 98 | export REPORT=$report_dir/new-$type 99 | prepare_new 100 | time benchmark $build $repo $port 101 | 102 | log_prefix; echo "End comparing $type..." 103 | } 104 | 105 | report_dir=`date '+%m%d-%H%M'` 106 | 107 | scenarios=( 108 | "thrift $PROJECT_ROOT/scripts/build_thrift.sh kitex 8001" 109 | "thrift-mux $PROJECT_ROOT/scripts/build_thrift.sh kitex-mux 8002" 110 | "protobuf $PROJECT_ROOT/scripts/build_pb.sh kitex 8001" 111 | "grpc-unary $PROJECT_ROOT/scripts/build_grpc.sh kitex 8006" 112 | "grpc-bidi $PROJECT_ROOT/scripts/build_streaming.sh kitex_grpc 8001" 113 | "ttstream-bidi $PROJECT_ROOT/scripts/build_streaming.sh kitex_tts_lconn 8002" 114 | "generic-json $PROJECT_ROOT/scripts/build_generic.sh generic_json 8002" 115 | "generic-map $PROJECT_ROOT/scripts/build_generic.sh generic_map 8003" 116 | # "generic-binary $PROJECT_ROOT/scripts/build_generic.sh generic_binary 8004" 117 | ) 118 | 119 | keys=() 120 | for s in "${scenarios[@]}"; do 121 | IFS=' ' read -r -a value <<< "$s" 122 | compare "${value[0]}" "${value[1]}" "${value[2]}" "${value[3]}" 123 | keys+=("${value[0]}") 124 | done 125 | 126 | key_len=${#keys[@]} 127 | # compare results 128 | $PROJECT_ROOT/scripts/compare_report.sh $PROJECT_ROOT/output/$report_dir $(printf "%s|" "${keys[@]}" | sed 's/|$//') | grep -A $((key_len + 1)) Kind | column -t 129 | 130 | log_prefix; echo "All benchmark finished" 131 | --------------------------------------------------------------------------------