From afce51392d74484bf523c07d37aa07d20f5d8555 Mon Sep 17 00:00:00 2001 From: fibrechannelscsi <110562401+fibrechannelscsi@users.noreply.github.com> Date: Mon, 7 Nov 2022 15:52:25 -0700 Subject: [PATCH] An additional benchmark for KeyPath read performance. (#61795) * Added a benchmark for KeyPaths where trivially-typed memory is preceded by non-trivially-typed memory. * Reduces the workload of run_KeyPathClassStructs by a factor of 4. The reported time was 1847 us. --- .../KeyPathPerformanceTests.swift | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/benchmark/single-source/KeyPathPerformanceTests.swift b/benchmark/single-source/KeyPathPerformanceTests.swift index f1d5c69c9347f..98fa4f76d20e6 100644 --- a/benchmark/single-source/KeyPathPerformanceTests.swift +++ b/benchmark/single-source/KeyPathPerformanceTests.swift @@ -66,6 +66,12 @@ public let benchmarks = [ tags: [.validation, .api], setUpFunction: setupKeyPathNestedStructs ), + BenchmarkInfo( + name: "KeyPathClassStructs", + runFunction: run_KeyPathClassStructs, + tags: [.validation, .api], + setUpFunction: setupKeyPathNestedStructs + ), ] /** @@ -97,6 +103,7 @@ class FixedSizeArrayHolder { var fixedSizeArray100: FixedSizeArray100 var fixedSizeArray10: FixedSizeArray10 var mainArrayForNestedStructs: [A] + var mainArrayForClassStructs: [D1] var arrayForMutatingGetset: [MutatingGetsetNested1] var arrayForGet: [GetNested1] var arrayForOptionals: [Optional1] @@ -107,6 +114,7 @@ class FixedSizeArrayHolder { var keypathForOptional: KeyPath var keypathForNestedClasses: KeyPath var keypathForNonMutatingGetset: WritableKeyPath + var keypathForClassStructs: WritableKeyPath // Same order as in KeyPathWritePerformance var kp46: WritableKeyPath, ElementType> @@ -176,6 +184,7 @@ class FixedSizeArrayHolder { fixedSizeArray100 = initializeFixedSizeArray100() fixedSizeArray10 = initializeFixedSizeArray10() mainArrayForNestedStructs = [A]() + mainArrayForClassStructs = [D1]() arrayForMutatingGetset = [MutatingGetsetNested1]() arrayForGet = [GetNested1]() arrayForOptionals = [Optional1]() @@ -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) } } @@ -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 @@ -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 @@ -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.b + let singleHopKeyPath1: WritableKeyPath = \D2.c + let singleHopKeyPath2: WritableKeyPath = \D3.d + let singleHopKeyPath3: WritableKeyPath = \D4.e + let singleHopKeyPath4: WritableKeyPath = \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.