Skip to content

Commit

Permalink
feat(minor): Add signposts for explicit starts (#260)
Browse files Browse the repository at this point in the history
Adding support for per-iteration signposts as requested in #259
  • Loading branch information
hassila authored Aug 13, 2024
1 parent f03eaa2 commit a214635
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Benchmarks/Benchmarks/Basic/BenchmarkRunner+Basic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ let benchmarks = {
free(something)
}
if let fileHandle = FileHandle(forWritingAtPath: "/dev/null") {
let data = "Data to discard".data(using: .utf8)!
let data = Data("Data to discard".utf8)
fileHandle.write(data)
fileHandle.closeFile()
}
Expand Down
22 changes: 15 additions & 7 deletions Sources/Benchmark/Benchmark.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public final class Benchmark: Codable, Hashable {
#if swift(>=5.8)
@_documentation(visibility: internal)
#endif
public typealias BenchmarkMeasurementSynchronization = () -> Void
public typealias BenchmarkMeasurementSynchronization = (_ explicitStartStop: Bool) -> Void
#if swift(>=5.8)
@_documentation(visibility: internal)
#endif
Expand Down Expand Up @@ -283,8 +283,12 @@ public final class Benchmark: Codable, Hashable {
/// `startMeasurement` can be called explicitly to define when measurement should begin.
/// Otherwise the whole benchmark will be measured.
public func startMeasurement() {
_startMeasurement(true)
}

private func _startMeasurement(_ explicitStartStop: Bool) {
if let measurementPreSynchronization {
measurementPreSynchronization()
measurementPreSynchronization(explicitStartStop)
}
measurementCompleted = false
}
Expand All @@ -293,13 +297,17 @@ public final class Benchmark: Codable, Hashable {
/// `stopMeasurement` can be called explicitly to define when measurement should stop.
/// Otherwise the whole benchmark will be measured.
public func stopMeasurement() {
_stopMeasurement(true)
}

private func _stopMeasurement(_ explicitStartStop: Bool) {
guard measurementCompleted == false else { // This is to skip the implicit stop if we did an explicit before
return
}

if let measurementPostSynchronization {
measurementCompleted = true
measurementPostSynchronization()
measurementPostSynchronization(explicitStartStop)
}
}

Expand All @@ -324,9 +332,9 @@ public final class Benchmark: Codable, Hashable {
// Must do this in a separate thread, otherwise we block the concurrent thread pool
DispatchQueue.global(qos: .userInitiated).async {
Task {
self.startMeasurement()
self._startMeasurement(false)
await asyncClosure(self)
self.stopMeasurement()
self._stopMeasurement(false)

semaphore.signal()
}
Expand All @@ -340,9 +348,9 @@ public final class Benchmark: Codable, Hashable {
#endif
public func run() {
if let closure {
startMeasurement()
_startMeasurement(false)
closure(self)
stopMeasurement()
_stopMeasurement(false)
} else {
runAsync()
}
Expand Down
17 changes: 15 additions & 2 deletions Sources/Benchmark/BenchmarkExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct BenchmarkExecutor { // swiftlint:disable:this type_body_length
let signPost = OSSignposter(logHandle: logHandler)
let signpostID = OSSignpostID(log: logHandler)
var warmupInterval: OSSignpostIntervalState?
var explicitStartStopInterval: OSSignpostIntervalState?

if benchmark.configuration.warmupIterations > 0 {
warmupInterval = signPost.beginInterval("Benchmark", id: signpostID, "\(benchmark.name) warmup")
Expand Down Expand Up @@ -141,7 +142,13 @@ struct BenchmarkExecutor { // swiftlint:disable:this type_body_length
// then reset to a new starting state.
// NB that the order is important, as we will get leaked
// ARC measurements if initializing it before malloc etc.
benchmark.measurementPreSynchronization = {
benchmark.measurementPreSynchronization = { explicitStartStop in
#if canImport(OSLog)
if explicitStartStop {
explicitStartStopInterval = signPost.beginInterval("Benchmark", id: signpostID, "\(benchmark.name) startMeasurement()")
}
#endif

if mallocStatsRequested {
startMallocStats = MallocStatsProducer.makeMallocStats()
}
Expand All @@ -164,7 +171,7 @@ struct BenchmarkExecutor { // swiftlint:disable:this type_body_length

// And corresponding hook for then the benchmark has finished and capture finishing metrics here
// This closure will only be called once for a given run though.
benchmark.measurementPostSynchronization = {
benchmark.measurementPostSynchronization = { _ in
if performanceCountersRequested {
stopPerformanceCounters = operatingSystemStatsProducer.makePerformanceCounters()
}
Expand All @@ -183,6 +190,12 @@ struct BenchmarkExecutor { // swiftlint:disable:this type_body_length
stopMallocStats = MallocStatsProducer.makeMallocStats()
}

#if canImport(OSLog)
if let explicitStartStopInterval {
signPost.endInterval("Benchmark", explicitStartStopInterval, "\(benchmark.name) stopMeasurement()")
}
#endif

var delta = 0
let runningTime: Duration = startTime.duration(to: stopTime)

Expand Down

0 comments on commit a214635

Please sign in to comment.