Skip to content

Commit a6cba88

Browse files
committed
asim: generate {TESTNAME}_setup.txt
This commit adds a test setup string which will be outputted to {TESTNAME}_setup.txt. Only the first configuration and first sample are emitted, since the setup should effectively be the same across runs (other than LBRebalancingMode) and duplicating it would add unnecessary runtime churn. One downside is that the scheduled event for LBRebalancingMode will only reflect the first occurrence. If a datadriven test contains multiple evals, the last one wins.
1 parent d66fe7e commit a6cba88

22 files changed

+556
-357
lines changed

pkg/kv/kvserver/asim/event/mutation_event.go

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package event
88
import (
99
"context"
1010
"fmt"
11+
"strings"
1112

1213
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/state"
1314
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/liveness/livenesspb"
@@ -73,7 +74,51 @@ func (se SetSpanConfigEvent) Func() EventFunc {
7374
}
7475

7576
func (se SetSpanConfigEvent) String() string {
76-
return fmt.Sprintf("set span config event with span=%v, config=%v", se.Span, &se.Config)
77+
var buf strings.Builder
78+
voter, nonvoter := se.Config.GetNumVoters(), se.Config.GetNumNonVoters()
79+
var nonvoterStr string
80+
if nonvoter != 0 {
81+
nonvoterStr = fmt.Sprintf(",%dnonvoters", nonvoter)
82+
}
83+
_, _ = fmt.Fprintf(&buf, "[%s,%s): %dvoters%s", se.Span.Key, se.Span.EndKey, voter, nonvoterStr)
84+
85+
printConstraint := func(tag string, constraints []roachpb.ConstraintsConjunction) {
86+
if len(constraints) != 0 {
87+
_, _ = fmt.Fprintf(&buf, "%s", tag)
88+
for _, c := range constraints {
89+
_, _ = fmt.Fprintf(&buf, "{%d:", c.NumReplicas)
90+
for j, constraint := range c.Constraints {
91+
_, _ = fmt.Fprintf(&buf, "%s=%s", constraint.Key, constraint.Value)
92+
if j != len(c.Constraints)-1 {
93+
_, _ = fmt.Fprintf(&buf, ",")
94+
}
95+
}
96+
_, _ = fmt.Fprintf(&buf, "}")
97+
}
98+
_, _ = fmt.Fprintf(&buf, "]")
99+
}
100+
}
101+
printConstraint(" [replicas:", se.Config.Constraints)
102+
printConstraint(" [voters:", se.Config.VoterConstraints)
103+
if len(se.Config.LeasePreferences) != 0 {
104+
_, _ = fmt.Fprint(&buf, " [lease:")
105+
for i, lp := range se.Config.LeasePreferences {
106+
_, _ = fmt.Fprint(&buf, "{")
107+
for j, c := range lp.Constraints {
108+
_, _ = fmt.Fprintf(&buf, "%s=%s", c.Key, c.Value)
109+
if j != len(lp.Constraints)-1 {
110+
_, _ = fmt.Fprintf(&buf, ",")
111+
}
112+
}
113+
_, _ = fmt.Fprintf(&buf, "}")
114+
if i != len(se.Config.LeasePreferences)-1 {
115+
_, _ = fmt.Fprintf(&buf, ">")
116+
}
117+
}
118+
_, _ = fmt.Fprint(&buf, "]")
119+
}
120+
noQuotesBuf := strings.ReplaceAll(buf.String(), "\"", "")
121+
return noQuotesBuf
77122
}
78123

79124
func (ae AddNodeEvent) Func() EventFunc {
@@ -95,7 +140,12 @@ func (ae AddNodeEvent) Func() EventFunc {
95140
}
96141

97142
func (ae AddNodeEvent) String() string {
98-
return fmt.Sprintf("add node event with num_of_stores=%d, locality_string=%s", ae.NumStores, ae.LocalityString)
143+
var buf strings.Builder
144+
_, _ = fmt.Fprintf(&buf, "add node with %d stores", ae.NumStores)
145+
if ae.LocalityString != "" {
146+
_, _ = fmt.Fprintf(&buf, ", locality_string=%s", ae.LocalityString)
147+
}
148+
return buf.String()
99149
}
100150

101151
func (sne SetNodeLivenessEvent) Func() EventFunc {
@@ -108,7 +158,7 @@ func (sne SetNodeLivenessEvent) Func() EventFunc {
108158
}
109159

110160
func (sne SetNodeLivenessEvent) String() string {
111-
return fmt.Sprintf("set node liveness event with nodeID=%d, liveness_status=%v", sne.NodeId, sne.LivenessStatus)
161+
return fmt.Sprintf("set n%d to %v", sne.NodeId, sne.LivenessStatus)
112162
}
113163

114164
func (sce SetCapacityOverrideEvent) Func() EventFunc {
@@ -150,5 +200,5 @@ func (se SetSimulationSettingsEvent) Func() EventFunc {
150200
}
151201

152202
func (se SetSimulationSettingsEvent) String() string {
153-
return fmt.Sprintf("set simulation settings event with key=%s, value=%v", se.Key, se.Value)
203+
return fmt.Sprintf("set %s to %v", se.Key, se.Value)
154204
}

pkg/kv/kvserver/asim/gen/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go_library(
55
srcs = [
66
"event_generator.go",
77
"generator.go",
8+
"printer.go",
89
],
910
importpath = "github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/gen",
1011
visibility = ["//visibility:public"],

pkg/kv/kvserver/asim/gen/generator.go

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type RangeGen interface {
5151
// Generate returns an updated state, given the initial state, seed and
5252
// simulation settings provided. In the updated state, ranges will have been
5353
// created, replicas and leases assigned to stores in the cluster.
54-
Generate(seed int64, settings *config.SimulationSettings, s state.State) state.State
54+
Generate(seed int64, settings *config.SimulationSettings, s state.State) (state.State, string)
5555
String() string
5656
}
5757

@@ -65,11 +65,13 @@ func GenerateSimulation(
6565
settingsGen SettingsGen,
6666
eventGen EventGen,
6767
seed int64,
68+
buf *strings.Builder,
6869
) *asim.Simulator {
6970
settings := settingsGen.Generate(seed)
7071
s := clusterGen.Generate(seed, &settings)
71-
s = rangeGen.Generate(seed, &settings, s)
72+
s, rangeStateStr := rangeGen.Generate(seed, &settings, s)
7273
eventExecutor := eventGen.Generate(seed, &settings)
74+
generateClusterVisualization(buf, s, loadGen, eventGen, rangeStateStr)
7375
return asim.NewSimulator(
7476
duration,
7577
loadGen.Generate(seed, &settings),
@@ -102,8 +104,11 @@ var _ LoadGen = MultiLoad{}
102104

103105
func (ml MultiLoad) String() string {
104106
var str string
105-
for _, load := range ml {
106-
str += fmt.Sprintf("%s\n", load.String())
107+
for i, load := range ml {
108+
if i > 0 {
109+
str += "\n"
110+
}
111+
str += load.String()
107112
}
108113
return str
109114
}
@@ -131,11 +136,36 @@ type BasicLoad struct {
131136
var _ LoadGen = BasicLoad{}
132137

133138
func (bl BasicLoad) String() string {
134-
return fmt.Sprintf(
135-
"basic load with rw_ratio=%0.2f, rate=%0.2f, skewed_access=%t, min_block_size=%d, max_block_size=%d, "+
136-
"min_key=%d, max_key=%d, request_cpu_per_access=%d, raft_cpu_per_write=%d",
137-
bl.RWRatio, bl.Rate, bl.SkewedAccess, bl.MinBlockSize, bl.MaxBlockSize,
138-
bl.MinKey, bl.MaxKey, bl.RequestCPUPerAccess, bl.RaftCPUPerWrite)
139+
var buf strings.Builder
140+
fmt.Fprintf(&buf, "\t[%d,%d): ", bl.MinKey, bl.MaxKey)
141+
if bl.RWRatio == 1 {
142+
_, _ = fmt.Fprint(&buf, "read-only")
143+
} else if bl.RWRatio == 0 {
144+
_, _ = fmt.Fprint(&buf, "write-only")
145+
} else {
146+
_, _ = fmt.Fprintf(&buf, "%d%%r", int(bl.RWRatio*100))
147+
}
148+
if bl.RequestCPUPerAccess > 0 {
149+
_, _ = fmt.Fprint(&buf, " high-cpu")
150+
}
151+
if bl.MinBlockSize > 1 && bl.MaxBlockSize > 1 {
152+
_, _ = fmt.Fprint(&buf, " large-block")
153+
}
154+
_, _ = fmt.Fprint(&buf, " [")
155+
156+
if bl.RequestCPUPerAccess > 0 {
157+
_, _ = fmt.Fprintf(&buf, "%.2fcpu-us/op, ", float64(bl.RequestCPUPerAccess/time.Microsecond.Nanoseconds()))
158+
}
159+
if bl.RaftCPUPerWrite > 0 {
160+
_, _ = fmt.Fprintf(&buf, "%.2fcpu-us/write(raft), ", float64(bl.RaftCPUPerWrite/time.Microsecond.Nanoseconds()))
161+
}
162+
if bl.MinBlockSize == bl.MaxBlockSize {
163+
_, _ = fmt.Fprintf(&buf, "%dB/op, ", bl.MinBlockSize)
164+
} else {
165+
_, _ = fmt.Fprintf(&buf, "%d-%dB/op, ", bl.MinBlockSize, bl.MaxBlockSize)
166+
}
167+
fmt.Fprintf(&buf, "%gops/s]", bl.Rate)
168+
return buf.String()
139169
}
140170

141171
// Generate returns a new list of workload generators where the generator
@@ -184,7 +214,7 @@ func (lc LoadedCluster) Generate(seed int64, settings *config.SimulationSettings
184214
}
185215

186216
func (lc LoadedCluster) String() string {
187-
return fmt.Sprintf("loaded cluster with\n %v", lc.Info)
217+
return fmt.Sprintf("cluster: %s", lc.Info.String())
188218
}
189219

190220
func (lc LoadedCluster) Regions() []state.Region {
@@ -204,11 +234,12 @@ type BasicCluster struct {
204234
func (bc BasicCluster) String() string {
205235
var b strings.Builder
206236
_, _ = fmt.Fprintf(&b,
207-
"basic cluster with nodes=%d, stores_per_node=%d, store_byte_capacity=%d, node_cpu_rate_capacity=%d",
208-
bc.Nodes, bc.StoresPerNode, bc.StoreByteCapacity, bc.NodeCPURateCapacity)
237+
"[nodes: %d, stores_per_node:%d, store_disk_capacity: %dGiB, node_capacity: %dcpu-sec/sec",
238+
bc.Nodes, bc.StoresPerNode, bc.StoreByteCapacity>>30, bc.NodeCPURateCapacity/time.Second.Nanoseconds())
209239
if len(bc.Region) != 0 {
210-
_, _ = fmt.Fprintf(&b, ", region=%v, nodes_per_region=%v", bc.Region, bc.NodesPerRegion)
240+
_, _ = fmt.Fprintf(&b, ", region: %v, nodes_per_region: %v", bc.Region, bc.NodesPerRegion)
211241
}
242+
b.WriteString("]")
212243
return b.String()
213244
}
214245

@@ -325,15 +356,11 @@ type BaseRanges struct {
325356
ReplicaPlacement state.ReplicaPlacement
326357
}
327358

328-
func (b BaseRanges) String() string {
329-
return fmt.Sprintf("ranges=%d, min_key=%d, max_key=%d, replication_factor=%d, bytes=%d", b.Ranges, b.MinKey, b.MaxKey, b.ReplicationFactor, b.Bytes)
330-
}
331-
332359
// GetRangesInfo generates and distributes ranges across stores based on
333360
// PlacementType while using other BaseRanges fields for range configuration.
334361
func (b BaseRanges) GetRangesInfo(
335362
pType PlacementType, numOfStores int, randSource *rand.Rand, weightedRandom []float64,
336-
) state.RangesInfo {
363+
) (state.RangesInfo, string) {
337364
switch pType {
338365
case Even:
339366
return state.RangesInfoEvenDistribution(numOfStores, b.Ranges, b.MinKey, b.MaxKey, b.ReplicationFactor, b.Bytes)
@@ -369,21 +396,24 @@ type BasicRanges struct {
369396
}
370397

371398
func (br BasicRanges) String() string {
372-
return fmt.Sprintf("basic ranges with placement_type=%v, %v", br.PlacementType, br.BaseRanges)
399+
return fmt.Sprintf("[%d,%d): %d(rf=%d), %dMiB",
400+
br.MinKey, br.MaxKey, br.Ranges, br.ReplicationFactor, br.Bytes>>20)
373401
}
374402

375403
// Generate returns an updated simulator state, where the cluster is loaded with
376404
// ranges generated based on the parameters specified in the fields of
377405
// BasicRanges.
378406
func (br BasicRanges) Generate(
379407
seed int64, settings *config.SimulationSettings, s state.State,
380-
) state.State {
408+
) (state.State, string) {
381409
if br.PlacementType == Random || br.PlacementType == WeightedRandom {
382410
panic("BasicRanges generate only uniform or skewed distributions")
383411
}
384-
rangesInfo := br.GetRangesInfo(br.PlacementType, len(s.Stores()), nil, []float64{})
412+
rangesInfo, str := br.GetRangesInfo(br.PlacementType, len(s.Stores()), nil, []float64{})
385413
br.LoadRangeInfo(s, rangesInfo)
386-
return s
414+
var buf strings.Builder
415+
_, _ = fmt.Fprintf(&buf, "\t%s, %s", br, str)
416+
return s, buf.String()
387417
}
388418

389419
// MultiRanges implements the RangeGen interface, supporting multiple
@@ -402,12 +432,18 @@ func (mr MultiRanges) String() string {
402432

403433
func (mr MultiRanges) Generate(
404434
seed int64, settings *config.SimulationSettings, s state.State,
405-
) state.State {
435+
) (state.State, string) {
406436
var rangeInfos []state.RangeInfo
437+
var rangeInfoStrings []string
407438
for _, ranges := range mr {
408-
rangeInfos = append(rangeInfos,
409-
ranges.GetRangesInfo(ranges.PlacementType, len(s.Stores()), nil, []float64{})...)
439+
rangeInfo, rangeInfoStr := ranges.GetRangesInfo(ranges.PlacementType, len(s.Stores()), nil, []float64{})
440+
rangeInfos = append(rangeInfos, rangeInfo...)
441+
rangeInfoStrings = append(rangeInfoStrings, fmt.Sprintf("\t%s, %s", ranges.String(), rangeInfoStr))
410442
}
411443
state.LoadRangeInfo(s, rangeInfos...)
412-
return s
444+
var buf strings.Builder
445+
for _, str := range rangeInfoStrings {
446+
_, _ = fmt.Fprintf(&buf, "%s\n", str)
447+
}
448+
return s, buf.String()
413449
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2023 The Cockroach Authors.
2+
//
3+
// Use of this software is governed by the CockroachDB Software License
4+
// included in the /LICENSE file.
5+
6+
package gen
7+
8+
import (
9+
"fmt"
10+
"strings"
11+
12+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/state"
13+
)
14+
15+
// generateClusterVisualization generates a visualization of the cluster state.
16+
// Example: mma_one_voter_skewed_cpu_skewed_write_setup.txt.
17+
//
18+
// Cluster Set Up
19+
// n1(AU_EAST,AU_EAST_1,0vcpu): {s1}
20+
// n2(AU_EAST,AU_EAST_1,0vcpu): {s2}
21+
// Key Space
22+
// [1,10000): 100(rf=1), 25MiB, [{s1*}:100]
23+
// [10001,20000): 100(rf=1), 25MiB, [{s2*}:100]
24+
// Event
25+
// set LBRebalancingMode to 4
26+
// Workload Set Up
27+
// [1,10000): read-only high-cpu [500.00cpu-us/op, 1B/op, 1000ops/s]
28+
// [10001,20000): write-only large-block [0.00cpu-us/write(raft), 1000B/op, 5000ops/s]
29+
func generateClusterVisualization(
30+
buf *strings.Builder, s state.State, loadGen LoadGen, eventGen EventGen, rangeStateStr string,
31+
) {
32+
if buf == nil {
33+
return
34+
}
35+
_, _ = fmt.Fprintf(buf, "Cluster Set Up\n")
36+
for _, n := range s.Nodes() {
37+
_, _ = fmt.Fprintf(buf, "%v", n)
38+
_, _ = fmt.Fprintf(buf, "\n")
39+
}
40+
_, _ = fmt.Fprintf(buf, "Key Space\n%s", rangeStateStr)
41+
_, _ = fmt.Fprintf(buf, "Event\n%s", eventGen.String())
42+
_, _ = fmt.Fprintf(buf, "Workload Set Up\n%s", loadGen.String())
43+
}

pkg/kv/kvserver/asim/scheduled/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ go_library(
99
importpath = "github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/scheduled",
1010
visibility = ["//visibility:public"],
1111
deps = [
12+
"//pkg/kv/kvserver/asim/config",
1213
"//pkg/kv/kvserver/asim/event",
1314
"//pkg/kv/kvserver/asim/history",
1415
"//pkg/kv/kvserver/asim/state",

pkg/kv/kvserver/asim/scheduled/scheduled_event.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strings"
1111
"time"
1212

13+
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/config"
1314
"github.com/cockroachdb/cockroach/pkg/kv/kvserver/asim/event"
1415
)
1516

@@ -40,8 +41,10 @@ type ScheduledEvent struct {
4041

4142
func (se ScheduledEvent) String() string {
4243
buf := strings.Builder{}
43-
buf.WriteString(fmt.Sprintf("\texecuted at: %s\n", se.At.Format("2006-01-02 15:04:05")))
44-
buf.WriteString(fmt.Sprintf("\t\tevent: %s", se.TargetEvent.String()))
44+
buf.WriteString(fmt.Sprintf("\t%s", se.TargetEvent.String()))
45+
if !se.At.Equal(config.DefaultStartTime) {
46+
buf.WriteString(fmt.Sprintf(" at %s", se.At.Format("15:04:05")))
47+
}
4548
return buf.String()
4649
}
4750

pkg/kv/kvserver/asim/scheduled/scheduled_event_executor.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,17 @@ func newExecutorWithNoEvents() *eventExecutor {
7070
// assertion events.
7171
func (e *eventExecutor) PrintEventSummary() string {
7272
mutationEvents, assertionEvents := 0, 0
73+
var buf strings.Builder
74+
sort.Sort(e.scheduledEvents)
7375
for _, e := range e.scheduledEvents {
76+
_, _ = fmt.Fprintf(&buf, "%v\n", e)
7477
if e.IsMutationEvent() {
7578
mutationEvents++
7679
} else {
7780
assertionEvents++
7881
}
7982
}
80-
return fmt.Sprintf(
81-
"number of mutation events=%d, number of assertion events=%d", mutationEvents, assertionEvents)
83+
return buf.String()
8284
}
8385

8486
// PrintEventsExecuted returns a detailed string representation of executed

pkg/kv/kvserver/asim/state/config_loader.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,8 +283,8 @@ type ClusterInfo struct {
283283

284284
func (c ClusterInfo) String() (s string) {
285285
buf := &strings.Builder{}
286-
for i, r := range c.Regions {
287-
buf.WriteString(fmt.Sprintf("\t\tregion:%s [", r.Name))
286+
for _, r := range c.Regions {
287+
buf.WriteString(fmt.Sprintf("region:%s [", r.Name))
288288
if len(r.Zones) == 0 {
289289
panic(fmt.Sprintf("number of zones within region %s is zero", r.Name))
290290
}
@@ -295,10 +295,10 @@ func (c ClusterInfo) String() (s string) {
295295
}
296296
}
297297
buf.WriteString("]")
298-
if i != len(c.Regions)-1 {
299-
buf.WriteString("\n")
300-
}
298+
buf.WriteString("\n")
301299
}
300+
buf.WriteString(fmt.Sprintf("store_disk_capacity=%d bytes, node_cpu_rate_capacity=%d cpu-ns/sec",
301+
c.StoreDiskCapacityBytes, c.NodeCPURateCapacityNanos))
302302
return buf.String()
303303
}
304304

0 commit comments

Comments
 (0)