@@ -90,6 +90,10 @@ type codspeed struct {
90
90
91
91
codspeedTimePerRoundNs []time.Duration
92
92
codspeedItersPerRound []int64
93
+
94
+ startTimestamp uint64
95
+ startTimestamps []uint64
96
+ stopTimestamps []uint64
93
97
}
94
98
95
99
// B is a type passed to [Benchmark] functions to manage benchmark
@@ -158,26 +162,40 @@ func (b *B) StartTimer() {
158
162
b .start = highPrecisionTimeNow ()
159
163
b .timerOn = true
160
164
// b.loop.i &^= loopPoisonTimer
165
+ b .startTimestamp = capi .CurrentTimestamp ()
161
166
}
162
167
}
163
168
164
169
// StopTimer stops timing a test. This can be used to pause the timer
165
170
// while performing steps that you don't want to measure.
166
171
func (b * B ) StopTimer () {
167
172
if b .timerOn {
168
- // For b.N loops: This will be called in runN which sets b.N to the number of iterations.
169
- // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since
170
- // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as
171
- // the number of iterations for this round.
172
- b .codspeedItersPerRound = append (b .codspeedItersPerRound , max (int64 (b .N ), 1 ))
173
- b .codspeedTimePerRoundNs = append (b .codspeedTimePerRoundNs , highPrecisionTimeSince (b .start ))
173
+ endTimestamp := capi .CurrentTimestamp ()
174
174
b .duration += highPrecisionTimeSince (b .start )
175
175
// runtime.ReadMemStats(&memStats)
176
176
// b.netAllocs += memStats.Mallocs - b.startAllocs
177
177
// b.netBytes += memStats.TotalAlloc - b.startBytes
178
178
b .timerOn = false
179
179
// If we hit B.Loop with the timer stopped, fail.
180
180
// b.loop.i |= loopPoisonTimer
181
+
182
+ if b .startTimestamp >= endTimestamp {
183
+ // This should never happen, unless we have a bug in the
184
+ // timer logic.
185
+ panic ("Invalid benchmark start timestamp" )
186
+ }
187
+ b .startTimestamps = append (b .startTimestamps , b .startTimestamp )
188
+ b .stopTimestamps = append (b .stopTimestamps , endTimestamp )
189
+
190
+ // Reset to prevent accidental reuse
191
+ b .startTimestamp = 0
192
+
193
+ // For b.N loops: This will be called in runN which sets b.N to the number of iterations.
194
+ // For b.Loop() loops: loopSlowPath sets b.N to 0 to prevent b.N loops within b.Loop. However, since
195
+ // we're starting/stopping the timer for each iteration in the b.Loop() loop, we can use 1 as
196
+ // the number of iterations for this round.
197
+ b .codspeedItersPerRound = append (b .codspeedItersPerRound , max (int64 (b .N ), 1 ))
198
+ b .codspeedTimePerRoundNs = append (b .codspeedTimePerRoundNs , highPrecisionTimeSince (b .start ))
181
199
}
182
200
}
183
201
@@ -201,6 +219,23 @@ func (b *B) ResetTimer() {
201
219
b .duration = 0
202
220
b .netAllocs = 0
203
221
b .netBytes = 0
222
+
223
+ // Clear CodSpeed timestamp data
224
+ b .codspeedItersPerRound = b .codspeedItersPerRound [:0 ]
225
+ b .codspeedTimePerRoundNs = b .codspeedTimePerRoundNs [:0 ]
226
+ b .startTimestamps = b .startTimestamps [:0 ]
227
+ b .stopTimestamps = b .stopTimestamps [:0 ]
228
+ }
229
+
230
+ func (b * B ) sendAccumulatedTimestamps () {
231
+ for i := 0 ; i < len (b .startTimestamps ); i ++ {
232
+ b .instrument_hooks .AddBenchmarkTimestamps (
233
+ b .startTimestamps [i ],
234
+ b .stopTimestamps [i ],
235
+ )
236
+ }
237
+ b .startTimestamps = b .startTimestamps [:0 ]
238
+ b .stopTimestamps = b .stopTimestamps [:0 ]
204
239
}
205
240
206
241
// SetBytes records the number of bytes processed in a single operation.
@@ -385,8 +420,7 @@ func (b *B) launch() {
385
420
}
386
421
387
422
// Reset the fields from the warmup run
388
- b .codspeedItersPerRound = make ([]int64 , 0 )
389
- b .codspeedTimePerRoundNs = make ([]time.Duration , 0 )
423
+ b .ResetTimer ()
390
424
391
425
// Final run:
392
426
benchD := b .benchTime .d
@@ -411,6 +445,7 @@ func (b *B) launch() {
411
445
b .runN (int (roundN ))
412
446
}
413
447
b .codspeed .instrument_hooks .StopBenchmark ()
448
+ b .sendAccumulatedTimestamps ()
414
449
}
415
450
}
416
451
b .result = BenchmarkResult {b .N , b .duration , b .bytes , b .netAllocs , b .netBytes , b .codspeedTimePerRoundNs , b .codspeedItersPerRound , b .extra }
@@ -452,6 +487,8 @@ func (b *B) stopOrScaleBLoop() bool {
452
487
// Stop the timer so we don't count cleanup time
453
488
b .StopTimer ()
454
489
b .codspeed .instrument_hooks .StopBenchmark ()
490
+ b .sendAccumulatedTimestamps ()
491
+
455
492
// Commit iteration count
456
493
b .N = int (b .loop .n )
457
494
b .loop .done = true
@@ -490,9 +527,7 @@ func (b *B) loopSlowPath() bool {
490
527
b .N = 0
491
528
b .loop .i ++
492
529
493
- b .codspeedItersPerRound = make ([]int64 , 0 )
494
- b .codspeedTimePerRoundNs = make ([]time.Duration , 0 )
495
-
530
+ b .ResetTimer ()
496
531
b .codspeed .instrument_hooks .StartBenchmark ()
497
532
b .ResetTimer ()
498
533
b .StartTimer ()
@@ -509,6 +544,8 @@ func (b *B) loopSlowPath() bool {
509
544
}
510
545
b .StopTimer ()
511
546
b .codspeed .instrument_hooks .StopBenchmark ()
547
+ b .sendAccumulatedTimestamps ()
548
+
512
549
// Commit iteration count
513
550
b .N = int (b .loop .n )
514
551
b .loop .done = true
0 commit comments