Skip to content

Commit 37ed69e

Browse files
authored
Merge pull request #235 from bojand/pace
Load and concurrency control
2 parents 1a641f9 + c115457 commit 37ed69e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+5947
-804
lines changed

.github/workflows/build.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
runs-on: ubuntu-latest
3232
env:
3333
GO111MODULE: on
34-
GOLANGCI_LINT_VERSION: v1.27.0
34+
GOLANGCI_LINT_VERSION: v1.31.0
3535

3636
steps:
3737
- name: Set up Go

.golangci.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,17 @@ issues:
2424
- path: cmd/ghz/main.go
2525
text: "Error return value of `logger.Sync` is not checked"
2626

27+
# sync.once copy in pacer test
28+
- path: load/pacer_test.go
29+
text: "copylocks"
30+
31+
# TODO fix protobuf deprecated
32+
- path: runner/
33+
text: "SA1019: package github.com/golang/protobuf"
34+
35+
# TODO fix protobuf deprecated
36+
- path: protodesc/
37+
text: "SA1019: package github.com/golang/protobuf"
38+
2739
- path: runner/requester.go
2840
text: "SA1019: grpc.WithBalancerName"

Makefile

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ else
3636
OPEN_COVERAGE_HTML :=
3737
endif
3838

39-
#################################################
40-
##### Everything below should not be edited #####
41-
#################################################
42-
4339
# UNAME_OS stores the value of uname -s.
4440
UNAME_OS := $(shell uname -s)
4541
# UNAME_ARCH stores the value of uname -m.
@@ -48,25 +44,16 @@ UNAME_ARCH := $(shell uname -m)
4844
# TMP_BASE is the base directory used for TMP.
4945
# Use TMP and not TMP_BASE as the temporary directory.
5046
TMP_BASE := .tmp
51-
# TMP is the temporary directory used.
52-
# This is based on UNAME_OS and UNAME_ARCH to make sure there are no issues
53-
# switching between platform builds.
54-
TMP := $(TMP_BASE)/$(UNAME_OS)/$(UNAME_ARCH)
55-
# TMP_BIN is where we install binaries for usage during development.
56-
TMP_BIN = $(TMP)/bin
5747
# TMP_COVERAGE is where we store code coverage files.
5848
TMP_COVERAGE := $(TMP_BASE)/coverage
5949

6050
# Run all by default when "make" is invoked.
6151
.DEFAULT_GOAL := all
6252

63-
# Install all the build and lint dependencies
64-
setup:
65-
if [ ! -f $(GOPATH)/bin/tparse ]; then go get github.com/mfridman/tparse; fi;
66-
if [ ! -f $(GOPATH)/bin/goimports ]; then go get golang.org/x/tools/cmd/goimports; fi;
67-
if [ ! -f $(GOPATH)/bin/golangci-lint ]; then curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOPATH)/bin v1.23.8; fi;
68-
go mod download
69-
.PHONY: setup
53+
# Tools
54+
.PHONY: tools
55+
tools:
56+
go generate -tags tools tools/tools.go
7057

7158
# All runs the default lint, test, and code coverage targets.
7259
.PHONY: all
@@ -88,11 +75,12 @@ lint:
8875
test:
8976
go test $(GO_TEST_FLAGS) $(GO_PKGS)
9077

91-
# gofmt and goimports all go files
78+
# Formats using gofmt and goimports all go files
9279
.PHONY: fmt
9380
fmt:
9481
find . -name '*.go' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done
9582

83+
# Build
9684
.PHONY: build
9785
build:
9886
CGO_ENABLED=0 go build --ldflags="-s -w" -o $(DIST_DIR)/ghz ./cmd/ghz/...

README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,31 @@ Flags:
7070
--key= File containing client private key, to present to the server. Must also provide -cert option.
7171
--cname= Server name override when validating TLS certificate - useful for self signed certs.
7272
--skipTLS Skip TLS client verification of the server's certificate chain and host name.
73-
--skipFirst=0 Skip the first X requests from the timing calculations (useful for initial warmup)
7473
--insecure Use plaintext and insecure connection.
7574
--authority= Value to be used as the :authority pseudo-header. Only works if -insecure is used.
76-
-c, --concurrency=50 Number of requests to run concurrently. Total number of requests cannot be smaller than the concurrency level. Default is 50.
75+
--async Make requests asynchronous as soon as possible. Does not wait for request to finish before sending next one.
76+
-r, --rps=0 Requests per second (RPS) rate limit for constant load schedule. Default is no rate limit.
77+
--load-schedule="const" Specifies the load schedule. Options are const, step, or line. Default is const.
78+
--load-start=0 Specifies the RPS load start value for step or line schedules.
79+
--load-step=0 Specifies the load step value or slope value.
80+
--load-end=0 Specifies the load end value for step or line load schedules.
81+
--load-step-duration=0 Specifies the load step duration value for step load schedule.
82+
--load-max-duration=0 Specifies the max load duration value for step or line load schedule.
83+
-c, --concurrency=50 Number of request workers to run concurrently for const concurrency schedule. Default is 50.
84+
--concurrency-schedule="const"
85+
Concurrency change schedule. Options are const, step, or line. Default is const.
86+
--concurrency-start=0 Concurrency start value for step and line concurrency schedules.
87+
--concurrency-end=0 Concurrency end value for step and line concurrency schedules.
88+
--concurrency-step=1 Concurrency step / slope value for step and line concurrency schedules.
89+
--concurrency-step-duration=0
90+
Specifies the concurrency step duration value for step concurrency schedule.
91+
--concurrency-max-duration=0
92+
Specifies the max concurrency adjustment duration value for step or line concurrency schedule.
7793
-n, --total=200 Number of requests to run. Default is 200.
78-
-q, --qps=0 Rate limit, in queries per second (QPS). Default is no rate limit.
7994
-t, --timeout=20s Timeout for each request. Default is 20s, use 0 for infinite.
8095
-z, --duration=0 Duration of application to send requests. When duration is reached, application stops and exits. If duration is specified, n is ignored. Examples: -z 10s -z 3m.
8196
-x, --max-duration=0 Maximum duration of application to send requests with n setting respected. If duration is reached before n requests are completed, application stops and exits. Examples: -x 10s -x 3m.
82-
--duration-stop="close" Specifies how duration stop is reported. Options are close, wait or ignore.
97+
--duration-stop="close" Specifies how duration stop is reported. Options are close, wait or ignore. Default is close.
8398
-d, --data= The call data as stringified JSON. If the value is '@' then the request contents are read from stdin.
8499
-D, --data-file= File path for call data JSON file. Examples: /home/user/file.json or ./file.json.
85100
-b, --binary The call data comes as serialized binary message or multiple count-prefixed messages read from stdin.
@@ -90,6 +105,7 @@ Flags:
90105
--reflect-metadata= Reflect metadata as stringified JSON used only for reflection request.
91106
-o, --output= Output path. If none provided stdout is used.
92107
-O, --format= Output format. One of: summary, csv, json, pretty, html, influx-summary, influx-details. Default is summary.
108+
--skipFirst=0 Skip the first X requests when doing the results tally.
93109
--connections=1 Number of connections to use. Concurrency is distributed evenly among all the connections. Default is 1.
94110
--connect-timeout=10s Connection timeout for the initial connection dial. Default is 10s.
95111
--keepalive=0 Keepalive time duration. Only used if present and above 0.

cmd/ghz/main.go

Lines changed: 152 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ var (
6464
skipVerify = kingpin.Flag("skipTLS", "Skip TLS client verification of the server's certificate chain and host name.").
6565
Default("false").IsSetByUser(&isSkipSet).Bool()
6666

67-
isSkipFirstSet = false
68-
skipFirst = kingpin.Flag("skipFirst", "Skip the first X requests when doing the results tally.").
69-
Default("0").IsSetByUser(&isSkipFirstSet).Uint()
70-
7167
isInsecSet = false
7268
insecure = kingpin.Flag("insecure", "Use plaintext and insecure connection.").
7369
Default("false").IsSetByUser(&isInsecSet).Bool()
@@ -77,18 +73,72 @@ var (
7773
PlaceHolder(" ").IsSetByUser(&isAuthSet).String()
7874

7975
// Run
76+
isAsyncSet = false
77+
async = kingpin.Flag("async", "Make requests asynchronous as soon as possible. Does not wait for request to finish before sending next one.").
78+
Default("false").IsSetByUser(&isAsyncSet).Bool()
79+
80+
isRPSSet = false
81+
rps = kingpin.Flag("rps", "Requests per second (RPS) rate limit for constant load schedule. Default is no rate limit.").
82+
Default("0").Short('r').IsSetByUser(&isRPSSet).Uint()
83+
84+
isScheduleSet = false
85+
schedule = kingpin.Flag("load-schedule", "Specifies the load schedule. Options are const, step, or line. Default is const.").
86+
Default("const").IsSetByUser(&isScheduleSet).String()
87+
88+
isLoadStartSet = false
89+
loadStart = kingpin.Flag("load-start", "Specifies the RPS load start value for step or line schedules.").
90+
Default("0").IsSetByUser(&isLoadStartSet).Uint()
91+
92+
isLoadStepSet = false
93+
loadStep = kingpin.Flag("load-step", "Specifies the load step value or slope value.").
94+
Default("0").IsSetByUser(&isLoadStepSet).Int()
95+
96+
isLoadEndSet = false
97+
loadEnd = kingpin.Flag("load-end", "Specifies the load end value for step or line load schedules.").
98+
Default("0").IsSetByUser(&isLoadEndSet).Uint()
99+
100+
isLoadStepDurSet = false
101+
loadStepDuration = kingpin.Flag("load-step-duration", "Specifies the load step duration value for step load schedule.").
102+
Default("0").IsSetByUser(&isLoadStepDurSet).Duration()
103+
104+
isLoadMaxDurSet = false
105+
loadMaxDuration = kingpin.Flag("load-max-duration", "Specifies the max load duration value for step or line load schedule.").
106+
Default("0").IsSetByUser(&isLoadMaxDurSet).Duration()
107+
108+
// Concurrency
80109
isCSet = false
81-
c = kingpin.Flag("concurrency", "Number of requests to run concurrently. Total number of requests cannot be smaller than the concurrency level. Default is 50.").
110+
c = kingpin.Flag("concurrency", "Number of request workers to run concurrently for const concurrency schedule. Default is 50.").
82111
Short('c').Default("50").IsSetByUser(&isCSet).Uint()
83112

113+
isCScheduleSet = false
114+
cschdule = kingpin.Flag("concurrency-schedule", "Concurrency change schedule. Options are const, step, or line. Default is const.").
115+
Default("const").IsSetByUser(&isCScheduleSet).String()
116+
117+
isCStartSet = false
118+
cStart = kingpin.Flag("concurrency-start", "Concurrency start value for step and line concurrency schedules.").
119+
Default("0").IsSetByUser(&isCStartSet).Uint()
120+
121+
isCEndSet = false
122+
cEnd = kingpin.Flag("concurrency-end", "Concurrency end value for step and line concurrency schedules.").
123+
Default("0").IsSetByUser(&isCEndSet).Uint()
124+
125+
isCStepSet = false
126+
cstep = kingpin.Flag("concurrency-step", "Concurrency step / slope value for step and line concurrency schedules.").
127+
Default("1").IsSetByUser(&isCStepSet).Int()
128+
129+
isCStepDurSet = false
130+
cStepDuration = kingpin.Flag("concurrency-step-duration", "Specifies the concurrency step duration value for step concurrency schedule.").
131+
Default("0").IsSetByUser(&isCStepDurSet).Duration()
132+
133+
isCMaxDurSet = false
134+
cMaxDuration = kingpin.Flag("concurrency-max-duration", "Specifies the max concurrency adjustment duration value for step or line concurrency schedule.").
135+
Default("0").IsSetByUser(&isCMaxDurSet).Duration()
136+
137+
// Other
84138
isNSet = false
85139
n = kingpin.Flag("total", "Number of requests to run. Default is 200.").
86140
Short('n').Default("200").IsSetByUser(&isNSet).Uint()
87141

88-
isQSet = false
89-
q = kingpin.Flag("qps", "Rate limit, in queries per second (QPS). Default is no rate limit.").
90-
Default("0").Short('q').IsSetByUser(&isQSet).Uint()
91-
92142
isTSet = false
93143
t = kingpin.Flag("timeout", "Timeout for each request. Default is 20s, use 0 for infinite.").
94144
Default("20s").Short('t').IsSetByUser(&isTSet).Duration()
@@ -102,7 +152,7 @@ var (
102152
Short('x').Default("0").IsSetByUser(&isXSet).Duration()
103153

104154
isZStopSet = false
105-
zstop = kingpin.Flag("duration-stop", "Specifies how duration stop is reported. Options are close, wait or ignore.").
155+
zstop = kingpin.Flag("duration-stop", "Specifies how duration stop is reported. Options are close, wait or ignore. Default is close.").
106156
Default("close").IsSetByUser(&isZStopSet).String()
107157

108158
// Data
@@ -147,6 +197,10 @@ var (
147197
format = kingpin.Flag("format", "Output format. One of: summary, csv, json, pretty, html, influx-summary, influx-details. Default is summary.").
148198
Short('O').Default("summary").PlaceHolder(" ").IsSetByUser(&isFormatSet).Enum("summary", "csv", "json", "pretty", "html", "influx-summary", "influx-details")
149199

200+
isSkipFirstSet = false
201+
skipFirst = kingpin.Flag("skipFirst", "Skip the first X requests when doing the results tally.").
202+
Default("0").IsSetByUser(&isSkipFirstSet).Uint()
203+
150204
// Connection
151205
isConnSet = false
152206
conns = kingpin.Flag("connections", "Number of connections to use. Concurrency is distributed evenly among all the connections. Default is 1.").
@@ -360,7 +414,7 @@ func createConfigFromArgs(cfg *runner.Config) error {
360414
cfg.CName = *cname
361415
cfg.N = *n
362416
cfg.C = *c
363-
cfg.QPS = *q
417+
cfg.RPS = *rps
364418
cfg.Z = runner.Duration(*z)
365419
cfg.X = runner.Duration(*x)
366420
cfg.Timeout = runner.Duration(*t)
@@ -384,6 +438,19 @@ func createConfigFromArgs(cfg *runner.Config) error {
384438
cfg.ReflectMetadata = rmdMap
385439
cfg.Debug = *debug
386440
cfg.EnableCompression = *enableCompression
441+
cfg.LoadSchedule = *schedule
442+
cfg.LoadStart = *loadStart
443+
cfg.LoadStep = *loadStep
444+
cfg.LoadEnd = *loadEnd
445+
cfg.LoadStepDuration = runner.Duration(*loadStepDuration)
446+
cfg.LoadMaxDuration = runner.Duration(*loadMaxDuration)
447+
cfg.Async = *async
448+
cfg.CSchedule = *cschdule
449+
cfg.CStart = *cStart
450+
cfg.CStep = *cstep
451+
cfg.CEnd = *cEnd
452+
cfg.CStepDuration = runner.Duration(*cStepDuration)
453+
cfg.CMaxDuration = runner.Duration(*cMaxDuration)
387454

388455
return nil
389456
}
@@ -393,6 +460,8 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
393460
return errors.New("config cannot be nil")
394461
}
395462

463+
// proto
464+
396465
if isProtoSet {
397466
dest.Proto = src.Proto
398467
}
@@ -405,6 +474,8 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
405474
dest.Call = src.Call
406475
}
407476

477+
// security
478+
408479
if isCACertSet {
409480
dest.RootCert = src.RootCert
410481
}
@@ -437,18 +508,12 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
437508
dest.CName = src.CName
438509
}
439510

511+
// run
512+
440513
if isNSet {
441514
dest.N = src.N
442515
}
443516

444-
if isCSet {
445-
dest.C = src.C
446-
}
447-
448-
if isQSet {
449-
dest.QPS = src.QPS
450-
}
451-
452517
if isZSet {
453518
dest.Z = src.Z
454519
}
@@ -465,6 +530,8 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
465530
dest.ZStop = src.ZStop
466531
}
467532

533+
// data
534+
468535
if isDataSet {
469536
dest.Data = src.Data
470537
}
@@ -489,6 +556,8 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
489556
dest.MetadataPath = src.MetadataPath
490557
}
491558

559+
// other
560+
492561
if isSISet {
493562
dest.SI = src.SI
494563
}
@@ -541,6 +610,70 @@ func mergeConfig(dest *runner.Config, src *runner.Config) error {
541610
dest.Host = src.Host
542611
}
543612

613+
// load
614+
615+
if isAsyncSet {
616+
dest.Async = src.Async
617+
}
618+
619+
if isRPSSet {
620+
dest.RPS = src.RPS
621+
}
622+
623+
if isScheduleSet {
624+
dest.LoadSchedule = src.LoadSchedule
625+
}
626+
627+
if isLoadStartSet {
628+
dest.LoadStart = src.LoadStart
629+
}
630+
631+
if isLoadStepSet {
632+
dest.LoadStep = src.LoadStep
633+
}
634+
635+
if isLoadEndSet {
636+
dest.LoadEnd = src.LoadEnd
637+
}
638+
639+
if isLoadStepDurSet {
640+
dest.LoadStepDuration = src.LoadStepDuration
641+
}
642+
643+
if isLoadMaxDurSet {
644+
dest.LoadMaxDuration = src.LoadMaxDuration
645+
}
646+
647+
// concurrency
648+
649+
if isCSet {
650+
dest.C = src.C
651+
}
652+
653+
if isCScheduleSet {
654+
dest.CSchedule = src.CSchedule
655+
}
656+
657+
if isCStartSet {
658+
dest.CStart = src.CStart
659+
}
660+
661+
if isCStepSet {
662+
dest.CStep = src.CStep
663+
}
664+
665+
if isCEndSet {
666+
dest.CEnd = src.CEnd
667+
}
668+
669+
if isCStepDurSet {
670+
dest.CStepDuration = src.CStepDuration
671+
}
672+
673+
if isCMaxDurSet {
674+
dest.CMaxDuration = src.CMaxDuration
675+
}
676+
544677
return nil
545678
}
546679

0 commit comments

Comments
 (0)