diff --git a/benchmark/single-source/ArrayInClass.swift b/benchmark/single-source/ArrayInClass.swift index 3aa94d0111905..27360590592e8 100644 --- a/benchmark/single-source/ArrayInClass.swift +++ b/benchmark/single-source/ArrayInClass.swift @@ -11,12 +11,19 @@ //===----------------------------------------------------------------------===// import TestsUtils -public let ArrayInClass = BenchmarkInfo( - name: "ArrayInClass", - runFunction: run_ArrayInClass, - tags: [.validation, .api, .Array], - setUpFunction: { ac = ArrayContainer() }, - tearDownFunction: { ac = nil }) +public let ArrayInClass = [ + BenchmarkInfo( + name: "ArrayInClass", + runFunction: run_ArrayInClass, + tags: [.validation, .api, .Array], + setUpFunction: { ac = ArrayContainer() }, + tearDownFunction: { ac = nil }), + BenchmarkInfo(name: "DistinctClassFieldAccesses", + runFunction: run_DistinctClassFieldAccesses, + tags: [.unstable, .api, .Array], + setUpFunction: { workload = ClassWithArrs(N: 100_000) }, + tearDownFunction: { workload = nil }), +] var ac: ArrayContainer! @@ -41,3 +48,38 @@ public func run_ArrayInClass(_ N: Int) { let a = ac! a.runLoop(N) } + +class ClassWithArrs { + var N: Int = 0 + var A: [Int] + var B: [Int] + + init(N: Int) { + self.N = N + + A = [Int](repeating: 0, count: N) + B = [Int](repeating: 0, count: N) + } + + func readArr() { + for i in 0..(_: T.Type) { + array = Array(repeating: T(), count: 128) +} +func caVal0() { ca(Val0.self) } +func caVal1() { ca(Val1.self) } +func caVal2() { ca(Val2.self) } +func caVal3() { ca(Val3.self) } +func caVal4() { ca(Val4.self) } +func caRef1() { ca(Ref1.self) } +func caRef2() { ca(Ref2.self) } +func caRef3() { ca(Ref3.self) } +func caRef4() { ca(Ref4.self) } +@inline(never) +func grabArray() -> [Existential] { // transfer array ownership to caller + // FIXME: This is causing Illegal Instruction: 4 crash + // defer { array = nil } + // return array + // This doesn't work either: + // let a = array! + // array = nil + // return a + return array! +} + +// `setUpFunctions` that determine which existential type will be tested +var existentialType: Existential.Type! +func etVal0() { existentialType = Val0.self } +func etVal1() { existentialType = Val1.self } +func etVal2() { existentialType = Val2.self } +func etVal3() { existentialType = Val3.self } +func etVal4() { existentialType = Val4.self } +func etRef1() { existentialType = Ref1.self } +func etRef2() { existentialType = Ref2.self } +func etRef3() { existentialType = Ref3.self } +func etRef4() { existentialType = Ref4.self } protocol Existential { init() @@ -160,7 +295,11 @@ protocol Existential { mutating func mutateIt() -> Bool } -struct IntValueBuffer0 : Existential { +func next(_ x: inout Int, upto mod: Int) { + x = (x + 1) % (mod + 1) +} + +struct Val0 : Existential { func doIt() -> Bool { return true } @@ -172,11 +311,7 @@ struct IntValueBuffer0 : Existential { } } -func next(_ x: inout Int, upto mod: Int) { - x = (x + 1) % (mod + 1) -} - -struct IntValueBuffer1 : Existential { +struct Val1 : Existential { var f0: Int = 0 func doIt() -> Bool { @@ -186,12 +321,12 @@ struct IntValueBuffer1 : Existential { return true } mutating func mutateIt() -> Bool { - next(&f0, upto: 1) + next(&f0, upto: 1) return true } } -struct IntValueBuffer2 : Existential { +struct Val2 : Existential { var f0: Int = 0 var f1: Int = 3 @@ -199,7 +334,7 @@ struct IntValueBuffer2 : Existential { return f0 == 0 } func reallyDoIt() -> Bool { - return f0 == 0 && f1 == 3 + return f0 == 0 && f1 == 3 } mutating func mutateIt() -> Bool { next(&f0, upto: 1) @@ -208,7 +343,7 @@ struct IntValueBuffer2 : Existential { } } -struct IntValueBuffer3 : Existential { +struct Val3 : Existential { var f0: Int = 0 var f1: Int = 3 var f2: Int = 7 @@ -217,10 +352,9 @@ struct IntValueBuffer3 : Existential { return f0 == 0 } func reallyDoIt() -> Bool { - return f0 == 0 && f1 == 3 && f2 == 7 + return f0 == 0 && f1 == 3 && f2 == 7 } - - mutating func mutateIt() -> Bool{ + mutating func mutateIt() -> Bool { next(&f0, upto: 1) next(&f1, upto: 3) next(&f2, upto: 7) @@ -228,7 +362,7 @@ struct IntValueBuffer3 : Existential { } } -struct IntValueBuffer4 : Existential { +struct Val4 : Existential { var f0: Int = 0 var f1: Int = 3 var f2: Int = 7 @@ -238,10 +372,9 @@ struct IntValueBuffer4 : Existential { return f0 == 0 } func reallyDoIt() -> Bool { - return f0 == 0 && f1 == 3 && f2 == 7 && f3 == 13 + return f0 == 0 && f1 == 3 && f2 == 7 && f3 == 13 } - - mutating func mutateIt() -> Bool{ + mutating func mutateIt() -> Bool { next(&f0, upto: 1) next(&f1, upto: 3) next(&f2, upto: 7) @@ -250,7 +383,7 @@ struct IntValueBuffer4 : Existential { } } -class Klazz { +class Klazz { // body same as Val2 var f0: Int = 0 var f1: Int = 3 @@ -260,7 +393,6 @@ class Klazz { func reallyDoIt() -> Bool { return f0 == 0 && f1 == 3 } - func mutateIt() -> Bool{ next(&f0, upto: 1) next(&f1, upto: 3) @@ -268,7 +400,7 @@ class Klazz { } } -struct ClassValueBuffer1 : Existential { +struct Ref1 : Existential { var f0: Klazz = Klazz() func doIt() -> Bool { @@ -277,13 +409,12 @@ struct ClassValueBuffer1 : Existential { func reallyDoIt() -> Bool { return f0.reallyDoIt() } - mutating func mutateIt() -> Bool{ return f0.mutateIt() } } -struct ClassValueBuffer2 : Existential { +struct Ref2 : Existential { var f0: Klazz = Klazz() var f1: Klazz = Klazz() @@ -293,13 +424,12 @@ struct ClassValueBuffer2 : Existential { func reallyDoIt() -> Bool { return f0.reallyDoIt() } - mutating func mutateIt() -> Bool{ return f0.mutateIt() } } -struct ClassValueBuffer3 : Existential { +struct Ref3 : Existential { var f0: Klazz = Klazz() var f1: Klazz = Klazz() var f2: Klazz = Klazz() @@ -310,26 +440,23 @@ struct ClassValueBuffer3 : Existential { func reallyDoIt() -> Bool { return f0.reallyDoIt() } - mutating func mutateIt() -> Bool{ return f0.mutateIt() } } -struct ClassValueBuffer4 : Existential { +struct Ref4 : Existential { var f0: Klazz = Klazz() var f1: Klazz = Klazz() var f2: Klazz = Klazz() - var f3: Int = 0 + var f3: Int = 0 func doIt() -> Bool { return f0.doIt() } - func reallyDoIt() -> Bool { return f0.reallyDoIt() } - mutating func mutateIt() -> Bool{ return f0.mutateIt() } @@ -337,473 +464,136 @@ struct ClassValueBuffer4 : Existential { @inline(never) -func initExistential(withType: T.Type) -> Existential { - return T() -} - -@inline(never) -func initExistentialArray(withType: T.Type, count c: Int) -> [Existential] { - return [T](repeating: T(), count: c) -} - -@inline(never) -func passExistentialTwiceOneMethodCall(_ e0: Existential, _ e1: Existential) -> Bool { +func passExistentialTwiceOneMethodCall(_ e0: Existential, _ e1: Existential) + -> Bool { return e0.doIt() && e1.doIt() } @inline(never) -func passExistentialTwiceTwoMethodCalls(_ e0: Existential, _ e1: Existential) -> Bool { +func passExistentialTwiceTwoMethodCalls(_ e0: Existential, _ e1: Existential) + -> Bool { return e0.doIt() && e1.doIt() && e0.reallyDoIt() && e1.reallyDoIt() } -func runTestOneMethodCall(withType: T.Type, numberOfTimes N: Int) { - let existential = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - if !existential.doIt() { - fatalError("expected true") - } +func run_method1x(_ N: Int) { + let existential = existentialType.init() + for _ in 0 ..< N * 20_000 { + if !existential.doIt() { + fatalError("expected true") } } } -func runTestTwoMethodCalls(withType: T.Type, numberOfTimes N: Int) { - let existential = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - if !existential.doIt() || !existential.reallyDoIt() { - fatalError("expected true") - } +func run_method2x(_ N: Int) { + let existential = existentialType.init() + for _ in 0 ..< N * 20_000 { + if !existential.doIt() || !existential.reallyDoIt() { + fatalError("expected true") } } } -func runTestPassExistentialOneMethodCall(withType: T.Type, numberOfTimes N: Int) { - let existential = initExistential(withType: T.self) - let existential2 = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - if !passExistentialTwiceOneMethodCall(existential, existential2) { - fatalError("expected true") - } +func run_Pass_method1x(_ N: Int) { + let existential = existentialType.init() + let existential2 = existentialType.init() + for _ in 0 ..< N * 20_000 { + if !passExistentialTwiceOneMethodCall(existential, existential2) { + fatalError("expected true") } } } -func runTestPassExistentialTwoMethodCalls(withType: T.Type, numberOfTimes N: Int) { - let existential = initExistential(withType: T.self) - let existential2 = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - if !passExistentialTwiceTwoMethodCalls(existential, existential2) { - fatalError("expected true") - } +func run_Pass_method2x(_ N: Int) { + let existential = existentialType.init() + let existential2 = existentialType.init() + for _ in 0 ..< N * 20_000 { + if !passExistentialTwiceTwoMethodCalls(existential, existential2) { + fatalError("expected true") } } } -func runTestMutating(withType: T.Type, numberOfTimes N: Int) { - var existential = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - if !existential.mutateIt() { - fatalError("expected true") - } +func run_Mutating(_ N: Int) { + var existential = existentialType.init() + for _ in 0 ..< N * 10_000 { + if !existential.mutateIt() { + fatalError("expected true") } } } -func runTestMutatingAndNonMutating(withType: T.Type, numberOfTimes N: Int) { - var existential = initExistential(withType: T.self) - for _ in 0 ..< N { - for _ in 0 ..< 5_000_000 { - let _ = existential.doIt() - if !existential.mutateIt() { - fatalError("expected true") - } +func run_MutatingAndNonMutating(_ N: Int) { + var existential = existentialType.init() + for _ in 0 ..< N * 10_000 { + let _ = existential.doIt() + if !existential.mutateIt() { + fatalError("expected true") } } } -func runTestArrayOneMethodCall(withType: T.Type, numberOfTimes N: Int) { - let existentialArray = initExistentialArray(withType: T.self, count: 128) - for _ in 0 ..< N { - for _ in 0 ..< 5_000 { - for elt in existentialArray { - if !elt.doIt() { - fatalError("expected true") - } - } - } +func run_Array_init(_ N: Int) { + + for _ in 0 ..< N * 100 { + blackHole(Array(repeating: existentialType.init(), count: 128)) } } -func runTestArrayTwoMethodCalls(withType: T.Type, numberOfTimes N: Int) { - let existentialArray = initExistentialArray(withType: T.self, count: 128) - for _ in 0 ..< N { - for _ in 0 ..< 5_000 { - for elt in existentialArray { - if !elt.doIt() || !elt.reallyDoIt() { - fatalError("expected true") - } +func run_Array_method1x(_ N: Int) { + let existentialArray = grabArray() + for _ in 0 ..< N * 100 { + for elt in existentialArray { + if !elt.doIt() { + fatalError("expected true") } } } } -func runTestArrayMutating(withType: T.Type, numberOfTimes N: Int) { - var existentialArray = initExistentialArray(withType: T.self, count: 128) - for _ in 0 ..< N { - for _ in 0 ..< 5_000 { - for i in 0 ..< existentialArray.count { - if !existentialArray[i].mutateIt() { - fatalError("expected true") - } +func run_Array_method2x(_ N: Int) { + let existentialArray = grabArray() + for _ in 0 ..< N * 100 { + for elt in existentialArray { + if !elt.doIt() || !elt.reallyDoIt() { + fatalError("expected true") } } } } -func runTestArrayShift(withType: T.Type, numberOfTimes N: Int) { - var existentialArray = initExistentialArray(withType: T.self, count: 128) - for _ in 0 ..< N { - for _ in 0 ..< 5_000 { - for i in 0 ..< existentialArray.count-1 { - existentialArray.swapAt(i, i+1) +func run_ArrayMutating(_ N: Int) { + var existentialArray = grabArray() + for _ in 0 ..< N * 100 { + for i in 0 ..< existentialArray.count { + if !existentialArray[i].mutateIt() { + fatalError("expected true") } } } } -func runTestArrayConditionalShift(withType: T.Type, numberOfTimes N: Int) { - var existentialArray = initExistentialArray(withType: T.self, count: 128) - for _ in 0 ..< N { - for _ in 0 ..< 5_000 { - for i in 0 ..< existentialArray.count-1 { - let curr = existentialArray[i] - if curr.doIt() { - existentialArray[i] = existentialArray[i+1] - existentialArray[i+1] = curr - } - } + +func run_ArrayShift(_ N: Int) { + var existentialArray = grabArray() + for _ in 0 ..< N * 25 { + for i in 0 ..< existentialArray.count-1 { + existentialArray.swapAt(i, i+1) } } } -// TestOneMethodCall. -public func run_ExistentialTestOneMethodCall_IntValueBuffer0(_ N: Int) { - runTestOneMethodCall(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_IntValueBuffer1(_ N: Int) { - runTestOneMethodCall(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_IntValueBuffer2(_ N: Int) { - runTestOneMethodCall(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_IntValueBuffer3(_ N: Int) { - runTestOneMethodCall(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_IntValueBuffer4(_ N: Int) { - runTestOneMethodCall(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_ClassValueBuffer1(_ N: Int) { - runTestOneMethodCall(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_ClassValueBuffer2(_ N: Int) { - runTestOneMethodCall(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_ClassValueBuffer3(_ N: Int) { - runTestOneMethodCall(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestOneMethodCall_ClassValueBuffer4(_ N: Int) { - runTestOneMethodCall(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestTwoMethodCalls. -public func run_ExistentialTestTwoMethodCalls_IntValueBuffer0(_ N: Int) { - runTestTwoMethodCalls(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_IntValueBuffer1(_ N: Int) { - runTestTwoMethodCalls(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_IntValueBuffer2(_ N: Int) { - runTestTwoMethodCalls(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_IntValueBuffer3(_ N: Int) { - runTestTwoMethodCalls(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_IntValueBuffer4(_ N: Int) { - runTestTwoMethodCalls(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_ClassValueBuffer1(_ N: Int) { - runTestTwoMethodCalls(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_ClassValueBuffer2(_ N: Int) { - runTestTwoMethodCalls(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_ClassValueBuffer3(_ N: Int) { - runTestTwoMethodCalls(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestTwoMethodCalls_ClassValueBuffer4(_ N: Int) { - runTestTwoMethodCalls(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestPassExistentialOneMethodCall. -public func run_ExistentialTestPassExistentialOneMethodCall_IntValueBuffer0(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_IntValueBuffer1(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_IntValueBuffer2(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_IntValueBuffer3(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_IntValueBuffer4(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_ClassValueBuffer1(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_ClassValueBuffer2(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_ClassValueBuffer3(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialOneMethodCall_ClassValueBuffer4(_ N: Int) { - runTestPassExistentialOneMethodCall(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestPassExistentialTwoMethodCalls. -public func run_ExistentialTestPassExistentialTwoMethodCalls_IntValueBuffer0(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_IntValueBuffer1(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_IntValueBuffer2(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_IntValueBuffer3(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_IntValueBuffer4(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_ClassValueBuffer1(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_ClassValueBuffer2(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_ClassValueBuffer3(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestPassExistentialTwoMethodCalls_ClassValueBuffer4(_ N: Int) { - runTestPassExistentialTwoMethodCalls(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestMutating. -public func run_ExistentialTestMutating_IntValueBuffer0(_ N: Int) { - runTestMutating(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_IntValueBuffer1(_ N: Int) { - runTestMutating(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_IntValueBuffer2(_ N: Int) { - runTestMutating(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_IntValueBuffer3(_ N: Int) { - runTestMutating(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_IntValueBuffer4(_ N: Int) { - runTestMutating(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_ClassValueBuffer1(_ N: Int) { - runTestMutating(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_ClassValueBuffer2(_ N: Int) { - runTestMutating(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_ClassValueBuffer3(_ N: Int) { - runTestMutating(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestMutating_ClassValueBuffer4(_ N: Int) { - runTestMutating(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestMutatingAndNonMutating. -public func run_ExistentialTestMutatingAndNonMutating_IntValueBuffer0(_ N: Int) { - runTestMutatingAndNonMutating(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_IntValueBuffer1(_ N: Int) { - runTestMutatingAndNonMutating(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_IntValueBuffer2(_ N: Int) { - runTestMutatingAndNonMutating(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_IntValueBuffer3(_ N: Int) { - runTestMutatingAndNonMutating(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_IntValueBuffer4(_ N: Int) { - runTestMutatingAndNonMutating(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_ClassValueBuffer1(_ N: Int) { - runTestMutatingAndNonMutating(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_ClassValueBuffer2(_ N: Int) { - runTestMutatingAndNonMutating(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_ClassValueBuffer3(_ N: Int) { - runTestMutatingAndNonMutating(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestMutatingAndNonMutating_ClassValueBuffer4(_ N: Int) { - runTestMutatingAndNonMutating(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestArrayOneMethodCall. -public func run_ExistentialTestArrayOneMethodCall_IntValueBuffer0(_ N: Int) { - runTestArrayOneMethodCall(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_IntValueBuffer1(_ N: Int) { - runTestArrayOneMethodCall(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_IntValueBuffer2(_ N: Int) { - runTestArrayOneMethodCall(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_IntValueBuffer3(_ N: Int) { - runTestArrayOneMethodCall(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_IntValueBuffer4(_ N: Int) { - runTestArrayOneMethodCall(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_ClassValueBuffer1(_ N: Int) { - runTestArrayOneMethodCall(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_ClassValueBuffer2(_ N: Int) { - runTestArrayOneMethodCall(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_ClassValueBuffer3(_ N: Int) { - runTestArrayOneMethodCall(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayOneMethodCall_ClassValueBuffer4(_ N: Int) { - runTestArrayOneMethodCall(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestArrayTwoMethodCalls. -public func run_ExistentialTestArrayTwoMethodCalls_IntValueBuffer0(_ N: Int) { - runTestArrayTwoMethodCalls(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_IntValueBuffer1(_ N: Int) { - runTestArrayTwoMethodCalls(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_IntValueBuffer2(_ N: Int) { - runTestArrayTwoMethodCalls(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_IntValueBuffer3(_ N: Int) { - runTestArrayTwoMethodCalls(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_IntValueBuffer4(_ N: Int) { - runTestArrayTwoMethodCalls(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_ClassValueBuffer1(_ N: Int) { - runTestArrayTwoMethodCalls(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_ClassValueBuffer2(_ N: Int) { - runTestArrayTwoMethodCalls(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_ClassValueBuffer3(_ N: Int) { - runTestArrayTwoMethodCalls(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayTwoMethodCalls_ClassValueBuffer4(_ N: Int) { - runTestArrayTwoMethodCalls(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestArrayMutating. -public func run_ExistentialTestArrayMutating_IntValueBuffer0(_ N: Int) { - runTestArrayMutating(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_IntValueBuffer1(_ N: Int) { - runTestArrayMutating(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_IntValueBuffer2(_ N: Int) { - runTestArrayMutating(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_IntValueBuffer3(_ N: Int) { - runTestArrayMutating(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_IntValueBuffer4(_ N: Int) { - runTestArrayMutating(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_ClassValueBuffer1(_ N: Int) { - runTestArrayMutating(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_ClassValueBuffer2(_ N: Int) { - runTestArrayMutating(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_ClassValueBuffer3(_ N: Int) { - runTestArrayMutating(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayMutating_ClassValueBuffer4(_ N: Int) { - runTestArrayMutating(withType: ClassValueBuffer4.self, numberOfTimes: N) -} - -// TestArrayShift. -public func run_ExistentialTestArrayShift_IntValueBuffer0(_ N: Int) { - runTestArrayShift(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_IntValueBuffer1(_ N: Int) { - runTestArrayShift(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_IntValueBuffer2(_ N: Int) { - runTestArrayShift(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_IntValueBuffer3(_ N: Int) { - runTestArrayShift(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_IntValueBuffer4(_ N: Int) { - runTestArrayShift(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_ClassValueBuffer1(_ N: Int) { - runTestArrayShift(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_ClassValueBuffer2(_ N: Int) { - runTestArrayShift(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_ClassValueBuffer3(_ N: Int) { - runTestArrayShift(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayShift_ClassValueBuffer4(_ N: Int) { - runTestArrayShift(withType: ClassValueBuffer4.self, numberOfTimes: N) +func run_ArrayConditionalShift(_ N: Int) { + var existentialArray = grabArray() + for _ in 0 ..< N * 25 { + for i in 0 ..< existentialArray.count-1 { + let curr = existentialArray[i] + if curr.doIt() { + existentialArray[i] = existentialArray[i+1] + existentialArray[i+1] = curr + } + } + } } -// TestArrayConditionalShift. -public func run_ExistentialTestArrayConditionalShift_IntValueBuffer0(_ N: Int) { - runTestArrayConditionalShift(withType: IntValueBuffer0.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_IntValueBuffer1(_ N: Int) { - runTestArrayConditionalShift(withType: IntValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_IntValueBuffer2(_ N: Int) { - runTestArrayConditionalShift(withType: IntValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_IntValueBuffer3(_ N: Int) { - runTestArrayConditionalShift(withType: IntValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_IntValueBuffer4(_ N: Int) { - runTestArrayConditionalShift(withType: IntValueBuffer4.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_ClassValueBuffer1(_ N: Int) { - runTestArrayConditionalShift(withType: ClassValueBuffer1.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_ClassValueBuffer2(_ N: Int) { - runTestArrayConditionalShift(withType: ClassValueBuffer2.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_ClassValueBuffer3(_ N: Int) { - runTestArrayConditionalShift(withType: ClassValueBuffer3.self, numberOfTimes: N) -} -public func run_ExistentialTestArrayConditionalShift_ClassValueBuffer4(_ N: Int) { - runTestArrayConditionalShift(withType: ClassValueBuffer4.self, numberOfTimes: N) -} +// Local Variables: +// eval: (read-only-mode 1) +// End: diff --git a/benchmark/single-source/ExistentialPerformance.swift.gyb b/benchmark/single-source/ExistentialPerformance.swift.gyb new file mode 100644 index 0000000000000..567ce6b785a5f --- /dev/null +++ b/benchmark/single-source/ExistentialPerformance.swift.gyb @@ -0,0 +1,261 @@ +//===--- ExistentialPerformance.swift -------------------------*- swift -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +% # Ignore the following warning. This _is_ the correct file to edit. +//////////////////////////////////////////////////////////////////////////////// +// WARNING: This file is manually generated from .gyb template and should not +// be directly modified. Instead, change ExistentialPerformance.swift.gyb +// and run scripts/generate_harness/generate_harness.py to regenerate this file. +//////////////////////////////////////////////////////////////////////////////// + +import TestsUtils + +// The purpose of these benchmarks is to evaluate different scenarios when +// moving the implementation of existentials (protocol values) to heap based +// copy-on-write buffers. +// +// The performance boost of `Ref4` vs `Ref3` is expected because copying the +// existential only involves copying one reference of the heap based +// copy-on-write buffer (outline case) that holds the struct vs copying the +// individual fields of the struct in the inline case of `Ref3`. + +let t: [BenchmarkCategory] = [.skip] +let ta: [BenchmarkCategory] = [.api, .Array, .skip] + +%{ +Setup = """ + let existential = existentialType.init() + let existential2 = existentialType.init() + var existential = existentialType.init() + let existentialArray = grabArray() + var existentialArray = grabArray() +""".splitlines() +Setup = [Setup[0], Setup[1], '\n'.join(Setup[1:3]), Setup[3], Setup[4], Setup[5]] + +Workloads = [ + ('method.1x', Setup[1], '20_000', """ + if !existential.doIt() { + fatalError("expected true") + } +"""), + ('method.2x', Setup[1], '20_000', """ + if !existential.doIt() || !existential.reallyDoIt() { + fatalError("expected true") + } +"""), + ('Pass.method.1x', Setup[2], '20_000', """ + if !passExistentialTwiceOneMethodCall(existential, existential2) { + fatalError("expected true") + } +"""), + ('Pass.method.2x', Setup[2], '20_000', """ + if !passExistentialTwiceTwoMethodCalls(existential, existential2) { + fatalError("expected true") + } +"""), + ('Mutating', Setup[3], '10_000', """ + if !existential.mutateIt() { + fatalError("expected true") + } +"""), + ('MutatingAndNonMutating', Setup[3], '10_000', """ + let _ = existential.doIt() + if !existential.mutateIt() { + fatalError("expected true") + } +"""), + ('Array.init', Setup[0], '100', """ + blackHole(Array(repeating: existentialType.init(), count: 128)) +"""), + ('Array.method.1x', Setup[4], '100', """ + for elt in existentialArray { + if !elt.doIt() { + fatalError("expected true") + } + } +"""), + ('Array.method.2x', Setup[4], '100', """ + for elt in existentialArray { + if !elt.doIt() || !elt.reallyDoIt() { + fatalError("expected true") + } + } +"""), + ('Array.Mutating', Setup[5], '100', """ + for i in 0 ..< existentialArray.count { + if !existentialArray[i].mutateIt() { + fatalError("expected true") + } + } +"""), + ('Array.Shift', Setup[5], '25', """ + for i in 0 ..< existentialArray.count-1 { + existentialArray.swapAt(i, i+1) + } +"""), + ('Array.ConditionalShift', Setup[5], '25', """ + for i in 0 ..< existentialArray.count-1 { + let curr = existentialArray[i] + if curr.doIt() { + existentialArray[i] = existentialArray[i+1] + existentialArray[i+1] = curr + } + } +"""), +] +Vars = [(0, 0), (1, 3), (2, 7), (3, 13)] +Refs = ['Ref' + str(i) for i in range(1, 5)] +Vals = ['Val' + str(i) for i in range(0, 5)] +Names = [(group + '.' + variant, group, variant) + for (group, _, _, _) in Workloads for variant in Refs + Vals] + +def create_array(group): + return 'Array' in group and 'Array.init' not in group + +import re + +method_variant_re = re.compile(r'\.([a-z])') +control_flow_separator_re = re.compile(r'-') +group_separator_re = re.compile(r'\.') + +def run_function_name(benchmark_name): + return 'run_' + group_separator_re.sub( # remove dots + '', method_variant_re.sub( # replace .methodName with _methodName + r'_\1', control_flow_separator_re.sub( # remove dashes + '', benchmark_name))) +}% +public let ExistentialPerformance: [BenchmarkInfo] = [ +% for (Name, Group, Variant) in Names: + BenchmarkInfo(name: "Existential.${Name}", + runFunction: ${run_function_name(Group) + }, tags: ${ 'ta' if 'Array' in Name else 't' + }, setUpFunction: ${ ('ca' if create_array(Group) else 'et') + Variant }), +% end +] + +// To exclude the setup overhead of existential array initialization, +// these are setup functions that **create array** for each variant type. +var array: [Existential]! +func ca(_: T.Type) { + array = Array(repeating: T(), count: 128) +} +% for Variant in Vals + Refs: +func ca${Variant}() { ca(${Variant}.self) } +% end +@inline(never) +func grabArray() -> [Existential] { // transfer array ownership to caller + // FIXME: This is causing Illegal Instruction: 4 crash + // defer { array = nil } + // return array + // This doesn't work either: + // let a = array! + // array = nil + // return a + return array! +} + +// `setUpFunctions` that determine which existential type will be tested +var existentialType: Existential.Type! +% for Variant in Vals + Refs: +func et${Variant}() { existentialType = ${Variant}.self } +% end + +protocol Existential { + init() + func doIt() -> Bool + func reallyDoIt() -> Bool + mutating func mutateIt() -> Bool +} + +func next(_ x: inout Int, upto mod: Int) { + x = (x + 1) % (mod + 1) +} + +% for (V, i) in [(v, int(filter(str.isdigit, v))) for v in Vals]: +struct ${V} : Existential {${ + ''.join(['\n var f{0}: Int = {1}'.format(vi, v) + for (vi, v) in Vars[0:i]]) + + '\n' if i > 0 else ''} + func doIt() -> Bool { + return ${'f0 == 0' if i > 0 else 'true'} + } + func reallyDoIt() -> Bool { + return ${ + 'true' if i == 1 else # so that Val1 doesn't do more work than Val2 + ' && '.join(['f{0} == {1}'.format(vi, v) for (vi, v) in Vars[0:i]]) or + 'true'} + } + mutating func mutateIt() -> Bool {${ + ''.join(['\n next(&f{0}, upto: {1})'.format(vi, (v if v > 0 else 1)) + for (vi, v) in Vars[0:i]])} + return true + } +} + +% end +class Klazz { // body same as Val2 + var f0: Int = 0 + var f1: Int = 3 + + func doIt() -> Bool { + return f0 == 0 + } + func reallyDoIt() -> Bool { + return f0 == 0 && f1 == 3 + } + func mutateIt() -> Bool{ + next(&f0, upto: 1) + next(&f1, upto: 3) + return true + } +} + +% for (V, i) in [(v, int(filter(str.isdigit, v))) for v in Refs]: +struct ${V} : Existential { + ${'\n '.join([('var f{0}: Klazz = Klazz()'.format(vi) if vi < 3 else + 'var f3: Int = 0') for (vi, _) in Vars[0:i]])} + + func doIt() -> Bool { + return f0.doIt() + } + func reallyDoIt() -> Bool { + return f0.reallyDoIt() + } + mutating func mutateIt() -> Bool{ + return f0.mutateIt() + } +} + +% end + +@inline(never) +func passExistentialTwiceOneMethodCall(_ e0: Existential, _ e1: Existential) + -> Bool { + return e0.doIt() && e1.doIt() +} + +@inline(never) +func passExistentialTwiceTwoMethodCalls(_ e0: Existential, _ e1: Existential) + -> Bool { + return e0.doIt() && e1.doIt() && e0.reallyDoIt() && e1.reallyDoIt() +} +% for (group, setup, multiple, workload) in Workloads: +${""" +func {0}(_ N: Int) {{ +{1} + for _ in 0 ..< N * {2} {{{3} }} +}}""".format(run_function_name(group), setup, multiple, workload)} +% end + +// ${'Local Variables'}: +// eval: (read-only-mode 1) +// End: diff --git a/benchmark/utils/TestsUtils.swift b/benchmark/utils/TestsUtils.swift index dc28988f8e58a..3445c1eb32c9c 100644 --- a/benchmark/utils/TestsUtils.swift +++ b/benchmark/utils/TestsUtils.swift @@ -25,7 +25,7 @@ public enum BenchmarkCategory : String { case sdk case runtime, refcount, metadata // Other general areas of compiled code validation. - case abstraction, safetychecks, exceptions, bridging, concurrency + case abstraction, safetychecks, exceptions, bridging, concurrency, existential // Algorithms are "micro" that test some well-known algorithm in isolation: // sorting, searching, hashing, fibonaci, crypto, etc.