Skip to content

Commit 5f5cbe2

Browse files
authored
Add support for mixed columns (#57)
1 parent 556d421 commit 5f5cbe2

File tree

4 files changed

+177
-82
lines changed

4 files changed

+177
-82
lines changed

Sources/Benchmark/BenchmarkColumn.swift

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public struct BenchmarkColumn: Hashable {
4949
value: @escaping (BenchmarkResult) -> Double,
5050
unit: Unit = .none,
5151
alignment: Alignment = .right,
52-
formatter optionalFormatter: Formatter? = nil
52+
formatter optionalFormatter: Formatter? = nil
5353
) {
5454
self.name = name
5555
self.value = value
@@ -214,39 +214,31 @@ public struct BenchmarkColumn: Hashable {
214214
return columns
215215
}
216216

217-
/// Evaluate all cells for all columns over all results, using
218-
/// columns defined in settings or defaults otherwise.
219-
static func evaluate(results: [BenchmarkResult], settings: BenchmarkSettings, pretty: Bool) -> (
220-
[Row], [BenchmarkColumn]
221-
) {
222-
var columns: [BenchmarkColumn] = []
223-
if let names = settings.columns {
224-
for name in names {
225-
columns.append(BenchmarkColumn.registry[name]!)
226-
}
227-
} else {
228-
columns = BenchmarkColumn.defaults(results: results)
229-
}
230-
231-
let rows = BenchmarkColumn.evaluate(columns: columns, results: results, pretty: pretty)
232-
233-
return (rows, columns)
234-
}
235-
236217
/// Evaluate all cells for all columns over all results.
237218
/// Pretty argument specifies if output is meant to be human-readable.
238-
static func evaluate(columns: [BenchmarkColumn], results: [BenchmarkResult], pretty: Bool)
239-
-> [Row]
219+
static func evaluate(results: [BenchmarkResult], pretty: Bool)
220+
-> ([Row], [BenchmarkColumn])
240221
{
222+
var allColumns: [BenchmarkColumn] = []
241223
var header: Row = [:]
242-
for column in columns {
243-
header[column] = column.name
244-
}
245-
246-
var rows: [Row] = [header]
224+
var rows: [Row] = []
247225
for result in results {
226+
var columns: [BenchmarkColumn] = []
227+
if let names = result.settings.columns {
228+
for name in names {
229+
columns.append(BenchmarkColumn.registry[name]!)
230+
}
231+
} else {
232+
columns = BenchmarkColumn.defaults(results: results)
233+
}
234+
248235
var row: Row = [:]
249236
for column in columns {
237+
if header[column] == nil {
238+
header[column] = column.name
239+
allColumns.append(column)
240+
}
241+
250242
var content: String
251243
if column.name == "name" {
252244
if result.suiteName != "" {
@@ -286,6 +278,8 @@ public struct BenchmarkColumn: Hashable {
286278
rows.append(row)
287279
}
288280

289-
return rows
281+
var result: [Row] = [header]
282+
result.append(contentsOf: rows)
283+
return (result, allColumns)
290284
}
291285
}

Sources/Benchmark/BenchmarkReporter.swift

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ protocol ProgressReporter {
2020
}
2121

2222
protocol BenchmarkReporter {
23-
mutating func report(results: [BenchmarkResult], settings: BenchmarkSettings)
23+
mutating func report(results: [BenchmarkResult])
2424
}
2525

2626
struct VerboseProgressReporter<Output: FlushableTextOutputStream>: ProgressReporter {
@@ -51,7 +51,7 @@ struct VerboseProgressReporter<Output: FlushableTextOutputStream>: ProgressRepor
5151
struct QuietReporter: ProgressReporter, BenchmarkReporter {
5252
mutating func report(running name: String, suite: String) {}
5353
mutating func report(finishedRunning name: String, suite: String, nanosTaken: UInt64) {}
54-
mutating func report(results: [BenchmarkResult], settings: BenchmarkSettings) {}
54+
mutating func report(results: [BenchmarkResult]) {}
5555
}
5656

5757
struct ConsoleReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
@@ -61,9 +61,8 @@ struct ConsoleReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
6161
self.output = output
6262
}
6363

64-
mutating func report(results: [BenchmarkResult], settings: BenchmarkSettings) {
65-
let (rows, columns) = BenchmarkColumn.evaluate(
66-
results: results, settings: settings, pretty: true)
64+
mutating func report(results: [BenchmarkResult]) {
65+
let (rows, columns) = BenchmarkColumn.evaluate(results: results, pretty: true)
6766

6867
let widths: [BenchmarkColumn: Int] = Dictionary(
6968
uniqueKeysWithValues:
@@ -80,7 +79,12 @@ struct ConsoleReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
8079
print("", to: &output)
8180
for (index, row) in rows.enumerated() {
8281
let components: [String] = columns.compactMap { column in
83-
let string = row[column]!
82+
var string: String
83+
if let value = row[column] {
84+
string = value
85+
} else {
86+
string = ""
87+
}
8488
let width = widths[column]!
8589
let alignment = index == 0 ? .left : column.alignment
8690
switch alignment {
@@ -108,12 +112,17 @@ struct CSVReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
108112
self.output = output
109113
}
110114

111-
mutating func report(results: [BenchmarkResult], settings: BenchmarkSettings) {
112-
let (rows, columns) = BenchmarkColumn.evaluate(
113-
results: results, settings: settings, pretty: false)
115+
mutating func report(results: [BenchmarkResult]) {
116+
let (rows, columns) = BenchmarkColumn.evaluate(results: results, pretty: false)
114117

115118
for row in rows {
116-
let components: [String] = columns.compactMap { row[$0]! }
119+
let components: [String] = columns.compactMap {
120+
if let value = row[$0] {
121+
return value
122+
} else {
123+
return ""
124+
}
125+
}
117126
let escaped = components.map { component -> String in
118127
if component.contains(",") || component.contains("\"") || component.contains("\n") {
119128
let escaped = component.replacingOccurrences(of: "\"", with: "\"\"")
@@ -135,9 +144,8 @@ struct JSONReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
135144
self.output = output
136145
}
137146

138-
mutating func report(results: [BenchmarkResult], settings: BenchmarkSettings) {
139-
let (rows, columns) = BenchmarkColumn.evaluate(
140-
results: results, settings: settings, pretty: false)
147+
mutating func report(results: [BenchmarkResult]) {
148+
let (rows, columns) = BenchmarkColumn.evaluate(results: results, pretty: false)
141149

142150
print("{", to: &output)
143151
print(" \"benchmarks\": [", to: &output)
@@ -151,13 +159,22 @@ struct JSONReporter<Output: FlushableTextOutputStream>: BenchmarkReporter {
151159
// performance to ensure that output properly
152160
// escapes special characters that could be
153161
// present within the benchmark name.
154-
let name = row[column]!
162+
let name: String
163+
if let value = row[column] {
164+
name = value
165+
} else {
166+
name = ""
167+
}
155168
let data = try! JSONSerialization.data(withJSONObject: [name])
156169
var encoded = String(data: data, encoding: .utf8)!
157170
encoded = String(encoded.dropFirst().dropLast())
158171
rhs = encoded
159172
} else {
160-
rhs = String(row[column]!)
173+
if let value = row[column] {
174+
rhs = String(value)
175+
} else {
176+
continue
177+
}
161178
}
162179
let suffix = columnIndex != columns.count - 1 ? "," : ""
163180
print(" \"\(column.name)\": \(rhs)\(suffix)", to: &output)

Sources/Benchmark/BenchmarkRunner.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ public struct BenchmarkRunner {
1616
let suites: [BenchmarkSuite]
1717
let settings: [BenchmarkSetting]
1818
let customDefaults: [BenchmarkSetting]
19-
let globalSettings: BenchmarkSettings
2019
var progress: ProgressReporter
2120
var reporter: BenchmarkReporter
2221
var results: [BenchmarkResult] = []
@@ -29,18 +28,18 @@ public struct BenchmarkRunner {
2928
self.suites = suites
3029
self.settings = settings
3130
self.customDefaults = customDefaults
32-
self.globalSettings = BenchmarkSettings([
31+
let globalSettings = BenchmarkSettings([
3332
defaultSettings,
3433
self.customDefaults,
3534
self.settings,
3635
])
37-
switch self.globalSettings.format {
36+
switch globalSettings.format {
3837
case .none:
3938
self.progress = QuietReporter()
4039
default:
4140
self.progress = VerboseProgressReporter(output: StderrOutputStream())
4241
}
43-
switch self.globalSettings.format {
42+
switch globalSettings.format {
4443
case .none:
4544
self.reporter = QuietReporter()
4645
case .console:
@@ -56,7 +55,7 @@ public struct BenchmarkRunner {
5655
for suite in suites {
5756
try run(suite: suite)
5857
}
59-
reporter.report(results: results, settings: globalSettings)
58+
reporter.report(results: results)
6059
}
6160

6261
mutating func run(suite: BenchmarkSuite) throws {

0 commit comments

Comments
 (0)