Skip to content

Commit a8db627

Browse files
authored
Testbed improvements (#1161)
* Use atomic wrappers for readability and for preventing accidentally accessing atomic variables non-atomically. * Enhance readability of large numbers in testbed by formatting with thousands separator. * Include rate per second in testbed output.
1 parent 4bf6afb commit a8db627

File tree

10 files changed

+86
-73
lines changed

10 files changed

+86
-73
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ require (
4848
github.com/tcnksm/ghr v0.13.0
4949
github.com/uber/jaeger-lib v2.2.0+incompatible
5050
go.opencensus.io v0.22.3
51+
go.uber.org/atomic v1.5.1
5152
go.uber.org/zap v1.13.0
5253
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
5354
golang.org/x/sys v0.0.0-20200408040146-ea54a3c99b9b
55+
golang.org/x/text v0.3.2
5456
golang.org/x/tools v0.0.0-20200428211428-0c9eba77bc32 // indirect
5557
google.golang.org/api v0.10.0 // indirect
5658
google.golang.org/genproto v0.0.0-20200408120641-fbb3ad325eb7

testbed/testbed/child_process.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ import (
2525
"path"
2626
"path/filepath"
2727
"sync"
28-
"sync/atomic"
2928
"syscall"
3029
"time"
3130

3231
"github.com/shirou/gopsutil/cpu"
3332
"github.com/shirou/gopsutil/process"
33+
"go.uber.org/atomic"
3434
)
3535

3636
// ResourceSpec is a resource consumption specification.
@@ -95,10 +95,10 @@ type ChildProcess struct {
9595
lastProcessTimes *cpu.TimesStat
9696

9797
// Current RAM RSS in MiBs
98-
ramMiBCur uint32
98+
ramMiBCur atomic.Uint32
9999

100100
// Current CPU percentage times 1000 (we use scaling since we have to use int for atomic operations).
101-
cpuPercentX1000Cur uint32
101+
cpuPercentX1000Cur atomic.Uint32
102102

103103
// Maximum CPU seen
104104
cpuPercentMax float64
@@ -287,8 +287,8 @@ func (cp *ChildProcess) Stop() (stopped bool, err error) {
287287
close(finished)
288288

289289
// Set resource consumption stats to 0
290-
atomic.StoreUint32(&cp.ramMiBCur, 0)
291-
atomic.StoreUint32(&cp.cpuPercentX1000Cur, 0)
290+
cp.ramMiBCur.Store(0)
291+
cp.cpuPercentX1000Cur.Store(0)
292292

293293
log.Printf("%s process stopped, exit code=%d", cp.name, cp.cmd.ProcessState.ExitCode())
294294

@@ -369,7 +369,7 @@ func (cp *ChildProcess) fetchRAMUsage() {
369369
}
370370

371371
// Store current usage.
372-
atomic.StoreUint32(&cp.ramMiBCur, ramMiBCur)
372+
cp.ramMiBCur.Store(ramMiBCur)
373373
}
374374

375375
func (cp *ChildProcess) fetchCPUUsage() {
@@ -398,19 +398,19 @@ func (cp *ChildProcess) fetchCPUUsage() {
398398
curCPUPercentageX1000 := uint32(cpuPercent * 1000)
399399

400400
// Store current usage.
401-
atomic.StoreUint32(&cp.cpuPercentX1000Cur, curCPUPercentageX1000)
401+
cp.cpuPercentX1000Cur.Store(curCPUPercentageX1000)
402402
}
403403

404404
func (cp *ChildProcess) checkAllowedResourceUsage() error {
405405
// Check if current CPU usage exceeds expected.
406406
var errMsg string
407-
if cp.resourceSpec.ExpectedMaxCPU != 0 && cp.cpuPercentX1000Cur/1000 > cp.resourceSpec.ExpectedMaxCPU {
407+
if cp.resourceSpec.ExpectedMaxCPU != 0 && cp.cpuPercentX1000Cur.Load()/1000 > cp.resourceSpec.ExpectedMaxCPU {
408408
errMsg = fmt.Sprintf("CPU consumption is %.1f%%, max expected is %d%%",
409-
float64(cp.cpuPercentX1000Cur)/1000.0, cp.resourceSpec.ExpectedMaxCPU)
409+
float64(cp.cpuPercentX1000Cur.Load())/1000.0, cp.resourceSpec.ExpectedMaxCPU)
410410
}
411411

412412
// Check if current RAM usage exceeds expected.
413-
if cp.resourceSpec.ExpectedMaxRAM != 0 && cp.ramMiBCur > cp.resourceSpec.ExpectedMaxRAM {
413+
if cp.resourceSpec.ExpectedMaxRAM != 0 && cp.ramMiBCur.Load() > cp.resourceSpec.ExpectedMaxRAM {
414414
errMsg = fmt.Sprintf("RAM consumption is %d MiB, max expected is %d MiB",
415415
cp.ramMiBCur, cp.resourceSpec.ExpectedMaxRAM)
416416
}
@@ -431,8 +431,8 @@ func (cp *ChildProcess) GetResourceConsumption() string {
431431
return ""
432432
}
433433

434-
curRSSMib := atomic.LoadUint32(&cp.ramMiBCur)
435-
curCPUPercentageX1000 := atomic.LoadUint32(&cp.cpuPercentX1000Cur)
434+
curRSSMib := cp.ramMiBCur.Load()
435+
curCPUPercentageX1000 := cp.cpuPercentX1000Cur.Load()
436436

437437
return fmt.Sprintf("%s RAM (RES):%4d MiB, CPU:%4.1f%%", cp.name,
438438
curRSSMib, float64(curCPUPercentageX1000)/1000.0)

testbed/testbed/data_providers.go

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ import (
2222
"log"
2323
"math/rand"
2424
"strconv"
25-
"sync/atomic"
2625
"time"
2726

2827
metricspb "github.com/census-instrumentation/opencensus-proto/gen-go/metrics/v1"
2928
resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
3029
tracepb "github.com/census-instrumentation/opencensus-proto/gen-go/trace/v1"
3130
"github.com/golang/protobuf/ptypes/timestamp"
31+
"go.uber.org/atomic"
3232

3333
"go.opentelemetry.io/collector/consumer/pdata"
3434
"go.opentelemetry.io/collector/internal/data"
@@ -37,53 +37,53 @@ import (
3737
"go.opentelemetry.io/collector/translator/internaldata"
3838
)
3939

40-
//DataProvider defines the interface for generators of test data used to drive various end-to-end tests.
40+
// DataProvider defines the interface for generators of test data used to drive various end-to-end tests.
4141
type DataProvider interface {
42-
//SetLoadGeneratorCounters supplies pointers to LoadGenerator counters.
43-
//The data provider implementation should increment these as it generates data.
44-
SetLoadGeneratorCounters(batchesGenerated *uint64, dataItemsGenerated *uint64)
45-
//GenerateTraces returns an internal Traces instance with an OTLP ResourceSpans slice populated with test data.
42+
// SetLoadGeneratorCounters supplies pointers to LoadGenerator counters.
43+
// The data provider implementation should increment these as it generates data.
44+
SetLoadGeneratorCounters(batchesGenerated *atomic.Uint64, dataItemsGenerated *atomic.Uint64)
45+
// GenerateTraces returns an internal Traces instance with an OTLP ResourceSpans slice populated with test data.
4646
GenerateTraces() (pdata.Traces, bool)
47-
//GenerateTracesOld returns a slice of OpenCensus Span instances populated with test data.
47+
// GenerateTracesOld returns a slice of OpenCensus Span instances populated with test data.
4848
GenerateTracesOld() ([]*tracepb.Span, bool)
49-
//GenerateMetrics returns an internal MetricData instance with an OTLP ResourceMetrics slice of test data.
49+
// GenerateMetrics returns an internal MetricData instance with an OTLP ResourceMetrics slice of test data.
5050
GenerateMetrics() (data.MetricData, bool)
51-
//GenerateMetricsOld returns a slice of OpenCensus Metric instances populated with test data.
51+
// GenerateMetricsOld returns a slice of OpenCensus Metric instances populated with test data.
5252
GenerateMetricsOld() ([]*metricspb.Metric, bool)
53-
//GetGeneratedSpan returns the generated Span matching the provided traceId and spanId or else nil if no match found.
53+
// GetGeneratedSpan returns the generated Span matching the provided traceId and spanId or else nil if no match found.
5454
GetGeneratedSpan(traceID []byte, spanID []byte) *otlptrace.Span
5555
}
5656

57-
//PerfTestDataProvider in an implementation of the DataProvider for use in performance tests.
58-
//Tracing IDs are based on the incremented batch and data items counters.
57+
// PerfTestDataProvider in an implementation of the DataProvider for use in performance tests.
58+
// Tracing IDs are based on the incremented batch and data items counters.
5959
type PerfTestDataProvider struct {
6060
options LoadOptions
61-
batchesGenerated *uint64
62-
dataItemsGenerated *uint64
61+
batchesGenerated *atomic.Uint64
62+
dataItemsGenerated *atomic.Uint64
6363
}
6464

65-
//NewPerfTestDataProvider creates an instance of PerfTestDataProvider which generates test data based on the sizes
66-
//specified in the supplied LoadOptions.
65+
// NewPerfTestDataProvider creates an instance of PerfTestDataProvider which generates test data based on the sizes
66+
// specified in the supplied LoadOptions.
6767
func NewPerfTestDataProvider(options LoadOptions) *PerfTestDataProvider {
6868
return &PerfTestDataProvider{
6969
options: options,
7070
}
7171
}
7272

73-
func (dp *PerfTestDataProvider) SetLoadGeneratorCounters(batchesGenerated *uint64, dataItemsGenerated *uint64) {
73+
func (dp *PerfTestDataProvider) SetLoadGeneratorCounters(batchesGenerated *atomic.Uint64, dataItemsGenerated *atomic.Uint64) {
7474
dp.batchesGenerated = batchesGenerated
7575
dp.dataItemsGenerated = dataItemsGenerated
7676
}
7777

7878
func (dp *PerfTestDataProvider) GenerateTracesOld() ([]*tracepb.Span, bool) {
7979

8080
var spans []*tracepb.Span
81-
traceID := atomic.AddUint64(dp.batchesGenerated, 1)
81+
traceID := dp.batchesGenerated.Inc()
8282
for i := 0; i < dp.options.ItemsPerBatch; i++ {
8383

8484
startTime := time.Now()
8585

86-
spanID := atomic.AddUint64(dp.dataItemsGenerated, 1)
86+
spanID := dp.dataItemsGenerated.Inc()
8787

8888
// Create a span.
8989
span := &tracepb.Span{
@@ -126,13 +126,13 @@ func (dp *PerfTestDataProvider) GenerateTraces() (pdata.Traces, bool) {
126126
spans := ilss.At(0).Spans()
127127
spans.Resize(dp.options.ItemsPerBatch)
128128

129-
traceID := atomic.AddUint64(dp.batchesGenerated, 1)
129+
traceID := dp.batchesGenerated.Inc()
130130
for i := 0; i < dp.options.ItemsPerBatch; i++ {
131131

132132
startTime := time.Now()
133133
endTime := startTime.Add(time.Duration(time.Millisecond))
134134

135-
spanID := atomic.AddUint64(dp.dataItemsGenerated, 1)
135+
spanID := dp.dataItemsGenerated.Inc()
136136

137137
span := spans.At(i)
138138

@@ -192,7 +192,7 @@ func (dp *PerfTestDataProvider) GenerateMetricsOld() ([]*metricspb.Metric, bool)
192192
Resource: resource,
193193
}
194194

195-
batchIndex := atomic.AddUint64(dp.batchesGenerated, 1)
195+
batchIndex := dp.batchesGenerated.Inc()
196196

197197
// Generate data points for the metric. We generate timeseries each containing
198198
// a single data points. This is the most typical payload composition since
@@ -201,7 +201,7 @@ func (dp *PerfTestDataProvider) GenerateMetricsOld() ([]*metricspb.Metric, bool)
201201
timeseries := &metricspb.TimeSeries{}
202202

203203
startTime := time.Now()
204-
value := atomic.AddUint64(dp.dataItemsGenerated, 1)
204+
value := dp.dataItemsGenerated.Inc()
205205

206206
// Create a data point.
207207
point := &metricspb.Point{
@@ -248,14 +248,14 @@ func (dp *PerfTestDataProvider) GenerateMetrics() (data.MetricData, bool) {
248248
metricDescriptor.SetDescription("Load Generator Counter #" + strconv.Itoa(i))
249249
metricDescriptor.SetType(pdata.MetricTypeInt64)
250250

251-
batchIndex := atomic.AddUint64(dp.batchesGenerated, 1)
251+
batchIndex := dp.batchesGenerated.Inc()
252252

253253
// Generate data points for the metric.
254254
metric.Int64DataPoints().Resize(dataPointsPerMetric)
255255
for j := 0; j < dataPointsPerMetric; j++ {
256256
dataPoint := metric.Int64DataPoints().At(j)
257257
dataPoint.SetStartTime(pdata.TimestampUnixNano(uint64(time.Now().UnixNano())))
258-
value := atomic.AddUint64(dp.dataItemsGenerated, 1)
258+
value := dp.dataItemsGenerated.Inc()
259259
dataPoint.SetValue(int64(value))
260260
dataPoint.LabelsMap().InitFromMap(map[string]string{
261261
"item_index": "item_" + strconv.Itoa(j),
@@ -283,22 +283,22 @@ func timeToTimestamp(t time.Time) *timestamp.Timestamp {
283283
}
284284
}
285285

286-
//GoldenDataProvider is an implementation of DataProvider for use in correctness tests.
287-
//Provided data from the "Golden" dataset generated using pairwise combinatorial testing techniques.
286+
// GoldenDataProvider is an implementation of DataProvider for use in correctness tests.
287+
// Provided data from the "Golden" dataset generated using pairwise combinatorial testing techniques.
288288
type GoldenDataProvider struct {
289289
tracePairsFile string
290290
spanPairsFile string
291291
random io.Reader
292-
batchesGenerated *uint64
293-
dataItemsGenerated *uint64
292+
batchesGenerated *atomic.Uint64
293+
dataItemsGenerated *atomic.Uint64
294294
resourceSpans []*otlptrace.ResourceSpans
295295
spansIndex int
296296
spansMap map[string]*otlptrace.Span
297297
}
298298

299-
//NewGoldenDataProvider creates a new instance of GoldenDataProvider which generates test data based
300-
//on the pairwise combinations specified in the tracePairsFile and spanPairsFile input variables.
301-
//The supplied randomSeed is used to initialize the random number generator used in generating tracing IDs.
299+
// NewGoldenDataProvider creates a new instance of GoldenDataProvider which generates test data based
300+
// on the pairwise combinations specified in the tracePairsFile and spanPairsFile input variables.
301+
// The supplied randomSeed is used to initialize the random number generator used in generating tracing IDs.
302302
func NewGoldenDataProvider(tracePairsFile string, spanPairsFile string, randomSeed int64) *GoldenDataProvider {
303303
return &GoldenDataProvider{
304304
tracePairsFile: tracePairsFile,
@@ -307,7 +307,7 @@ func NewGoldenDataProvider(tracePairsFile string, spanPairsFile string, randomSe
307307
}
308308
}
309309

310-
func (dp *GoldenDataProvider) SetLoadGeneratorCounters(batchesGenerated *uint64, dataItemsGenerated *uint64) {
310+
func (dp *GoldenDataProvider) SetLoadGeneratorCounters(batchesGenerated *atomic.Uint64, dataItemsGenerated *atomic.Uint64) {
311311
dp.batchesGenerated = batchesGenerated
312312
dp.dataItemsGenerated = dataItemsGenerated
313313
}
@@ -321,7 +321,7 @@ func (dp *GoldenDataProvider) GenerateTraces() (pdata.Traces, bool) {
321321
dp.resourceSpans = make([]*otlptrace.ResourceSpans, 0)
322322
}
323323
}
324-
atomic.AddUint64(dp.batchesGenerated, 1)
324+
dp.batchesGenerated.Inc()
325325
if dp.spansIndex >= len(dp.resourceSpans) {
326326
return pdata.TracesFromOtlp(make([]*otlptrace.ResourceSpans, 0)), true
327327
}
@@ -332,7 +332,7 @@ func (dp *GoldenDataProvider) GenerateTraces() (pdata.Traces, bool) {
332332
for _, libSpans := range resourceSpans[0].InstrumentationLibrarySpans {
333333
spanCount += uint64(len(libSpans.Spans))
334334
}
335-
atomic.AddUint64(dp.dataItemsGenerated, spanCount)
335+
dp.dataItemsGenerated.Add(spanCount)
336336
return pdata.TracesFromOtlp(resourceSpans), false
337337
}
338338

testbed/testbed/load_generator.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,28 @@ import (
1818
"fmt"
1919
"log"
2020
"sync"
21-
"sync/atomic"
2221
"time"
2322

2423
resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1"
24+
"go.uber.org/atomic"
25+
"golang.org/x/text/message"
2526

2627
"go.opentelemetry.io/collector/consumer/consumerdata"
2728
)
2829

30+
var printer = message.NewPrinter(message.MatchLanguage("en"))
31+
2932
// LoadGenerator is a simple load generator.
3033
type LoadGenerator struct {
3134
sender DataSender
3235

3336
dataProvider DataProvider
3437

3538
// Number of batches of data items sent.
36-
batchesSent uint64
39+
batchesSent atomic.Uint64
3740

3841
// Number of data items (spans or metric data points) sent.
39-
dataItemsSent uint64
42+
dataItemsSent atomic.Uint64
4043

4144
stopOnce sync.Once
4245
stopWait sync.WaitGroup
@@ -111,11 +114,11 @@ func (lg *LoadGenerator) Stop() {
111114

112115
// GetStats returns the stats as a printable string.
113116
func (lg *LoadGenerator) GetStats() string {
114-
return fmt.Sprintf("Sent:%5d items", atomic.LoadUint64(&lg.dataItemsSent))
117+
return printer.Sprintf("Sent:%10d items", lg.DataItemsSent())
115118
}
116119

117120
func (lg *LoadGenerator) DataItemsSent() uint64 {
118-
return atomic.LoadUint64(&lg.dataItemsSent)
121+
return lg.dataItemsSent.Load()
119122
}
120123

121124
// IncDataItemsSent is used when a test bypasses the LoadGenerator and sends data
@@ -125,7 +128,7 @@ func (lg *LoadGenerator) DataItemsSent() uint64 {
125128
// reports to use their own counter and load generator and other sending sources
126129
// to contribute to this counter. This could be done as a future improvement.
127130
func (lg *LoadGenerator) IncDataItemsSent() {
128-
atomic.AddUint64(&lg.dataItemsSent, 1)
131+
lg.dataItemsSent.Inc()
129132
}
130133

131134
func (lg *LoadGenerator) generate() {

0 commit comments

Comments
 (0)