@@ -2,14 +2,17 @@ package bench
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
5
6
"fmt"
6
7
"hash/adler32"
7
8
"math/rand"
8
9
"strings"
10
+ "sync"
9
11
"text/template"
10
12
"time"
11
13
12
14
"github.com/prometheus/client_golang/prometheus"
15
+ "github.com/prometheus/client_golang/prometheus/promauto"
13
16
"github.com/prometheus/prometheus/prompb"
14
17
)
15
18
@@ -70,7 +73,11 @@ type writeWorkload struct {
70
73
totalSeries int
71
74
totalSeriesTypeMap map [SeriesType ]int
72
75
76
+ missedIterations prometheus.Counter
77
+
73
78
options WriteDesc
79
+
80
+ seriesBufferChan chan []prompb.TimeSeries
74
81
}
75
82
76
83
func newWriteWorkload (workloadDesc WorkloadDesc , reg prometheus.Registerer ) * writeWorkload {
@@ -132,6 +139,14 @@ func newWriteWorkload(workloadDesc WorkloadDesc, reg prometheus.Registerer) *wri
132
139
totalSeries : totalSeries ,
133
140
totalSeriesTypeMap : totalSeriesTypeMap ,
134
141
options : workloadDesc .Write ,
142
+
143
+ missedIterations : promauto .With (reg ).NewCounter (
144
+ prometheus.CounterOpts {
145
+ Namespace : "benchtool" ,
146
+ Name : "write_iterations_late_total" ,
147
+ Help : "Number of write intervals started late because the previous interval did not complete in time." ,
148
+ },
149
+ ),
135
150
}
136
151
}
137
152
@@ -194,6 +209,91 @@ func (w *writeWorkload) generateTimeSeries(id string, t time.Time) []prompb.Time
194
209
return timeseries
195
210
}
196
211
212
+ type batchReq struct {
213
+ batch []prompb.TimeSeries
214
+ wg * sync.WaitGroup
215
+ putBack chan []prompb.TimeSeries
216
+ }
217
+
218
+ func (w * writeWorkload ) getSeriesBuffer (ctx context.Context ) []prompb.TimeSeries {
219
+ select {
220
+ case <- ctx .Done ():
221
+ return nil
222
+ case seriesBuffer := <- w .seriesBufferChan :
223
+ return seriesBuffer [:0 ]
224
+ }
225
+ }
226
+
227
+ func (w * writeWorkload ) generateWriteBatch (ctx context.Context , id string , numBuffers int , seriesChan chan batchReq ) error {
228
+ w .seriesBufferChan = make (chan []prompb.TimeSeries , numBuffers )
229
+ for i := 0 ; i < numBuffers ; i ++ {
230
+ w .seriesBufferChan <- make ([]prompb.TimeSeries , 0 , w .options .BatchSize )
231
+ }
232
+
233
+ seriesBuffer := w .getSeriesBuffer (ctx )
234
+ ticker := time .NewTicker (w .options .Interval )
235
+
236
+ defer close (seriesChan )
237
+
238
+ for {
239
+ select {
240
+ case <- ctx .Done ():
241
+ return nil
242
+ case timeNow := <- ticker .C :
243
+ now := timeNow .UnixNano () / int64 (time .Millisecond )
244
+ wg := & sync.WaitGroup {}
245
+ for replicaNum := 0 ; replicaNum < w .replicas ; replicaNum ++ {
246
+ replicaLabel := prompb.Label {Name : "bench_replica" , Value : fmt .Sprintf ("replica-%05d" , replicaNum )}
247
+ idLabel := prompb.Label {Name : "bench_id" , Value : id }
248
+ for _ , series := range w .series {
249
+ var value float64
250
+ switch series .seriesType {
251
+ case GaugeZero :
252
+ value = 0
253
+ case GaugeRandom :
254
+ value = rand .Float64 ()
255
+ case CounterOne :
256
+ value = series .lastValue + 1
257
+ case CounterRandom :
258
+ value = series .lastValue + float64 (rand .Int ())
259
+ default :
260
+ return fmt .Errorf ("unknown series type %v" , series .seriesType )
261
+ }
262
+ series .lastValue = value
263
+ for _ , labelSet := range series .labelSets {
264
+ if len (seriesBuffer ) == w .options .BatchSize {
265
+ wg .Add (1 )
266
+ seriesChan <- batchReq {seriesBuffer , wg , w .seriesBufferChan }
267
+ seriesBuffer = w .getSeriesBuffer (ctx )
268
+ }
269
+ newLabelSet := make ([]prompb.Label , len (labelSet )+ 2 )
270
+ copy (newLabelSet , labelSet )
271
+
272
+ newLabelSet [len (newLabelSet )- 2 ] = replicaLabel
273
+ newLabelSet [len (newLabelSet )- 1 ] = idLabel
274
+ seriesBuffer = append (seriesBuffer , prompb.TimeSeries {
275
+ Labels : newLabelSet ,
276
+ Samples : []prompb.Sample {{
277
+ Timestamp : now ,
278
+ Value : value ,
279
+ }},
280
+ })
281
+ }
282
+ }
283
+ }
284
+ if len (seriesBuffer ) > 0 {
285
+ wg .Add (1 )
286
+ seriesChan <- batchReq {seriesBuffer , wg , w .seriesBufferChan }
287
+ seriesBuffer = w .getSeriesBuffer (ctx )
288
+ }
289
+ wg .Wait ()
290
+ if time .Since (timeNow ) > w .options .Interval {
291
+ w .missedIterations .Inc ()
292
+ }
293
+ }
294
+ }
295
+ }
296
+
197
297
type queryWorkload struct {
198
298
queries []query
199
299
}
0 commit comments