Skip to content

An additional benchmark for KeyPath read performance. #61795

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 21 commits into from
Nov 7, 2022
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0089a50
Add benchmarks that measure KeyPath read and write performance.
fibrechannelscsi Aug 3, 2022
7c4fd37
Added setUpFunctions. Revised number of iterations per benchmark.
fibrechannelscsi Aug 5, 2022
ea9984b
Include n as a factor in the number of iterations.
fibrechannelscsi Aug 5, 2022
578ce7d
Increased number of iterations for KeyPathDirectAccess by a factor of…
fibrechannelscsi Aug 8, 2022
14ef45a
One last tweak to the number of iterations on testDirectAccess to get…
fibrechannelscsi Aug 8, 2022
2efa8eb
Made revisions based on feedback. Added three new benchmarks.
fibrechannelscsi Aug 11, 2022
221c0e5
Added benchmarks to exhaustively benchmark all KeyPathComponent types…
fibrechannelscsi Aug 16, 2022
1b7d834
Wrapped additional keypaths with identity() where needed. More cleanu…
fibrechannelscsi Aug 16, 2022
8562c6a
Moved KeyPaths for KeyPathRead and Write into FixedSizeArrayHolder. R…
fibrechannelscsi Aug 17, 2022
0db40a0
Added inline(never) to both versions of getKeypathToElement().
fibrechannelscsi Aug 19, 2022
1c9ba16
Moved identity() wraps so that they're called once per variable per b…
fibrechannelscsi Aug 22, 2022
34d0ac0
Moving destinationKeyPaths into FixedSizeArrayHolder to try to reduce…
fibrechannelscsi Aug 23, 2022
ceb69d0
Additional moving of the identity() wrapping into the singleton's ini…
fibrechannelscsi Aug 23, 2022
cc41b97
Merge branch 'apple:main' into main
fibrechannelscsi Aug 24, 2022
66c6f7d
Proposed design for skipping of KeyPath projections across trivially-…
fibrechannelscsi Aug 24, 2022
0378bf5
Merge branch 'main' of github.com:fibrechannelscsi/keypath-benchmarks
fibrechannelscsi Aug 24, 2022
14436a0
Clarified a comment in isTuple().
fibrechannelscsi Aug 24, 2022
ad68085
Added a benchmark for KeyPaths where trivially-typed memory is preced…
fibrechannelscsi Oct 28, 2022
0751362
Merge branch 'main' into more-keypath-benchmarks
fibrechannelscsi Nov 3, 2022
c1e03a1
Fixing bad rebase on KeyPath.swift.
fibrechannelscsi Nov 4, 2022
f526e08
Reduces the workload of run_KeyPathClassStructs by a factor of 4.
fibrechannelscsi Nov 4, 2022
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
74 changes: 74 additions & 0 deletions benchmark/single-source/KeyPathPerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ public let benchmarks = [
tags: [.validation, .api],
setUpFunction: setupKeyPathNestedStructs
),
BenchmarkInfo(
name: "KeyPathClassStructs",
runFunction: run_KeyPathClassStructs,
tags: [.validation, .api],
setUpFunction: setupKeyPathNestedStructs
),
]

/**
Expand Down Expand Up @@ -97,6 +103,7 @@ class FixedSizeArrayHolder {
var fixedSizeArray100: FixedSizeArray100<ElementType>
var fixedSizeArray10: FixedSizeArray10<ElementType>
var mainArrayForNestedStructs: [A]
var mainArrayForClassStructs: [D1]
var arrayForMutatingGetset: [MutatingGetsetNested1]
var arrayForGet: [GetNested1]
var arrayForOptionals: [Optional1]
Expand All @@ -107,6 +114,7 @@ class FixedSizeArrayHolder {
var keypathForOptional: KeyPath<Optional1, Int?>
var keypathForNestedClasses: KeyPath<C1, Int>
var keypathForNonMutatingGetset: WritableKeyPath<M, Int>
var keypathForClassStructs: WritableKeyPath<D1, Int>

// Same order as in KeyPathWritePerformance
var kp46: WritableKeyPath<FixedSizeArray100<ElementType>, ElementType>
Expand Down Expand Up @@ -176,6 +184,7 @@ class FixedSizeArrayHolder {
fixedSizeArray100 = initializeFixedSizeArray100()
fixedSizeArray10 = initializeFixedSizeArray10()
mainArrayForNestedStructs = [A]()
mainArrayForClassStructs = [D1]()
arrayForMutatingGetset = [MutatingGetsetNested1]()
arrayForGet = [GetNested1]()
arrayForOptionals = [Optional1]()
Expand Down Expand Up @@ -252,6 +261,7 @@ class FixedSizeArrayHolder {
._nestedItemStorage?!._nestedItemStorage?!._storage)
keypathForNestedClasses = identity(\C1.r.r.r.r.a)
keypathForNonMutatingGetset = identity(\M.n.o.p.q.q)
keypathForClassStructs = identity(\D1.b.c.d.e.e)
}
}

Expand All @@ -262,6 +272,10 @@ public func setupKeyPathNestedStructs() {
let instance = A(a: 0, b: B(b: 0, c: C(c: 0, d: D(d: 0, e: E(e: expectedIntForNestedItems)))))
holder.mainArrayForNestedStructs.append(instance)

let classStructInstance = D1(b: D2(b: 0, c: D3(c: 0, d: D4(d: 0,
e: D5(e: expectedIntForNestedItems)))))
holder.mainArrayForClassStructs.append(classStructInstance)

var mutatingGetsetInstance = MutatingGetsetNested1()
mutatingGetsetInstance.nestedItem.nestedItem.nestedItem.nestedItem
.storage = expectedIntForNestedItems
Expand Down Expand Up @@ -333,6 +347,36 @@ struct E {
var e: Int
}

// Used for run_KeyPathClassStruct().
class D1 {
var a: Int
var b: D2
init(b: D2)
{
a = 0
self.b = b
}
}

struct D2 {
var b: Int
var c: D3
}

struct D3 {
var c: Int
var d: D4
}

struct D4 {
var d: Int
var e: D5
}

struct D5 {
var e: Int
}

// Used for run_KeyPathNestedClasses()
class C1 {
let a: Int = 0
Expand Down Expand Up @@ -1326,6 +1370,36 @@ public func run_KeyPathNestedStructs(n: Int) {
check(sum == iterationMultipier * n * expectedIntForNestedItems)
}

// This measures the performance of keypath reads where a block of
// trivially-typed memory is preceded by something else (optionals, reference
// types, etc.)
@inline(never)
public func run_KeyPathClassStructs(n: Int) {
var sum = 0
var index = 0
let iterationMultipier = 500

let singleHopKeyPath0: WritableKeyPath<D1, D2> = \D1.b
let singleHopKeyPath1: WritableKeyPath<D2, D3> = \D2.c
let singleHopKeyPath2: WritableKeyPath<D3, D4> = \D3.d
let singleHopKeyPath3: WritableKeyPath<D4, D5> = \D4.e
let singleHopKeyPath4: WritableKeyPath<D5, Int> = \D5.e

let appendedKeyPath = identity(singleHopKeyPath0.appending(path: singleHopKeyPath1)
.appending(path: singleHopKeyPath2).appending(path: singleHopKeyPath3)
.appending(path: singleHopKeyPath4))

let elementCount = FixedSizeArrayHolder.shared.mainArrayForClassStructs.count
for _ in 1 ... iterationMultipier * n {
let element = FixedSizeArrayHolder.shared.mainArrayForClassStructs[index]
sum += element[keyPath: appendedKeyPath]
index = (index + 1) % elementCount
}
check(sum == iterationMultipier * n * expectedIntForNestedItems)
}



// This is meant as a baseline, from a timing perspective,
// for run_testKeyPathReadPerformance() and run_testKeyPathWritePerformance().
// It's currently set to ".skip", but is useful for comparing the performance between keypath operations and direct dot-notation.
Expand Down