Skip to content

Commit 982579c

Browse files
craig[bot]knzrafiss
committed
Merge #39685 #40380
39685: workload/tpcc: extend --wait to also support fractions r=danhhz,petermattis a=knz In order to use TPC-C for operational testing (i.e. NOT benchmarking) it is useful to increase the rate of transactions without altogether saturating the TPS capacity (`--wait=false`). For this purpose, this commit extends the syntax accepted by `--wait` to recognize a multiplier which is applied to all wait times. The default is 1.0 (i.e. 100% of the wait time required by a benchmark). The words `true`/`on` and `false`/`off` are aliases for 1.0 and 0.0, respectively 40380: exec: use same decimal context as non-vec r=rafiss a=rafiss Use the same decimal contexts that eval.go uses for decimal arithmetic. based on discussion in #40327 Release note: None Co-authored-by: Raphael 'kena' Poss <[email protected]> Co-authored-by: Rafi Shamim <[email protected]>
3 parents b4caac8 + c6ec74f + caa3207 commit 982579c

File tree

4 files changed

+117
-41
lines changed

4 files changed

+117
-41
lines changed

pkg/sql/exec/execgen/cmd/execgen/overloads.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ var binaryOpDecMethod = map[tree.BinaryOperator]string{
5252
tree.Div: "Quo",
5353
}
5454

55+
var binaryOpDecCtx = map[tree.BinaryOperator]string{
56+
tree.Plus: "ExactCtx",
57+
tree.Minus: "ExactCtx",
58+
tree.Mult: "ExactCtx",
59+
tree.Div: "DecimalCtx",
60+
}
61+
5562
var comparisonOpInfix = map[tree.ComparisonOperator]string{
5663
tree.EQ: "==",
5764
tree.NE: "!=",
@@ -639,22 +646,21 @@ func (decimalCustomizer) getCmpOpCompareFunc() compareFunc {
639646

640647
func (decimalCustomizer) getBinOpAssignFunc() assignFunc {
641648
return func(op overload, target, l, r string) string {
642-
// todo(jordan): should tree.ExactCtx be used here? (#39540)
643649
if op.BinOp == tree.Div {
644650
return fmt.Sprintf(`
645651
{
646-
cond, err := tree.DecimalCtx.%s(&%s, &%s, &%s)
652+
cond, err := tree.%s.%s(&%s, &%s, &%s)
647653
if cond.DivisionByZero() {
648654
execerror.NonVectorizedPanic(tree.ErrDivByZero)
649655
}
650656
if err != nil {
651657
execerror.NonVectorizedPanic(err)
652658
}
653659
}
654-
`, binaryOpDecMethod[op.BinOp], target, l, r)
660+
`, binaryOpDecCtx[op.BinOp], binaryOpDecMethod[op.BinOp], target, l, r)
655661
}
656-
return fmt.Sprintf("if _, err := tree.DecimalCtx.%s(&%s, &%s, &%s); err != nil { execerror.NonVectorizedPanic(err) }",
657-
binaryOpDecMethod[op.BinOp], target, l, r)
662+
return fmt.Sprintf("if _, err := tree.%s.%s(&%s, &%s, &%s); err != nil { execerror.NonVectorizedPanic(err) }",
663+
binaryOpDecCtx[op.BinOp], binaryOpDecMethod[op.BinOp], target, l, r)
658664
}
659665
}
660666

@@ -854,7 +860,7 @@ func (c intCustomizer) getBinOpAssignFunc() assignFunc {
854860
// Note that this is the '/' operator, which has a decimal result.
855861
// TODO(rafi): implement the '//' floor division operator.
856862
// todo(rafi): is there a way to avoid allocating on each operation?
857-
// todo(jordan): should tree.ExactCtx be used here? (#39540)
863+
args["Ctx"] = binaryOpDecCtx[op.BinOp]
858864
t = template.Must(template.New("").Parse(`
859865
{
860866
if {{.Right}} == 0 {
@@ -863,7 +869,7 @@ func (c intCustomizer) getBinOpAssignFunc() assignFunc {
863869
leftTmpDec, rightTmpDec := &apd.Decimal{}, &apd.Decimal{}
864870
leftTmpDec.SetFinite(int64({{.Left}}), 0)
865871
rightTmpDec.SetFinite(int64({{.Right}}), 0)
866-
if _, err := tree.DecimalCtx.Quo(&{{.Target}}, leftTmpDec, rightTmpDec); err != nil {
872+
if _, err := tree.{{.Ctx}}.Quo(&{{.Target}}, leftTmpDec, rightTmpDec); err != nil {
867873
execerror.NonVectorizedPanic(err)
868874
}
869875
}
@@ -924,13 +930,13 @@ func (c decimalIntCustomizer) getBinOpAssignFunc() assignFunc {
924930
return func(op overload, target, l, r string) string {
925931
isDivision := op.BinOp == tree.Div
926932
args := map[string]interface{}{
933+
"Ctx": binaryOpDecCtx[op.BinOp],
927934
"Op": binaryOpDecMethod[op.BinOp],
928935
"IsDivision": isDivision,
929936
"Target": target, "Left": l, "Right": r,
930937
}
931938
buf := strings.Builder{}
932939
// todo(rafi): is there a way to avoid allocating on each operation?
933-
// todo(jordan): should tree.ExactCtx be used here? (#39540)
934940
t := template.Must(template.New("").Parse(`
935941
{
936942
{{ if .IsDivision }}
@@ -940,7 +946,7 @@ func (c decimalIntCustomizer) getBinOpAssignFunc() assignFunc {
940946
{{ end }}
941947
tmpDec := &apd.Decimal{}
942948
tmpDec.SetFinite(int64({{.Right}}), 0)
943-
if _, err := tree.DecimalCtx.{{.Op}}(&{{.Target}}, &{{.Left}}, tmpDec); err != nil {
949+
if _, err := tree.{{.Ctx}}.{{.Op}}(&{{.Target}}, &{{.Left}}, tmpDec); err != nil {
944950
execerror.NonVectorizedPanic(err)
945951
}
946952
}
@@ -997,24 +1003,24 @@ func (c intDecimalCustomizer) getBinOpAssignFunc() assignFunc {
9971003
return func(op overload, target, l, r string) string {
9981004
isDivision := op.BinOp == tree.Div
9991005
args := map[string]interface{}{
1006+
"Ctx": binaryOpDecCtx[op.BinOp],
10001007
"Op": binaryOpDecMethod[op.BinOp],
10011008
"IsDivision": isDivision,
10021009
"Target": target, "Left": l, "Right": r,
10031010
}
10041011
buf := strings.Builder{}
10051012
// todo(rafi): is there a way to avoid allocating on each operation?
1006-
// todo(jordan): should tree.ExactCtx be used here? (#39540)
10071013
t := template.Must(template.New("").Parse(`
10081014
{
10091015
tmpDec := &apd.Decimal{}
10101016
tmpDec.SetFinite(int64({{.Left}}), 0)
10111017
{{ if .IsDivision }}
1012-
cond, err := tree.DecimalCtx.{{.Op}}(&{{.Target}}, tmpDec, &{{.Right}})
1018+
cond, err := tree.{{.Ctx}}.{{.Op}}(&{{.Target}}, tmpDec, &{{.Right}})
10131019
if cond.DivisionByZero() {
10141020
execerror.NonVectorizedPanic(tree.ErrDivByZero)
10151021
}
10161022
{{ else }}
1017-
_, err := tree.DecimalCtx.{{.Op}}(&{{.Target}}, tmpDec, &{{.Right}})
1023+
_, err := tree.{{.Ctx}}.{{.Op}}(&{{.Target}}, tmpDec, &{{.Right}})
10181024
{{ end }}
10191025
if err != nil {
10201026
execerror.NonVectorizedPanic(err)

pkg/sql/logictest/testdata/logic_test/vectorize

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,39 @@ SELECT a/b, a/c, b/c, b/d, c/d FROM intdecfloat
222222
statement ok
223223
RESET vectorize
224224

225+
# vectorized decimal arithmetic
226+
statement ok
227+
CREATE table decimals (a DECIMAL, b DECIMAL)
228+
229+
statement ok
230+
INSERT INTO decimals VALUES(123.0E200, 12.3)
231+
232+
statement ok
233+
SET vectorize = experimental_always
234+
235+
query R
236+
SELECT a*b FROM decimals
237+
----
238+
1.51290E+203
239+
240+
query R
241+
SELECT a/b FROM decimals
242+
----
243+
1.0E+201
244+
245+
query R
246+
SELECT a+b FROM decimals
247+
----
248+
12300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012.3
249+
250+
query R
251+
SELECT a-b FROM decimals
252+
----
253+
12299999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999987.7
254+
255+
statement ok
256+
RESET vectorize
257+
225258
# AND expressions.
226259
query II
227260
SELECT a, b FROM a WHERE a < 2 AND b > 0 AND a * b != 3
@@ -645,14 +678,14 @@ SET tracing = on; SELECT * FROM tpar WHERE a = 0 OR a = 10; SET tracing = off
645678
# tpar, this query will need an adjustment.
646679
query T
647680
SELECT message FROM [SHOW TRACE FOR SESSION] WHERE message IN
648-
('querying next range at /Table/71/1/0',
649-
'querying next range at /Table/71/1/10',
681+
('querying next range at /Table/72/1/0',
682+
'querying next range at /Table/72/1/10',
650683
'=== SPAN START: kv.DistSender: sending partial batch ==='
651684
)
652685
----
653-
querying next range at /Table/71/1/0
686+
querying next range at /Table/72/1/0
654687
=== SPAN START: kv.DistSender: sending partial batch ===
655-
querying next range at /Table/71/1/10
688+
querying next range at /Table/72/1/10
656689

657690
# Test for #38858 -- handle aggregates correctly on an empty table.
658691
statement ok

pkg/workload/tpcc/tpcc.go

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
gosql "database/sql"
1616
"fmt"
1717
"net/url"
18+
"strconv"
1819
"strings"
1920
"sync"
2021
"time"
@@ -48,11 +49,11 @@ type tpcc struct {
4849
// is the value of C for the item id generator. See 2.1.6.
4950
cLoad, cCustomerID, cItemID int
5051

51-
mix string
52-
doWaits bool
53-
workers int
54-
fks bool
55-
dbOverride string
52+
mix string
53+
waitFraction float64
54+
workers int
55+
fks bool
56+
dbOverride string
5657

5758
txInfos []txInfo
5859
// deck contains indexes into the txInfos slice.
@@ -83,6 +84,45 @@ type tpcc struct {
8384
localsPool *sync.Pool
8485
}
8586

87+
type waitSetter struct {
88+
val *float64
89+
}
90+
91+
// Set implements the pflag.Value interface.
92+
func (w *waitSetter) Set(val string) error {
93+
switch strings.ToLower(val) {
94+
case "true", "on":
95+
*w.val = 1.0
96+
case "false", "off":
97+
*w.val = 0.0
98+
default:
99+
f, err := strconv.ParseFloat(val, 64)
100+
if err != nil {
101+
return err
102+
}
103+
if f < 0 {
104+
return errors.New("cannot set --wait to a negative value")
105+
}
106+
*w.val = f
107+
}
108+
return nil
109+
}
110+
111+
// Type implements the pflag.Value interface
112+
func (*waitSetter) Type() string { return "0.0/false - 1.0/true" }
113+
114+
// String implements the pflag.Value interface.
115+
func (w *waitSetter) String() string {
116+
switch *w.val {
117+
case 0:
118+
return "false"
119+
case 1:
120+
return "true"
121+
default:
122+
return fmt.Sprintf("%f", *w.val)
123+
}
124+
}
125+
86126
func init() {
87127
workload.Register(tpccMeta)
88128
}
@@ -127,7 +167,8 @@ var tpccMeta = workload.Meta{
127167
g.flags.StringVar(&g.mix, `mix`,
128168
`newOrder=10,payment=10,orderStatus=1,delivery=1,stockLevel=1`,
129169
`Weights for the transaction mix. The default matches the TPCC spec.`)
130-
g.flags.BoolVar(&g.doWaits, `wait`, true, `Run in wait mode (include think/keying sleeps)`)
170+
g.waitFraction = 1.0
171+
g.flags.Var(&waitSetter{&g.waitFraction}, `wait`, `Wait mode (include think/keying sleeps): 1/true for tpcc-standard wait, 0/false for no waits, other factors also allowed`)
131172
g.flags.StringVar(&g.dbOverride, `db`, ``,
132173
`Override for the SQL database to use. If empty, defaults to the generator name`)
133174
g.flags.IntVar(&g.workers, `workers`, 0, fmt.Sprintf(
@@ -200,15 +241,15 @@ func (w *tpcc) Hooks() workload.Hooks {
200241
// waiting, we only use up to a set number of connections per warehouse.
201242
// This isn't mandated by the spec, but opening a connection per worker
202243
// when they each spend most of their time waiting is wasteful.
203-
if !w.doWaits {
244+
if w.waitFraction == 0 {
204245
w.numConns = w.workers
205246
} else {
206247
w.numConns = w.activeWarehouses * numConnsPerWarehouse
207248
}
208249
}
209250

210-
if w.doWaits && w.workers != w.activeWarehouses*numWorkersPerWarehouse {
211-
return errors.Errorf(`--wait=true and --warehouses=%d requires --workers=%d`,
251+
if w.waitFraction > 0 && w.workers != w.activeWarehouses*numWorkersPerWarehouse {
252+
return errors.Errorf(`--wait > 0 and --warehouses=%d requires --workers=%d`,
212253
w.activeWarehouses, w.warehouses*numWorkersPerWarehouse)
213254
}
214255

pkg/workload/tpcc/worker.go

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,10 @@ func (w *worker) run(ctx context.Context) error {
178178
w.permIdx++
179179

180180
warehouseID := w.warehouse
181-
if w.config.doWaits {
182-
// Wait out the entire keying and think time even if the context is
183-
// expired. This prevents all workers from immediately restarting when
184-
// the workload's ramp period expires, which can overload a cluster.
185-
time.Sleep(time.Duration(txInfo.keyingTime) * time.Second)
186-
}
181+
// Wait out the entire keying and think time even if the context is
182+
// expired. This prevents all workers from immediately restarting when
183+
// the workload's ramp period expires, which can overload a cluster.
184+
time.Sleep(time.Duration(float64(txInfo.keyingTime) * float64(time.Second) * w.config.waitFraction))
187185

188186
// Run transactions with a background context because we don't want to
189187
// cancel them when the context expires. Instead, let them finish normally
@@ -197,16 +195,14 @@ func (w *worker) run(ctx context.Context) error {
197195
w.hists.Get(txInfo.name).Record(elapsed)
198196
}
199197

200-
if w.config.doWaits {
201-
// 5.2.5.4: Think time is taken independently from a negative exponential
202-
// distribution. Think time = -log(r) * u, where r is a uniform random number
203-
// between 0 and 1 and u is the mean think time per operation.
204-
// Each distribution is truncated at 10 times its mean value.
205-
thinkTime := -math.Log(rand.Float64()) * txInfo.thinkTime
206-
if thinkTime > (txInfo.thinkTime * 10) {
207-
thinkTime = txInfo.thinkTime * 10
208-
}
209-
time.Sleep(time.Duration(thinkTime) * time.Second)
198+
// 5.2.5.4: Think time is taken independently from a negative exponential
199+
// distribution. Think time = -log(r) * u, where r is a uniform random number
200+
// between 0 and 1 and u is the mean think time per operation.
201+
// Each distribution is truncated at 10 times its mean value.
202+
thinkTime := -math.Log(rand.Float64()) * txInfo.thinkTime
203+
if thinkTime > (txInfo.thinkTime * 10) {
204+
thinkTime = txInfo.thinkTime * 10
210205
}
206+
time.Sleep(time.Duration(thinkTime * float64(time.Second) * w.config.waitFraction))
211207
return ctx.Err()
212208
}

0 commit comments

Comments
 (0)