Skip to content

Commit d03aa3f

Browse files
committed
feat(testing): add benchmark markers
1 parent 43b62e5 commit d03aa3f

File tree

2 files changed

+69
-11
lines changed

2 files changed

+69
-11
lines changed

testing/capi/instrument-hooks.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ typedef struct instruments_root_InstrumentHooks__547 InstrumentHooks;
77
*/
88
import "C"
99
import (
10+
"os"
1011
"runtime"
1112
"unsafe"
1213
)
1314

15+
const (
16+
MarkerTypeSampleStart = 0
17+
MarkerTypeSampleEnd = 1
18+
MarkerTypeBenchmarkStart = 2
19+
MarkerTypeBenchmarkEnd = 3
20+
)
21+
1422
// This will be set in the go-runner
1523
var integrationVersion = "dev"
1624

@@ -79,3 +87,16 @@ func (i *InstrumentHooks) IsInstrumented() bool {
7987
}
8088
return bool(C.instrument_hooks_is_instrumented(i.hooks))
8189
}
90+
91+
func CurrentTimestamp() uint64 {
92+
return uint64(C.instrument_hooks_current_timestamp())
93+
}
94+
95+
func (i *InstrumentHooks) AddBenchmarkTimestamps(startTimestamp, endTimestamp uint64) {
96+
if i.hooks == nil {
97+
return
98+
}
99+
pid := uint32(os.Getpid())
100+
C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.uint8_t(MarkerTypeBenchmarkStart), C.uint64_t(startTimestamp))
101+
C.instrument_hooks_add_marker(i.hooks, C.uint32_t(pid), C.uint8_t(MarkerTypeBenchmarkEnd), C.uint64_t(endTimestamp))
102+
}

testing/testing/benchmark.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ type codspeed struct {
9090

9191
codspeedTimePerRoundNs []time.Duration
9292
codspeedItersPerRound []int64
93+
94+
startTimestamp uint64
95+
startTimestamps []uint64
96+
stopTimestamps []uint64
9397
}
9498

9599
// B is a type passed to [Benchmark] functions to manage benchmark
@@ -158,26 +162,40 @@ func (b *B) StartTimer() {
158162
b.start = highPrecisionTimeNow()
159163
b.timerOn = true
160164
// b.loop.i &^= loopPoisonTimer
165+
b.startTimestamp = capi.CurrentTimestamp()
161166
}
162167
}
163168

164169
// StopTimer stops timing a test. This can be used to pause the timer
165170
// while performing steps that you don't want to measure.
166171
func (b *B) StopTimer() {
167172
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()
174174
b.duration += highPrecisionTimeSince(b.start)
175175
// runtime.ReadMemStats(&memStats)
176176
// b.netAllocs += memStats.Mallocs - b.startAllocs
177177
// b.netBytes += memStats.TotalAlloc - b.startBytes
178178
b.timerOn = false
179179
// If we hit B.Loop with the timer stopped, fail.
180180
// 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))
181199
}
182200
}
183201

@@ -201,6 +219,23 @@ func (b *B) ResetTimer() {
201219
b.duration = 0
202220
b.netAllocs = 0
203221
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]
204239
}
205240

206241
// SetBytes records the number of bytes processed in a single operation.
@@ -385,8 +420,7 @@ func (b *B) launch() {
385420
}
386421

387422
// Reset the fields from the warmup run
388-
b.codspeedItersPerRound = make([]int64, 0)
389-
b.codspeedTimePerRoundNs = make([]time.Duration, 0)
423+
b.ResetTimer()
390424

391425
// Final run:
392426
benchD := b.benchTime.d
@@ -411,6 +445,7 @@ func (b *B) launch() {
411445
b.runN(int(roundN))
412446
}
413447
b.codspeed.instrument_hooks.StopBenchmark()
448+
b.sendAccumulatedTimestamps()
414449
}
415450
}
416451
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 {
452487
// Stop the timer so we don't count cleanup time
453488
b.StopTimer()
454489
b.codspeed.instrument_hooks.StopBenchmark()
490+
b.sendAccumulatedTimestamps()
491+
455492
// Commit iteration count
456493
b.N = int(b.loop.n)
457494
b.loop.done = true
@@ -490,9 +527,7 @@ func (b *B) loopSlowPath() bool {
490527
b.N = 0
491528
b.loop.i++
492529

493-
b.codspeedItersPerRound = make([]int64, 0)
494-
b.codspeedTimePerRoundNs = make([]time.Duration, 0)
495-
530+
b.ResetTimer()
496531
b.codspeed.instrument_hooks.StartBenchmark()
497532
b.ResetTimer()
498533
b.StartTimer()
@@ -509,6 +544,8 @@ func (b *B) loopSlowPath() bool {
509544
}
510545
b.StopTimer()
511546
b.codspeed.instrument_hooks.StopBenchmark()
547+
b.sendAccumulatedTimestamps()
548+
512549
// Commit iteration count
513550
b.N = int(b.loop.n)
514551
b.loop.done = true

0 commit comments

Comments
 (0)