├── 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 |
--------------------------------------------------------------------------------