mirror of
https://github.com/tsolomko/SWCompression.git
synced 2026-06-23 14:56:41 +00:00
52961ea60d
This allowed to rewrite implementation in a much clearer way. One user-visible change, however, is that NEW/BASE is now always printed with an index even if there is only one (implementation complexity to accommodate empty index is not worth it).
120 lines
4.7 KiB
Swift
120 lines
4.7 KiB
Swift
// Copyright (c) 2026 Timofey Solomko
|
|
// Licensed under MIT License
|
|
//
|
|
// See LICENSE for license information
|
|
|
|
import Foundation
|
|
import SwiftCLI
|
|
|
|
final class ShowBenchmarkCommand: Command {
|
|
|
|
let name = "show"
|
|
let shortDescription = "Print saved benchmarks results"
|
|
|
|
@Key("-c", "--compare", description: "Compare with other saved benchmarks results")
|
|
var comparePath: String?
|
|
|
|
@Key("--self-compare", description: "Compare runs within the same file with new results identified by run UUID")
|
|
var selfCompare: String?
|
|
|
|
@Flag("--print-uuid", description: "Prints internal UUIDs of saved benchmark runs")
|
|
var printUuid: Bool
|
|
|
|
@Flag("--metadata-only", description: "Prints only metadata of saved benchmark runs")
|
|
var metadataOnly: Bool
|
|
|
|
@Param var path: String
|
|
|
|
var optionGroups: [OptionGroup] {
|
|
return [.atMostOne($comparePath, $selfCompare)]
|
|
}
|
|
|
|
func execute() throws {
|
|
let newSaveFile = try SaveFile.load(from: self.path)
|
|
var newRuns: [SaveFile.Run]
|
|
if let newUUIDString = self.selfCompare {
|
|
guard let newUUID = UUID(uuidString: newUUIDString)
|
|
else { swcompExit(.benchmarkBadUUID) }
|
|
guard let newRun = newSaveFile.runs.first(where: { $0.uuid == newUUID} )
|
|
else { swcompExit(.benchmarkNoUUID) }
|
|
newRuns = [newRun]
|
|
} else {
|
|
newRuns = newSaveFile.runs
|
|
}
|
|
self.printMetadatas(runs: newRuns, name: "NEW")
|
|
|
|
var baseRuns = [SaveFile.Run]()
|
|
if let comparePath = comparePath {
|
|
let baseSaveFile = try SaveFile.load(from: comparePath)
|
|
baseRuns = baseSaveFile.runs
|
|
} else if let newUUIDString = self.selfCompare {
|
|
// No need to double-check validity of input UUID. It was done already when loading the "new" run.
|
|
let newUUID = UUID(uuidString: newUUIDString)!
|
|
baseRuns = newSaveFile.runs.filter({ $0.uuid != newUUID })
|
|
}
|
|
self.printMetadatas(runs: baseRuns, name: "BASE")
|
|
|
|
guard !self.metadataOnly
|
|
else { return }
|
|
|
|
// There might be results for the same benchmark-input-iterCount tuple in different runs. We want to print those
|
|
// results together, so we have to group them based on their `id`.
|
|
let newResults = SaveFile.groupResults(runs: newRuns)
|
|
let baseResults = SaveFile.groupResults(runs: baseRuns)
|
|
|
|
// Even though we try to sort results before writing a save file, after grouping they can appear in `newResults`
|
|
// in essentially arbitrary order.
|
|
for id in newResults.keys.sorted() {
|
|
let results = newResults[id]!
|
|
print()
|
|
print("----------------")
|
|
print()
|
|
print("\(results.first!.1.name) => \(results.first!.1.input), iterations = \(results.first!.1.iterCount)")
|
|
print()
|
|
for (index, result) in results {
|
|
let benchmark = Benchmarks(rawValue: result.name)?.initialized(result.input)
|
|
if let warmup = result.warmup {
|
|
print("NEW(\(index + 1)): average = \(benchmark.format(result.avg)), standard deviation = \(benchmark.format(result.std)), warmup = \(benchmark.format(warmup))")
|
|
} else {
|
|
print("NEW(\(index + 1)): average = \(benchmark.format(result.avg)), standard deviation = \(benchmark.format(result.std))")
|
|
}
|
|
if let baseResults = baseResults[id] {
|
|
for (baseIndex, baseResult) in baseResults {
|
|
if let baseWarmup = baseResult.warmup {
|
|
print("BASE(\(baseIndex + 1)): average = \(benchmark.format(baseResult.avg)), standard deviation = \(benchmark.format(baseResult.std)), warmup = \(benchmark.format(baseWarmup))")
|
|
} else {
|
|
print("BASE(\(baseIndex + 1)): average = \(benchmark.format(baseResult.avg)), standard deviation = \(benchmark.format(baseResult.std))")
|
|
}
|
|
result.printComparison(with: baseResult)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func printMetadatas(runs: [SaveFile.Run], name: String) {
|
|
for (index, run) in runs.enumerated() {
|
|
print("\(name)(\(index + 1)) Metadata")
|
|
print("---------------")
|
|
if self.printUuid {
|
|
print("UUID: \(run.uuid)")
|
|
}
|
|
run.metadata.print()
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
fileprivate extension Optional where Wrapped == Benchmark {
|
|
|
|
func format(_ value: Double) -> String {
|
|
switch self {
|
|
case .some(let benchmark):
|
|
return benchmark.format(value)
|
|
case .none:
|
|
return String(value)
|
|
}
|
|
}
|
|
|
|
}
|