Skip to content

Benchmark: option to output perf as csv #781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 49 additions & 1 deletion Sources/RegexBenchmark/BenchmarkResults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,21 @@ extension BenchmarkRunner {
self.results = result
print("Loaded results from \(url.path)")
}


/// Attempts to save results in a CSV format to the given path
func saveCSV(to savePath: String) throws {
let url = URL(fileURLWithPath: savePath, isDirectory: false)
let parent = url.deletingLastPathComponent()
if !FileManager.default.fileExists(atPath: parent.path) {
try! FileManager.default.createDirectory(
atPath: parent.path,
withIntermediateDirectories: true)
}
print("Saving result as CSV to \(url.path)")
try results.saveCSV(to: url)

}

/// Compare this runner's results against the results stored in the given file path
func compare(
against compareFilePath: String,
Expand Down Expand Up @@ -153,6 +167,12 @@ struct Measurement: Codable, CustomStringConvertible {
var description: String {
return "\(median) (stdev: \(Time(stdev)), N = \(samples))"
}

var asCSV: String {
"""
\(median.asCSVSeconds), \(stdev), \(samples)
"""
}
}

struct BenchmarkResult: Codable, CustomStringConvertible {
Expand All @@ -170,6 +190,13 @@ struct BenchmarkResult: Codable, CustomStringConvertible {
}
return base
}

var asCSV: String {
let na = "N/A, N/A, N/A"
return """
\(runtime.asCSV), \(compileTime?.asCSV ?? na), \(parseTime?.asCSV ?? na)
"""
}
}

extension BenchmarkResult {
Expand Down Expand Up @@ -263,6 +290,27 @@ struct SuiteResult {
}

extension SuiteResult: Codable {
func saveCSV(to url: URL) throws {
var output: [(name: String, result: BenchmarkResult)] = []
for key in results.keys {
output.append((key, results[key]!))
}
output.sort {
$0.name < $1.name
}
var contents = """
name,\
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like we'll eventually get bitten by name having CSV-incompatible characters… is there a simple escaping step we could do here to forfend against that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can escape the entire field in double double quotes, e.g. ""field 1""

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to not do so now, as I think it will put the quote in the field when opened in a spreadsheet. We can add that later or just have a policy that names not include commas.

runtime_median, runTime_stddev, runTime_samples,\
compileTime_median, compileTime_stddev, compileTime_samples,\
parseTime_median, parseTime_stddev, parseTime_samples\n
"""
for (name, result) in output {
contents.append("\(name), \(result.asCSV))\n")
}
print("Saving result as .csv to \(url.path())")
try contents.write(to: url, atomically: true, encoding: String.Encoding.utf8)
}

func save(to url: URL) throws {
let encoder = JSONEncoder()
let data = try encoder.encode(self)
Expand Down
13 changes: 12 additions & 1 deletion Sources/RegexBenchmark/CLI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ struct Runner: ParsableCommand {
@Option(help: "Save comparison results as csv")
var saveComparison: String?

@Option(help: "Save benchmark results as csv")
var saveCSV: String?

@Flag(help: "Quiet mode")
var quiet = false

Expand Down Expand Up @@ -84,9 +87,14 @@ swift build -c release -Xswiftc -DPROCESSOR_MEASUREMENTS_ENABLED

if let loadFile = load {
try runner.load(from: loadFile)
if excludeNs {
runner.results.results = runner.results.results.filter {
!$0.key.contains("_NS")
}
}
} else {
if excludeNs {
runner.suite = runner.suite.filter { b in !b.name.contains("NS") }
runner.suite = runner.suite.filter { b in !b.name.contains("_NS") }
}
runner.run()
}
Expand All @@ -109,5 +117,8 @@ swift build -c release -Xswiftc -DPROCESSOR_MEASUREMENTS_ENABLED
if let compareFile = compareCompileTime {
try runner.compareCompileTimes(against: compareFile, showChart: showChart)
}
if let csvPath = saveCSV {
try runner.saveCSV(to: csvPath)
}
}
}
5 changes: 5 additions & 0 deletions Sources/RegexBenchmark/Utils/Time.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ extension Time {
}

extension Time: CustomStringConvertible {
/// Normalize our time to fractions of a second for CSV output
public var asCSVSeconds: String {
return String(format: "%.3g", seconds)
}

public var description: String {
if self.seconds == 0 { return "0" }
if self.abs() < .attosecond { return String(format: "%.3gas", seconds * 1e18) }
Expand Down