Skip to content

Commit bfe5638

Browse files
authored
Add JSON benchmarks and make benchmark package build for more targets (#810)
* Add JSON benchmarks and make benchmark package build for more targets * Address review feedback
1 parent c67f24e commit bfe5638

File tree

12 files changed

+15990
-91
lines changed

12 files changed

+15990
-91
lines changed

Benchmarks/Benchmarks/Calendar/BenchmarkCalendar.swift

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
import Benchmark
1414
import func Benchmark.blackHole
1515

16-
#if FOUNDATION_FRAMEWORK
17-
import Foundation
18-
#else
16+
#if os(macOS) && USE_PACKAGE
1917
import FoundationEssentials
2018
import FoundationInternationalization
19+
#else
20+
import Foundation
2121
#endif
2222

2323
let benchmarks = {
2424
Benchmark.defaultConfiguration.maxIterations = 1_000
2525
Benchmark.defaultConfiguration.maxDuration = .seconds(3)
2626
Benchmark.defaultConfiguration.scalingFactor = .kilo
27-
Benchmark.defaultConfiguration.metrics = [.cpuTotal, .wallClock, .mallocCountTotal, .throughput]
27+
Benchmark.defaultConfiguration.metrics = [.cpuTotal, .mallocCountTotal, .throughput]
2828

2929
let thanksgivingComponents = DateComponents(month: 11, weekday: 5, weekdayOrdinal: 4)
3030
let cal = Calendar(identifier: .gregorian)
@@ -42,6 +42,7 @@ let benchmarks = {
4242
}
4343
}
4444
}
45+
4546
Benchmark("nextThousandThanksgivings") { benchmark in
4647
var count = 1000
4748
cal.enumerateDates(startingAfter: thanksgivingStart, matching: thanksgivingComponents, matchingPolicy: .nextTime) { result, exactMatch, stop in
@@ -51,26 +52,34 @@ let benchmarks = {
5152
}
5253
}
5354
}
54-
Benchmark("nextThousandThanksgivingsSequence") { benchmark in
55-
var count = 1000
56-
for _ in cal.dates(byMatching: thanksgivingComponents, startingAt: thanksgivingStart, matchingPolicy: .nextTime) {
57-
count -= 1
58-
if count == 0 {
59-
break
55+
56+
// Only available in Swift 6 for non-Darwin platforms, macOS 15 for Darwin
57+
#if swift(>=6.0)
58+
if #available(macOS 15, *) {
59+
Benchmark("nextThousandThanksgivingsSequence") { benchmark in
60+
var count = 1000
61+
for _ in cal.dates(byMatching: thanksgivingComponents, startingAt: thanksgivingStart, matchingPolicy: .nextTime) {
62+
count -= 1
63+
if count == 0 {
64+
break
65+
}
6066
}
6167
}
62-
}
63-
Benchmark("nextThousandThanksgivingsUsingRecurrenceRule") { benchmark in
64-
var rule = Calendar.RecurrenceRule(calendar: cal, frequency: .yearly, end: .afterOccurrences(1000))
65-
rule.months = [11]
66-
rule.weekdays = [.nth(4, .thursday)]
67-
rule.matchingPolicy = .nextTime
68-
var count = 0
69-
for _ in rule.recurrences(of: thanksgivingStart) {
70-
count += 1
68+
69+
Benchmark("nextThousandThanksgivingsUsingRecurrenceRule") { benchmark in
70+
var rule = Calendar.RecurrenceRule(calendar: cal, frequency: .yearly, end: .afterOccurrences(1000))
71+
rule.months = [11]
72+
rule.weekdays = [.nth(4, .thursday)]
73+
rule.matchingPolicy = .nextTime
74+
var count = 0
75+
for _ in rule.recurrences(of: thanksgivingStart) {
76+
count += 1
77+
}
78+
assert(count == 1000)
7179
}
72-
assert(count == 1000)
73-
}
80+
} // #available(macOS 15, *)
81+
#endif // swift(>=6.0)
82+
7483
Benchmark("CurrentDateComponentsFromThanksgivings") { benchmark in
7584
var count = 1000
7685
currentCalendar.enumerateDates(startingAfter: thanksgivingStart, matching: thanksgivingComponents, matchingPolicy: .nextTime) { result, exactMatch, stop in
@@ -82,9 +91,17 @@ let benchmarks = {
8291
}
8392
}
8493

94+
// MARK: - Allocations
95+
8596
let reference = Date(timeIntervalSinceReferenceDate: 496359355.795410) //2016-09-23T14:35:55-0700
8697

87-
Benchmark("allocationsForFixedCalendars", configuration: .init(scalingFactor: .mega)) { benchmark in
98+
let allocationsConfiguration = Benchmark.Configuration(
99+
metrics: [.cpuTotal, .mallocCountTotal, .peakMemoryResident, .throughput],
100+
timeUnits: .nanoseconds,
101+
scalingFactor: .mega
102+
)
103+
104+
Benchmark("allocationsForFixedCalendars", configuration: allocationsConfiguration) { benchmark in
88105
for _ in benchmark.scaledIterations {
89106
// Fixed calendar
90107
let cal = Calendar(identifier: .gregorian)
@@ -93,7 +110,7 @@ let benchmarks = {
93110
}
94111
}
95112

96-
Benchmark("allocationsForCurrentCalendar", configuration: .init(scalingFactor: .mega)) { benchmark in
113+
Benchmark("allocationsForCurrentCalendar", configuration: allocationsConfiguration) { benchmark in
97114
for _ in benchmark.scaledIterations {
98115
// Current calendar
99116
let cal = Calendar.current
@@ -102,7 +119,7 @@ let benchmarks = {
102119
}
103120
}
104121

105-
Benchmark("allocationsForAutoupdatingCurrentCalendar", configuration: .init(scalingFactor: .mega)) { benchmark in
122+
Benchmark("allocationsForAutoupdatingCurrentCalendar", configuration: allocationsConfiguration) { benchmark in
106123
for _ in benchmark.scaledIterations {
107124
// Autoupdating current calendar
108125
let cal = Calendar.autoupdatingCurrent
@@ -111,23 +128,23 @@ let benchmarks = {
111128
}
112129
}
113130

114-
Benchmark("copyOnWritePerformance", configuration: .init(scalingFactor: .mega)) { benchmark in
131+
Benchmark("copyOnWritePerformance", configuration: allocationsConfiguration) { benchmark in
115132
var cal = Calendar(identifier: .gregorian)
116133
for i in benchmark.scaledIterations {
117134
cal.firstWeekday = i % 2
118135
assert(cal.firstWeekday == i % 2)
119136
}
120137
}
121138

122-
Benchmark("copyOnWritePerformanceNoDiff", configuration: .init(scalingFactor: .mega)) { benchmark in
139+
Benchmark("copyOnWritePerformanceNoDiff", configuration: allocationsConfiguration) { benchmark in
123140
var cal = Calendar(identifier: .gregorian)
124141
let tz = TimeZone(secondsFromGMT: 1800)!
125142
for _ in benchmark.scaledIterations {
126143
cal.timeZone = tz
127144
}
128145
}
129146

130-
Benchmark("allocationsForFixedLocale", configuration: .init(scalingFactor: .mega)) { benchmark in
147+
Benchmark("allocationsForFixedLocale", configuration: allocationsConfiguration) { benchmark in
131148
// Fixed locale
132149
for _ in benchmark.scaledIterations {
133150
let loc = Locale(identifier: "en_US")
@@ -136,7 +153,7 @@ let benchmarks = {
136153
}
137154
}
138155

139-
Benchmark("allocationsForCurrentLocale", configuration: .init(scalingFactor: .mega)) { benchmark in
156+
Benchmark("allocationsForCurrentLocale", configuration: allocationsConfiguration) { benchmark in
140157
// Current locale
141158
for _ in benchmark.scaledIterations {
142159
let loc = Locale.current
@@ -145,15 +162,17 @@ let benchmarks = {
145162
}
146163
}
147164

148-
Benchmark("allocationsForAutoupdatingCurrentLocale", configuration: .init(scalingFactor: .mega)) { benchmark in
165+
Benchmark("allocationsForAutoupdatingCurrentLocale", configuration: allocationsConfiguration) { benchmark in
149166
// Autoupdating current locale
150167
for _ in benchmark.scaledIterations {
151168
let loc = Locale.autoupdatingCurrent
152169
let identifier = loc.identifier
153170
assert(identifier == "en_US")
154171
}
155172
}
156-
173+
174+
// MARK: - Identifiers
175+
157176
Benchmark("identifierFromComponents", configuration: .init(scalingFactor: .mega)) { benchmark in
158177
let c1 = ["kCFLocaleLanguageCodeKey" : "en"]
159178
let c2 = ["kCFLocaleLanguageCodeKey" : "zh",

Benchmarks/Benchmarks/DataIO/BenchmarkDataIO.swift

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@
1313
import Benchmark
1414
import func Benchmark.blackHole
1515

16-
#if FOUNDATION_FRAMEWORK
17-
import Foundation
16+
#if os(macOS) && USE_PACKAGE
17+
import FoundationEssentials
1818
#else
19-
@testable import FoundationEssentials
19+
import Foundation
2020
#endif
2121

22+
#if !FOUNDATION_FRAMEWORK
23+
private func autoreleasepool<T>(_ block: () -> T) -> T { block() }
24+
#endif
2225

2326
#if canImport(Glibc)
2427
import Glibc
@@ -27,16 +30,13 @@ import Glibc
2730
import Darwin
2831
#endif
2932

30-
#if !FOUNDATION_FRAMEWORK
31-
func testPath() -> String {
32-
// Generate a random file name
33-
FileManager.default.temporaryDirectory.path.appendingPathComponent("testfile-\(UUID().uuidString)")
34-
}
35-
#else
3633
func testPath() -> URL {
34+
#if compiler(>=6)
3735
FileManager.default.temporaryDirectory.appending(path: "testfile-\(UUID().uuidString)", directoryHint: .notDirectory)
36+
#else
37+
FileManager.default.temporaryDirectory.appendingPathComponent("testfile-\(UUID().uuidString)")
38+
#endif
3839
}
39-
#endif
4040

4141
func generateTestData(count: Int) -> Data {
4242
let memory = malloc(count)!
@@ -51,17 +51,10 @@ func generateTestData(count: Int) -> Data {
5151
return Data(bytesNoCopy: ptr, count: count, deallocator: .free)
5252
}
5353

54-
#if !FOUNDATION_FRAMEWORK
55-
func cleanup(at path: String) {
56-
try? FileManager.default.removeItem(atPath: path)
57-
// Ignore any errors
58-
}
59-
#else
6054
func cleanup(at path: URL) {
6155
try? FileManager.default.removeItem(at: path)
6256
// Ignore any errors
6357
}
64-
#endif
6558

6659
// 16 MB file, big enough to trigger things like chunking
6760
let data = generateTestData(count: 1 << 24)
@@ -74,7 +67,13 @@ let benchmarks = {
7467
Benchmark.defaultConfiguration.maxIterations = 1_000_000_000
7568
Benchmark.defaultConfiguration.maxDuration = .seconds(3)
7669
Benchmark.defaultConfiguration.scalingFactor = .kilo
70+
#if os(macOS)
71+
Benchmark.defaultConfiguration.metrics = [.cpuTotal, .wallClock, .mallocCountTotal, .throughput, .syscalls]
72+
#elseif os(Linux)
73+
Benchmark.defaultConfiguration.metrics = [.cpuTotal, .wallClock, .mallocCountTotal, .throughput, .readSyscalls, .writeSyscalls]
74+
#else
7775
Benchmark.defaultConfiguration.metrics = [.cpuTotal, .wallClock, .mallocCountTotal, .throughput]
76+
#endif
7877

7978
Benchmark("read-write-emptyFile") { benchmark in
8079
let path = testPath()
@@ -118,7 +117,10 @@ let benchmarks = {
118117

119118
// MARK: base64
120119

121-
Benchmark("base64-encode", configuration: .init(scalingFactor: .kilo)) { benchmark in
120+
Benchmark("base64-encode", configuration: .init(
121+
metrics: [.cpuTotal, .mallocCountTotal, .peakMemoryResident, .throughput],
122+
scalingFactor: .kilo)
123+
) { benchmark in
122124
for _ in benchmark.scaledIterations {
123125
autoreleasepool {
124126
blackHole(base64Data.base64EncodedString())
@@ -127,7 +129,10 @@ let benchmarks = {
127129
}
128130

129131

130-
Benchmark("base64-decode", configuration: .init(scalingFactor: .kilo)) { benchmark in
132+
Benchmark("base64-decode", configuration: .init(
133+
metrics: [.cpuTotal, .mallocCountTotal, .peakMemoryResident, .throughput],
134+
scalingFactor: .kilo)
135+
) { benchmark in
131136
for _ in benchmark.scaledIterations {
132137
autoreleasepool {
133138
blackHole(Data(base64Encoded: base64DataString))

Benchmarks/Benchmarks/Essentials/BenchmarkEssentials.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import Benchmark
1414
import func Benchmark.blackHole
1515

16-
#if FOUNDATION_FRAMEWORK
17-
import Foundation
18-
#else
16+
#if os(macOS) && USE_PACKAGE
1917
import FoundationEssentials
18+
#else
19+
import Foundation
2020
#endif
2121

2222
let benchmarks = {

Benchmarks/Benchmarks/Formatting/BenchmarkFormatting.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
import Benchmark
1414
import func Benchmark.blackHole
1515

16-
#if FOUNDATION_FRAMEWORK
17-
import Foundation
18-
#else
16+
#if os(macOS) && USE_PACKAGE
1917
import FoundationEssentials
18+
#else
19+
import Foundation
2020
#endif
2121

2222
let benchmarks = {
@@ -27,6 +27,9 @@ let benchmarks = {
2727

2828
let date = Date(timeIntervalSinceReferenceDate: 665076946.0)
2929

30+
// ISO8601FormatStyle is only available in Swift 6 or newer, macOS 12 or newer
31+
#if compiler(>=6)
32+
3033
let iso8601 = Date.ISO8601FormatStyle()
3134
let formats: [Date.ISO8601FormatStyle] = [
3235
iso8601.year().month().day().dateSeparator(.dash),
@@ -57,4 +60,6 @@ let benchmarks = {
5760
}
5861
}
5962
}
63+
64+
#endif // swift(>=6)
6065
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2022-2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// Swift port of [Native-JSON Benchmark](https://github.com/miloyip/nativejson-benchmark)
14+
/*
15+
The MIT License (MIT)
16+
17+
Copyright (c) 2014 Milo Yip
18+
19+
Permission is hereby granted, free of charge, to any person obtaining a copy
20+
of this software and associated documentation files (the "Software"), to deal
21+
in the Software without restriction, including without limitation the rights
22+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23+
copies of the Software, and to permit persons to whom the Software is
24+
furnished to do so, subject to the following conditions:
25+
26+
The above copyright notice and this permission notice shall be included in all
27+
copies or substantial portions of the Software.
28+
29+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35+
SOFTWARE.
36+
*/
37+
38+
enum ObjType : String, Codable {
39+
case featureCollection = "FeatureCollection"
40+
case feature = "Feature"
41+
case polygon = "Polygon"
42+
}
43+
44+
struct Feature : Codable {
45+
var type: ObjType
46+
var properties: [String: String]
47+
var geometry: Geometry
48+
}
49+
50+
struct Geometry : Codable {
51+
struct Coordinate : Codable {
52+
var latitude: Double
53+
var longitude: Double
54+
55+
init(from decoder: any Decoder) throws {
56+
var container = try decoder.unkeyedContainer()
57+
latitude = try container.decode(Double.self)
58+
longitude = try container.decode(Double.self)
59+
}
60+
61+
func encode(to encoder: any Encoder) throws {
62+
var container = encoder.unkeyedContainer()
63+
try container.encode(latitude)
64+
try container.encode(longitude)
65+
}
66+
}
67+
68+
var type: ObjType
69+
var coordinates: [[Coordinate]]
70+
}
71+
72+
struct FeatureCollection : Codable {
73+
var type: ObjType
74+
var features: [Feature]
75+
}
76+

0 commit comments

Comments
 (0)