1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
|
//===--- TestsUtils.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
//
//===----------------------------------------------------------------------===//
#if os(Linux)
import Glibc
#elseif os(Windows)
import MSVCRT
#else
import Darwin
#endif
public enum BenchmarkCategory : String {
// Validation "micro" benchmarks test a specific operation or critical path that
// we know is important to measure.
case validation
// subsystems to validate and their subcategories.
case api, Array, String, Dictionary, Codable, Set, Data, IndexPath, SIMD
case sdk
case runtime, refcount, metadata
// Other general areas of compiled code validation.
case abstraction, safetychecks, exceptions, bridging, concurrency, existential, cxxInterop
case exclusivity, differentiation
// Algorithms are "micro" that test some well-known algorithm in isolation:
// sorting, searching, hashing, fibonacci, crypto, etc.
case algorithm
// Miniapplications are contrived to mimic some subset of application behavior
// in a way that can be easily measured. They are larger than micro-benchmarks,
// combining multiple APIs, data structures, or algorithms. This includes small
// standardized benchmarks, pieces of real applications that have been extracted
// into a benchmark, important functionality like JSON parsing, etc.
case miniapplication
// Regression benchmarks is a catch-all for less important "micro"
// benchmarks. This could be a random piece of code that was attached to a bug
// report. We want to make sure the optimizer as a whole continues to handle
// this case, but don't know how applicable it is to general Swift performance
// relative to the other micro-benchmarks. In particular, these aren't weighted
// as highly as "validation" benchmarks and likely won't be the subject of
// future investigation unless they significantly regress.
case regression
// Most benchmarks are assumed to be "stable" and will be regularly tracked at
// each commit. A handful may be marked unstable if continually tracking them is
// counterproductive.
case unstable
// CPU benchmarks represent intrinsic Swift performance. They are useful for
// measuring a fully baked Swift implementation across different platforms and
// hardware. The benchmark should also be reasonably applicable to real Swift
// code--it should exercise a known performance critical area. Typically these
// will be drawn from the validation benchmarks once the language and standard
// library implementation of the benchmark meets a reasonable efficiency
// baseline. A benchmark should only be tagged "cpubench" after a full
// performance investigation of the benchmark has been completed to determine
// that it is a good representation of future Swift performance. Benchmarks
// should not be tagged if they make use of an API that we plan on
// reimplementing or call into code paths that have known opportunities for
// significant optimization.
case cpubench
// Explicit skip marker
case skip
}
extension BenchmarkCategory : CustomStringConvertible {
public var description: String {
return self.rawValue
}
}
extension BenchmarkCategory : Comparable {
public static func < (lhs: BenchmarkCategory, rhs: BenchmarkCategory) -> Bool {
return lhs.rawValue < rhs.rawValue
}
}
public struct BenchmarkPlatformSet : OptionSet {
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
public static let darwin = BenchmarkPlatformSet(rawValue: 1 << 0)
public static let linux = BenchmarkPlatformSet(rawValue: 1 << 1)
public static var currentPlatform: BenchmarkPlatformSet {
#if os(Linux)
return .linux
#else
return .darwin
#endif
}
public static var allPlatforms: BenchmarkPlatformSet {
return [.darwin, .linux]
}
}
public struct BenchmarkInfo {
/// The name of the benchmark that should be displayed by the harness.
public var name: String
/// Shadow static variable for runFunction.
private var _runFunction: (Int) -> ()
/// A function that invokes the specific benchmark routine.
public var runFunction: ((Int) -> ())? {
if !shouldRun {
return nil
}
return _runFunction
}
/// A set of category tags that describe this benchmark. This is used by the
/// harness to allow for easy slicing of the set of benchmarks along tag
/// boundaries, e.x.: run all string benchmarks or ref count benchmarks, etc.
public var tags: Set<BenchmarkCategory>
/// The platforms that this benchmark supports. This is an OptionSet.
private var unsupportedPlatforms: BenchmarkPlatformSet
/// Shadow variable for setUpFunction.
private var _setUpFunction: (() -> ())?
/// An optional function that if non-null is run before benchmark samples
/// are timed.
public var setUpFunction : (() -> ())? {
if !shouldRun {
return nil
}
return _setUpFunction
}
/// Shadow static variable for computed property tearDownFunction.
private var _tearDownFunction: (() -> ())?
/// An optional function that if non-null is run after samples are taken.
public var tearDownFunction: (() -> ())? {
if !shouldRun {
return nil
}
return _tearDownFunction
}
/// DON'T USE ON NEW BENCHMARKS!
/// Optional `legacyFactor` is a multiplication constant applied to runtime
/// statistics reported in the benchmark summary (it doesn’t affect the
/// individual sample times reported in `--verbose` mode).
///
/// It enables the migration of benchmark suite to smaller workloads (< 1 ms),
/// which are more robust to measurement errors from system under load,
/// while maintaining the continuity of longterm benchmark tracking.
///
/// Most legacy benchmarks had workloads artificially inflated in their main
/// `for` loops with a constant integer factor and the migration consisted of
/// dividing it so that the optimized runtime (-O) was less than 1000 μs and
/// storing the divisor in `legacyFactor`. This effectively only increases the
/// frequency of measurement, gathering more samples that are much less likely
/// to be interrupted by a context switch.
public var legacyFactor: Int?
public init(name: String, runFunction: @escaping (Int) -> (), tags: [BenchmarkCategory],
setUpFunction: (() -> ())? = nil,
tearDownFunction: (() -> ())? = nil,
unsupportedPlatforms: BenchmarkPlatformSet = [],
legacyFactor: Int? = nil) {
self.name = name
self._runFunction = runFunction
self.tags = Set(tags)
self._setUpFunction = setUpFunction
self._tearDownFunction = tearDownFunction
self.unsupportedPlatforms = unsupportedPlatforms
self.legacyFactor = legacyFactor
}
/// Returns true if this benchmark should be run on the current platform.
var shouldRun: Bool {
return !unsupportedPlatforms.contains(.currentPlatform)
}
}
extension BenchmarkInfo : Comparable {
public static func < (lhs: BenchmarkInfo, rhs: BenchmarkInfo) -> Bool {
return lhs.name < rhs.name
}
public static func == (lhs: BenchmarkInfo, rhs: BenchmarkInfo) -> Bool {
return lhs.name == rhs.name
}
}
extension BenchmarkInfo : Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(name)
}
}
// Linear function shift register.
//
// This is just to drive benchmarks. I don't make any claim about its
// strength. According to Wikipedia, it has the maximal period for a
// 32-bit register.
public struct LFSR {
// Set the register to some seed that I pulled out of a hat.
var lfsr: UInt32 = 0xb78978e7
public init() {}
mutating func shift() {
lfsr = (lfsr >> 1) ^ (UInt32(bitPattern: -Int32((lfsr & 1))) & 0xD0000001)
}
public mutating func next() -> Int64 {
var result : UInt32 = 0
for _ in 0..<32 {
result = (result << 1) | (lfsr & 1)
shift()
}
return Int64(bitPattern: UInt64(result))
}
}
var lfsrRandomGenerator = LFSR()
// Start the generator from the beginning
@available(*, deprecated, renamed: "LFSR.init()")
public func SRand() {
lfsrRandomGenerator = LFSR()
}
@available(*, deprecated, renamed: "LFSR.next()")
public func Random() -> Int64 {
return lfsrRandomGenerator.next()
}
// This is a fixed-increment version of Java 8's SplittableRandom generator.
// It is a very fast generator passing BigCrush, with 64 bits of state.
// See http://dx.doi.org/10.1145/2714064.2660195 and
// http://docs.oracle.com/javase/8/docs/api/java/util/SplittableRandom.html
//
// Derived from public domain C implementation by Sebastiano Vigna
// See http://xoshiro.di.unimi.it/splitmix64.c
public struct SplitMix64: RandomNumberGenerator {
private var state: UInt64
public init(seed: UInt64) {
self.state = seed
}
public mutating func next() -> UInt64 {
self.state &+= 0x9e3779b97f4a7c15
var z: UInt64 = self.state
z = (z ^ (z &>> 30)) &* 0xbf58476d1ce4e5b9
z = (z ^ (z &>> 27)) &* 0x94d049bb133111eb
return z ^ (z &>> 31)
}
}
/// Like `precondition`, but also checked in unchecked builds.
@inlinable
@inline(__always)
public func check(
_ resultsMatch: Bool,
file: StaticString = #file,
function: StaticString = #function,
line: Int = #line
) {
guard _fastPath(resultsMatch) else {
print("Incorrect result in \(function), \(file):\(line)")
abort()
}
}
@available(*, deprecated, renamed: "check")
@inlinable
@inline(__always)
public func CheckResults(
_ resultsMatch: Bool,
file: StaticString = #file,
function: StaticString = #function,
line: Int = #line
) {
check(resultsMatch, file: file, function: function, line: line)
}
#if !_runtime(_ObjC)
// If we do not have an objc-runtime, then we do not have a definition for
// autoreleasepool. Add in our own fake autoclosure for it that is inline
// always. That should be able to be eaten through by the optimizer no problem.
@inlinable // FIXME(inline-always)
@inline(__always)
public func autoreleasepool<Result>(
invoking body: () throws -> Result
) rethrows -> Result {
return try body()
}
#endif
@_semantics("optimize.no.crossmodule")
public func getFalse() -> Bool { return false }
@available(*, deprecated, renamed: "getFalse()")
public func False() -> Bool { return false }
/// This is a dummy protocol to test the speed of our protocol dispatch.
public protocol SomeProtocol { func getValue() -> Int }
struct MyStruct : SomeProtocol {
init() {}
func getValue() -> Int { return 1 }
}
public func someProtocolFactory() -> SomeProtocol { return MyStruct() }
// Just consume the argument.
// It's important that this function is in another module than the tests
// which are using it.
@inline(never)
@_semantics("optimize.no.crossmodule")
public func blackHole<T>(_ x: T) {
}
// Return the passed argument without letting the optimizer know that.
@inline(never)
@_semantics("optimize.no.crossmodule")
public func identity<T>(_ x: T) -> T {
return x
}
// Return the passed argument without letting the optimizer know that.
// It's important that this function is in another module than the tests
// which are using it.
@inline(never)
@_semantics("optimize.no.crossmodule")
public func getInt(_ x: Int) -> Int { return x }
// The same for String.
@inline(never)
@_semantics("optimize.no.crossmodule")
public func getString(_ s: String) -> String { return s }
// The same for Substring.
@inline(never)
@_semantics("optimize.no.crossmodule")
public func getSubstring(_ s: Substring) -> Substring { return s }
|