Skip to content

Commit 80a84c3

Browse files
committed
Address PR feedback
1 parent 472ce2b commit 80a84c3

File tree

3 files changed

+163
-206
lines changed

3 files changed

+163
-206
lines changed

Benchmarks/Benchmarks/Predicates/Predicates.swift

Lines changed: 52 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -14,221 +14,68 @@ import Benchmark
1414
import func Benchmark.blackHole
1515
import FoundationEssentials
1616

17-
struct Mace {
18-
let p1: Int
19-
let p2: Int
20-
let p3: Int
21-
let p4: Int
22-
let p5: Int
23-
}
24-
25-
struct Sword {
26-
let p1: Int
27-
let p2: Int
28-
let p3: Int
29-
let p4: Int
30-
let p5: Int
31-
}
32-
33-
struct Lightsaber {
34-
let p1: Int
35-
let p2: Int
36-
let p3: Int
37-
let p4: Int
38-
let p5: Int
39-
}
40-
41-
enum Weapon {
42-
case mace(Mace)
43-
case sword(Sword)
44-
case lightsaber(Lightsaber)
45-
46-
var p1: Int {
47-
switch self {
48-
case let .mace(mace):
49-
mace.p1
50-
case let .sword(sword):
51-
sword.p1
52-
case let .lightsaber(lighsaber):
53-
lighsaber.p1
54-
}
55-
}
56-
57-
var p2: Int {
58-
switch self {
59-
case let .mace(mace):
60-
mace.p2
61-
case let .sword(sword):
62-
sword.p2
63-
case let .lightsaber(lighsaber):
64-
lighsaber.p2
65-
}
66-
}
67-
68-
var p3: Int {
69-
switch self {
70-
case let .mace(mace):
71-
mace.p3
72-
case let .sword(sword):
73-
sword.p3
74-
case let .lightsaber(lighsaber):
75-
lighsaber.p3
76-
}
77-
}
78-
79-
var p4: Int {
80-
switch self {
81-
case let .mace(mace):
82-
mace.p4
83-
case let .sword(sword):
84-
sword.p4
85-
case let .lightsaber(lighsaber):
86-
lighsaber.p4
87-
}
88-
}
89-
90-
var p5: Int {
91-
switch self {
92-
case let .mace(mace):
93-
mace.p5
94-
case let .sword(sword):
95-
sword.p5
96-
case let .lightsaber(lighsaber):
97-
lighsaber.p5
98-
}
99-
}
100-
}
101-
102-
struct Monster {
103-
let name: String
104-
var level: Int
105-
var hp: Int
106-
var mana: Int
107-
var weapon: Weapon?
108-
var levelComputed: Int { level }
109-
var weaponP1: Int? { weapon?.p1 }
110-
var weaponP2: Int? { weapon?.p2 }
111-
var weaponP3: Int? { weapon?.p3 }
112-
var weaponP4: Int? { weapon?.p4 }
113-
var weaponP5: Int? { weapon?.p5 }
114-
}
115-
11617
let benchmarks = {
11718
Benchmark.defaultConfiguration.maxIterations = 1_000_000_000
11819
Benchmark.defaultConfiguration.maxDuration = .seconds(5)
11920
Benchmark.defaultConfiguration.scalingFactor = .kilo
21+
Benchmark.defaultConfiguration.metrics = .arc + [.cpuTotal, .wallClock, .mallocCountTotal, .throughput] // use ARC to see traffic
22+
// Benchmark.defaultConfiguration.metrics = [.cpuTotal, .wallClock, .mallocCountTotal, .throughput] // skip ARC as it has some overhead
23+
// Benchmark.defaultConfiguration.metrics = .all // Use all metrics to easily see which ones are of interest for this benchmark suite
12024

12125
if #available(macOS 14, *) {
122-
Benchmark("Predicate #1 - simple 'true' condition") { benchmark in
123-
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
124-
let predicate = #Predicate<Monster> { monster in
125-
true
126-
}
127-
128-
benchmark.startMeasurement()
129-
var matched = 0
130-
for _ in benchmark.scaledIterations {
131-
if try predicate.evaluate(monster) {
132-
matched += 1
26+
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
27+
28+
var predicateTests : [(String, Predicate<Monster>)] = []
29+
30+
predicateTests.append(("Predicate #1 - simple 'true' condition", #Predicate<Monster> { monster in
31+
true
32+
}))
33+
34+
predicateTests.append(("Predicate #2 - 1 KeyPath variable condition", #Predicate<Monster> { monster in
35+
(monster.level == 80)
36+
}))
37+
38+
predicateTests.append(("Predicate #3 - 1 KeyPath computed property condition", #Predicate<Monster> { monster in
39+
(monster.levelComputed == 80)
40+
}))
41+
42+
predicateTests.append(("Predicate #4 - 1 KeyPath nested computed property condition", #Predicate<Monster> { monster in
43+
(monster.weaponP1 == 1)
44+
}))
45+
46+
predicateTests.append(("Predicate #5 - 3 KeyPath nested computed property conditions", #Predicate<Monster> { monster in
47+
((monster.weaponP1 == 1) &&
48+
(monster.weaponP2 == 2) &&
49+
(monster.weaponP3 == 3))
50+
}))
51+
52+
// This test disabled, as enabling it will make compilation fail due to:
53+
// .../swift-foundation/Benchmarks/Benchmarks/Predicates/Predicates.swift:17:5: error: the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions
54+
// let benchmarks = {
55+
// ^~~~~~~~~~~~~~
56+
// error: fatalError
57+
// predicateTests.append(("Predicate #6 - 5 KeyPath nested computed property conditions", #Predicate<Monster> { monster in
58+
// ((monster.weaponP1 == 1) &&
59+
// (monster.weaponP2 == 2) &&
60+
// (monster.weaponP3 == 3) &&
61+
// (monster.weaponP4 == 4) &&
62+
// (monster.weaponP5 == 5))
63+
// }))
64+
65+
predicateTests.forEach { (testDescription, predicate) in
66+
Benchmark(testDescription) { benchmark in
67+
var matched = 0
68+
69+
for _ in benchmark.scaledIterations {
70+
if try predicate.evaluate(monster) {
71+
matched += 1
72+
}
13373
}
134-
}
135-
benchmark.stopMeasurement()
136-
137-
guard matched == benchmark.scaledIterations.count else {
138-
fatalError("Internal error: wrong number of matched monsters")
139-
}
140-
}
141-
}
14274

143-
if #available(macOS 14, *) {
144-
Benchmark("Predicate #2 - 1 KeyPath variable condition") { benchmark in
145-
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
146-
let predicate = #Predicate<Monster> { monster in
147-
(monster.level == 80)
148-
}
149-
150-
benchmark.startMeasurement()
151-
var matched = 0
152-
for _ in benchmark.scaledIterations {
153-
if try predicate.evaluate(monster) {
154-
matched += 1
75+
guard matched == benchmark.scaledIterations.count else {
76+
fatalError("Internal error: wrong number of matched monsters")
15577
}
15678
}
157-
benchmark.stopMeasurement()
158-
159-
guard matched == benchmark.scaledIterations.count else {
160-
fatalError("Internal error: wrong number of matched monsters")
161-
}
162-
}
163-
}
164-
165-
if #available(macOS 14, *) {
166-
Benchmark("Predicate #3 - 1 KeyPath computed property condition") { benchmark in
167-
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
168-
let predicate = #Predicate<Monster> { monster in
169-
(monster.levelComputed == 80)
170-
}
171-
172-
benchmark.startMeasurement()
173-
var matched = 0
174-
for _ in benchmark.scaledIterations {
175-
if try predicate.evaluate(monster) {
176-
matched += 1
177-
}
178-
}
179-
benchmark.stopMeasurement()
180-
181-
guard matched == benchmark.scaledIterations.count else {
182-
fatalError("Internal error: wrong number of matched monsters")
183-
}
184-
}
185-
}
186-
187-
if #available(macOS 14, *) {
188-
Benchmark("Predicate #4 - 1 KeyPath nested computed property condition") { benchmark in
189-
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
190-
let predicate = #Predicate<Monster> { monster in
191-
(monster.weaponP1 == 1)
192-
}
193-
194-
benchmark.startMeasurement()
195-
var matched = 0
196-
for _ in benchmark.scaledIterations {
197-
if try predicate.evaluate(monster) {
198-
matched += 1
199-
}
200-
}
201-
benchmark.stopMeasurement()
202-
203-
guard matched == benchmark.scaledIterations.count else {
204-
fatalError("Internal error: wrong number of matched monsters")
205-
}
206-
}
207-
}
208-
209-
if #available(macOS 14, *) {
210-
Benchmark("Predicate #5 - 3 KeyPath nested computed property conditions") { benchmark in
211-
let monster = Monster(name: "Orc", level: 80, hp: 100, mana: 0, weapon: .sword(Sword(p1: 1, p2: 2, p3: 3, p4: 4, p5: 5)))
212-
let predicate = #Predicate<Monster> { monster in
213-
((monster.weaponP1 == 1) &&
214-
//(monster.weaponP2 == 2) &&
215-
//(monster.weaponP3 == 3) &&
216-
(monster.weaponP4 == 4) &&
217-
(monster.weaponP5 == 5))
218-
}
219-
220-
benchmark.startMeasurement()
221-
var matched = 0
222-
for _ in benchmark.scaledIterations {
223-
if try predicate.evaluate(monster) {
224-
matched += 1
225-
}
226-
}
227-
benchmark.stopMeasurement()
228-
229-
guard matched == benchmark.scaledIterations.count else {
230-
fatalError("Internal error: wrong number of matched monsters")
231-
}
23279
}
23380
}
23481
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
struct Mace {
14+
let p1: Int
15+
let p2: Int
16+
let p3: Int
17+
let p4: Int
18+
let p5: Int
19+
}
20+
21+
struct Sword {
22+
let p1: Int
23+
let p2: Int
24+
let p3: Int
25+
let p4: Int
26+
let p5: Int
27+
}
28+
29+
struct Lightsaber {
30+
let p1: Int
31+
let p2: Int
32+
let p3: Int
33+
let p4: Int
34+
let p5: Int
35+
}
36+
37+
enum Weapon {
38+
case mace(Mace)
39+
case sword(Sword)
40+
case lightsaber(Lightsaber)
41+
42+
var p1: Int {
43+
switch self {
44+
case let .mace(mace):
45+
mace.p1
46+
case let .sword(sword):
47+
sword.p1
48+
case let .lightsaber(lighsaber):
49+
lighsaber.p1
50+
}
51+
}
52+
53+
var p2: Int {
54+
switch self {
55+
case let .mace(mace):
56+
mace.p2
57+
case let .sword(sword):
58+
sword.p2
59+
case let .lightsaber(lighsaber):
60+
lighsaber.p2
61+
}
62+
}
63+
64+
var p3: Int {
65+
switch self {
66+
case let .mace(mace):
67+
mace.p3
68+
case let .sword(sword):
69+
sword.p3
70+
case let .lightsaber(lighsaber):
71+
lighsaber.p3
72+
}
73+
}
74+
75+
var p4: Int {
76+
switch self {
77+
case let .mace(mace):
78+
mace.p4
79+
case let .sword(sword):
80+
sword.p4
81+
case let .lightsaber(lighsaber):
82+
lighsaber.p4
83+
}
84+
}
85+
86+
var p5: Int {
87+
switch self {
88+
case let .mace(mace):
89+
mace.p5
90+
case let .sword(sword):
91+
sword.p5
92+
case let .lightsaber(lighsaber):
93+
lighsaber.p5
94+
}
95+
}
96+
}
97+
98+
struct Monster {
99+
let name: String
100+
var level: Int
101+
var hp: Int
102+
var mana: Int
103+
var weapon: Weapon?
104+
var levelComputed: Int { level }
105+
var weaponP1: Int? { weapon?.p1 }
106+
var weaponP2: Int? { weapon?.p2 }
107+
var weaponP3: Int? { weapon?.p3 }
108+
var weaponP4: Int? { weapon?.p4 }
109+
var weaponP5: Int? { weapon?.p5 }
110+
}

Benchmarks/Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ let package = Package(
1313
],
1414
targets: [
1515
.executableTarget(
16-
name: "Benchmarks",
16+
name: "PredicateBenchmarks",
1717
dependencies: [
1818
.product(name: "FoundationEssentials", package: "swift-foundation"),
1919
.product(name: "Benchmark", package: "package-benchmark"),

0 commit comments

Comments
 (0)