blob: cb688ce0f192006bb06ca641b5763f194432ec3e [file] [log] [blame]
//===--- PolymorphicCalls.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
//
//===----------------------------------------------------------------------===//
/*
This benchmark is used to check the performance of polymorphic invocations.
Essentially, it checks how good a compiler can optimize virtual calls of class
methods in cases where multiple sub-classes of a given class are available.
In particular, this benchmark would benefit from a good devirtualization.
In case of applying a speculative devirtualization, it would be benefit from
applying a jump-threading in combination with the speculative devirtualization.
*/
import TestsUtils
public var PolymorphicCalls = BenchmarkInfo(
name: "PolymorphicCalls",
runFunction: run_PolymorphicCalls,
tags: [.abstraction, .cpubench]
)
public class A {
let b: B
init(b:B) {
self.b = b
}
public func run1() -> Int {
return b.f1() + b.f2() + b.f3()
}
public func run2() -> Int {
return b.run()
}
}
// B has no known subclasses
public class B {
let x: Int
init(x:Int) {
self.x = x
}
public func f1() -> Int {
return x + 1
}
public func f2() -> Int {
return x + 11
}
public func f3() -> Int {
return x + 111
}
public func run() -> Int {
return f1() + f2() + f3()
}
}
public class A1 {
let b: B1
public init(b:B1) {
self.b = b
}
public func run1() -> Int {
return b.f1() + b.f2() + b.f3()
}
public func run2() -> Int {
return b.run()
}
}
// B1 has 1 known subclass
public class B1 {
func f1() -> Int { return 0 }
func f2() -> Int { return 0 }
func f3() -> Int { return 0 }
public func run() -> Int {
return f1() + f2() + f3()
}
}
public class C1: B1 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 2
}
override public func f2() -> Int {
return x + 22
}
override public func f3() -> Int {
return x + 222
}
}
public class A2 {
let b:B2
public init(b:B2) {
self.b = b
}
public func run1() -> Int {
return b.f1() + b.f2() + b.f3()
}
public func run2() -> Int {
return b.run()
}
}
// B2 has 2 known subclasses
public class B2 {
func f1() -> Int { return 0 }
func f2() -> Int { return 0 }
func f3() -> Int { return 0 }
public func run() -> Int {
return f1() + f2() + f3()
}
}
public class C2 : B2 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 3
}
override public func f2() -> Int {
return x + 33
}
override public func f3() -> Int {
return x + 333
}
}
public class D2 : B2 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 4
}
override public func f2() -> Int {
return x + 44
}
override public func f3() -> Int {
return x + 444
}
}
public class A3 {
let b: B3
public init(b:B3) {
self.b = b
}
public func run1() -> Int {
return b.f1() + b.f2() + b.f3()
}
public func run2() -> Int {
return b.run()
}
}
// B3 has 3 known subclasses
public class B3 {
func f1() -> Int { return 0 }
func f2() -> Int { return 0 }
func f3() -> Int { return 0 }
public func run() -> Int {
return f1() + f2() + f3()
}
}
public class C3: B3 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 5
}
override public func f2() -> Int {
return x + 55
}
override public func f3() -> Int {
return x + 555
}
}
public class D3: B3 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 6
}
override public func f2() -> Int {
return x + 66
}
override public func f3() -> Int {
return x + 666
}
}
public class E3:B3 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 7
}
override public func f2() -> Int {
return x + 77
}
override public func f3() -> Int {
return x + 777
}
}
public class F3 : B3 {
let x: Int
init(x:Int) {
self.x = x
}
override public func f1() -> Int {
return x + 8
}
override public func f2() -> Int {
return x + 88
}
override public func f3() -> Int {
return x + 888
}}
// Test the cost of polymorphic method invocation
// on a class without any subclasses
@inline(never)
func test(_ a:A, _ UPTO: Int) -> Int64 {
var cnt: Int64 = 0
for _ in 0..<UPTO {
cnt += Int64(a.run2())
}
return cnt
}
// Test the cost of polymorphic method invocation
// on a class with 1 subclass
@inline(never)
func test(_ a:A1, _ UPTO: Int) -> Int64 {
var cnt: Int64 = 0
for _ in 0..<UPTO {
cnt += Int64(a.run2())
}
return cnt
}
// Test the cost of polymorphic method invocation
// on a class with 2 subclasses
@inline(never)
func test(_ a:A2, _ UPTO: Int) -> Int64 {
var cnt: Int64 = 0
for _ in 0..<UPTO {
cnt += Int64(a.run2())
}
return cnt
}
// Test the cost of polymorphic method invocation
// on a class with 2 subclasses on objects
// of different subclasses
@inline(never)
func test(_ a2_c2:A2, _ a2_d2:A2, _ UPTO: Int) -> Int64 {
var cnt: Int64 = 0
for _ in 0..<UPTO/2 {
cnt += Int64(a2_c2.run2())
cnt += Int64(a2_d2.run2())
}
return cnt
}
// Test the cost of polymorphic method invocation
// on a class with 4 subclasses on objects
// of different subclasses
@inline(never)
func test(_ a3_c3: A3, _ a3_d3: A3, _ a3_e3: A3, _ a3_f3: A3, _ UPTO: Int) -> Int64 {
var cnt: Int64 = 0
for _ in 0..<UPTO/4 {
cnt += Int64(a3_c3.run2())
cnt += Int64(a3_d3.run2())
cnt += Int64(a3_e3.run2())
cnt += Int64(a3_f3.run2())
}
return cnt
}
let a = A(b:B(x:1))
let a1 = A1(b:C1(x:1))
let a2 = A2(b:C2(x:1))
let a2_c2 = A2(b:C2(x:1))
let a2_d2 = A2(b:D2(x:1))
let a3_c3 = A3(b:C3(x:1))
let a3_d3 = A3(b:D3(x:1))
let a3_e3 = A3(b:E3(x:1))
let a3_f3 = A3(b:F3(x:1))
@inline(never)
public func run_PolymorphicCalls(_ N:Int) {
let UPTO = 10_000 * N
_ = test(a, UPTO)
_ = test(a1, UPTO)
_ = test(a2, UPTO)
_ = test(a2_c2, a2_d2, UPTO)
_ = test(a3_c3, a3_d3, a3_e3, a3_f3, UPTO)
}