mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge remote-tracking branch 'origin/master' into swift-3-api-guidelines
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -28,9 +28,6 @@ cscope.out
|
||||
#==============================================================================#
|
||||
# Directories to ignore (do not add trailing '/'s, they skip symlinks).
|
||||
#==============================================================================#
|
||||
# Swift performance test suite.
|
||||
benchmark/PerfTestSuite
|
||||
|
||||
# Generated docs
|
||||
docs/_build
|
||||
|
||||
|
||||
61
CHANGELOG.md
61
CHANGELOG.md
@@ -12,9 +12,11 @@ Swift 2.2
|
||||
* Associated types in protocols can now be specified with a new 'associatedtype'
|
||||
declaration, to replace the use of 'typealias':
|
||||
|
||||
```swift
|
||||
protocol P {
|
||||
associatedtype Ty
|
||||
}
|
||||
```
|
||||
|
||||
The typealias keyword is still allowed (but deprecated and produces a warning)
|
||||
in Swift 2.2. This warning will become an error in Swift 3.
|
||||
@@ -23,12 +25,29 @@ Swift 2.2
|
||||
Swift 3.
|
||||
|
||||
* The ++ and -- operators have been deprecated, and are slated to be removed in
|
||||
Swift 3.0. As a replacement, please use "x += 1" on integer or floating point
|
||||
types, and "x = x.successor()" on Index types.
|
||||
Swift 3.0. As a replacement, please use `x += 1` on integer or floating point
|
||||
types, and `x = x.successor()` on Index types.
|
||||
|
||||
* New #file, #line, #column, and #function expressions have been introduced to
|
||||
replace the existing __FILE__, __LINE__, __COLUMN__, and __FUNCTION__ symbols.
|
||||
The __FILE__-style symbols have been deprecated, and will be removed in
|
||||
* The implicit tuple splat behavior in function application has been deprecated
|
||||
and will be removed in Swift 3.0. For example, this code:
|
||||
|
||||
```swift
|
||||
func foo(a : Int, b : Int) { ... }
|
||||
let x = (1, b: 2)
|
||||
foo(x) // Warning, deprecated.
|
||||
```
|
||||
|
||||
should move to being written as:
|
||||
```swift
|
||||
foo(x.0, x.b)
|
||||
```
|
||||
|
||||
For more information and rationale, see
|
||||
[SE-0029](https://github.com/apple/swift-evolution/blob/master/proposals/0029-remove-implicit-tuple-splat.md).
|
||||
|
||||
* New `#file`, `#line`, `#column`, and `#function` expressions have been introduced to
|
||||
replace the existing `__FILE__`, `__LINE__`, `__COLUMN__`, and `__FUNCTION__` symbols.
|
||||
The `__FILE__`-style symbols have been deprecated, and will be removed in
|
||||
Swift 3.
|
||||
|
||||
* The operator identifier lexer grammar has been revised to simplify the rules
|
||||
@@ -36,12 +55,12 @@ Swift 2.2
|
||||
that starts with a dot may contain other dots in it, but operators that start
|
||||
with some other character may not contain dots. For example:
|
||||
|
||||
```
|
||||
```swift
|
||||
x....foo --> "x" "...." "foo"
|
||||
x&%^.foo --> "x" "&%^" ".foo"
|
||||
```
|
||||
|
||||
This eliminates a special case for the ..< operator, folding it into a simple
|
||||
This eliminates a special case for the `..<` operator, folding it into a simple
|
||||
and consistent rule.
|
||||
|
||||
* The "C-style for loop", which is spelled `for init; comparison; increment {}`
|
||||
@@ -59,7 +78,7 @@ Swift 2.2
|
||||
are specified.
|
||||
|
||||
* Designated class initializers declared as failable or throwing may now
|
||||
return nil or throw an error, respectively, before the object has been
|
||||
return `nil` or throw an error, respectively, before the object has been
|
||||
fully initialized. For example:
|
||||
|
||||
```swift
|
||||
@@ -111,7 +130,9 @@ Swift 2.2
|
||||
* Argument labels and parameter names can now be any keyword except
|
||||
`var`, `let`, or `inout`. For example:
|
||||
|
||||
```swift
|
||||
NSURLProtectionSpace(host: "somedomain.com", port: 443, protocol: "https", realm: "Some Domain", authenticationMethod: "Basic")
|
||||
```
|
||||
|
||||
would previously have required `protocol` to be surrounded in
|
||||
back-ticks. For more information, see
|
||||
@@ -133,11 +154,13 @@ Swift 2.2
|
||||
* When referencing a function or initializer, one can provide the
|
||||
complete name, including argument labels. For example:
|
||||
|
||||
```swift
|
||||
let fn1 = someView.insertSubview(_:at:)
|
||||
let fn2 = someView.insertSubview(_:aboveSubview:)
|
||||
|
||||
let buttonFactory = UIButton.init(type:)
|
||||
|
||||
```
|
||||
|
||||
For more information, see [SE-0021](https://github.com/apple/swift-evolution/blob/master/proposals/0021-generalized-naming.md).
|
||||
|
||||
* There is a new build configuration function, `#if swift(>=x.y)`, which
|
||||
@@ -161,24 +184,30 @@ Swift 2.2
|
||||
* The Objective-C selector of a Swift method can now be determined
|
||||
directly with the #selector expression, e.g.,:
|
||||
|
||||
```swift
|
||||
let sel = #selector(insertSubview(_:aboveSubview:)) // sel has type Selector
|
||||
|
||||
```
|
||||
|
||||
Along with this change, the use of string literals as selectors has
|
||||
been deprecated, e.g.,
|
||||
|
||||
```swift
|
||||
let sel: Selector = "insertSubview:aboveSubview:"
|
||||
|
||||
```
|
||||
|
||||
Generally, such string literals should be replaced with uses of
|
||||
`#selector`, and the compiler will provide Fix-Its that use
|
||||
`#selector`. In cases where they is not possible (e.g., when referring
|
||||
to the getter of a property), one can still directly construct
|
||||
selectors, e.g.,:
|
||||
|
||||
```swift
|
||||
let sel = Selector("propertyName")
|
||||
|
||||
```
|
||||
|
||||
Note that the compiler is now checking the string literals used to
|
||||
construct Selectors to ensure that they are well-formed Objective-C
|
||||
selectors and that there is an '@objc' method with that selector.
|
||||
selectors and that there is an `@objc` method with that selector.
|
||||
|
||||
|
||||
2015-09-17 [Xcode 7.1, Swift 2.1]
|
||||
@@ -1838,9 +1867,9 @@ Swift 2.2
|
||||
}
|
||||
```
|
||||
|
||||
In the current implementation, struct and enum initializers can return nil
|
||||
In the current implementation, struct and enum initializers can return `nil`
|
||||
at any point inside the initializer, but class initializers can only return
|
||||
nil after all of the stored properties of the object have been initialized
|
||||
`nil` after all of the stored properties of the object have been initialized
|
||||
and `self.init` or `super.init` has been called. If `self.init` or
|
||||
`super.init` is used to delegate to a failable initializer, then the `nil`
|
||||
return is implicitly propagated through the current initializer if the
|
||||
@@ -5269,7 +5298,7 @@ Swift 2.2
|
||||
```
|
||||
|
||||
Swift also supports a special form of weak reference, called `[unowned]`, for
|
||||
references that should never be nil but are required to be weak to break
|
||||
references that should never be `nil` but are required to be weak to break
|
||||
cycles, such as parent or sibling references. Accessing an `[unowned]`
|
||||
reference asserts that the reference is still valid and implicitly promotes
|
||||
the loaded reference to a strong reference, so it does not need to be loaded
|
||||
|
||||
@@ -198,10 +198,15 @@ option(SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
|
||||
"Should the runtime be built with support for non-thread-safe leak detecting entrypoints"
|
||||
FALSE)
|
||||
|
||||
option(SWIFT_STDLIB_USE_ASSERT_CONFIG_RELEASE
|
||||
"Should the stdlib be build with assert config set to release"
|
||||
option(SWIFT_STDLIB_ENABLE_RESILIENCE
|
||||
"Build the standard libraries and overlays with resilience enabled; see docs/LibraryEvolution.rst"
|
||||
FALSE)
|
||||
|
||||
if(SWIFT_SERIALIZE_STDLIB_UNITTEST AND SWIFT_STDLIB_ENABLE_RESILIENCE)
|
||||
message(WARNING "Ignoring SWIFT_SERIALIZE_STDLIB_UNITTEST because SWIFT_STDLIB_ENABLE_RESILIENCE is set")
|
||||
set(SWIFT_SERIALIZE_STDLIB_UNITTEST FALSE)
|
||||
endif()
|
||||
|
||||
option(SWIFT_XCODE_GENERATE_FOR_IDE_ONLY
|
||||
"Generate an Xcode project suitable for IDE use, but which cannot build"
|
||||
FALSE)
|
||||
@@ -660,7 +665,7 @@ if(SWIFT_BUILD_TOOLS)
|
||||
endif()
|
||||
add_subdirectory(utils)
|
||||
add_subdirectory(stdlib)
|
||||
if(SWIFT_BUILD_PERF_TESTSUITE)
|
||||
if(SWIFT_BUILD_PERF_TESTSUITE AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
|
||||
add_subdirectory(benchmark)
|
||||
endif()
|
||||
if(SWIFT_INCLUDE_TESTS)
|
||||
@@ -690,21 +695,3 @@ if(XCODE)
|
||||
add_custom_target(Miscellaneous
|
||||
SOURCES ${SWIFT_TOPLEVEL_HEADERS})
|
||||
endif()
|
||||
|
||||
# Configure CPack.
|
||||
set(CPACK_GENERATOR "TGZ")
|
||||
set(CPACK_PACKAGE_RELOCATABLE "false")
|
||||
set(CPACK_PACKAGE_VENDOR "LLVM Project")
|
||||
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY "OFF")
|
||||
set(CPACK_SET_DESTDIR "ON")
|
||||
|
||||
set(CPACK_PACKAGE_NAME "swift")
|
||||
set(CPACK_SYSTEM_NAME "macosx")
|
||||
|
||||
# FIXME: Real version number.
|
||||
execute_process(COMMAND date "+%Y%m%d"
|
||||
OUTPUT_VARIABLE CPACK_PACKAGE_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
# CPack must be included *after* its configuration variables are set.
|
||||
include(CPack)
|
||||
|
||||
@@ -1,10 +1,213 @@
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
# Performance test harness only builds on Darwin.
|
||||
set(PERF_TESTSUITE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/PerfTestSuite" CACHE STRING "Path to swift performance testsuite repo.")
|
||||
if(EXISTS ${PERF_TESTSUITE_DIR}/CMakeLists.txt)
|
||||
add_subdirectory(${PERF_TESTSUITE_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "Can't find the Swift performance suite at ${PERF_TESTSUITE_DIR}/.")
|
||||
endif()
|
||||
# -*- mode: cmake -*-
|
||||
################################################################################
|
||||
# WARNING: This file is automatically generated from templates and should not
|
||||
# be directly modified. Instead, make changes to
|
||||
# scripts/generate_harness/CMakeLists.txt_template and run
|
||||
# scripts/generate_harness/generate_harness.py to regenerate this file.
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
# Add path for custom CMake modules.
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include(AddSwiftBenchmarkSuite)
|
||||
|
||||
set(SWIFT_BENCH_MODULES
|
||||
single-source/Ackermann
|
||||
single-source/AngryPhonebook
|
||||
single-source/Array2D
|
||||
single-source/ArrayAppend
|
||||
single-source/ArrayInClass
|
||||
single-source/ArrayLiteral
|
||||
single-source/ArrayOfGenericPOD
|
||||
single-source/ArrayOfGenericRef
|
||||
single-source/ArrayOfPOD
|
||||
single-source/ArrayOfRef
|
||||
single-source/ArraySubscript
|
||||
single-source/BitCount
|
||||
single-source/ByteSwap
|
||||
single-source/Calculator
|
||||
single-source/CaptureProp
|
||||
single-source/Chars
|
||||
single-source/ClassArrayGetter
|
||||
single-source/DeadArray
|
||||
single-source/DictionaryBridge
|
||||
single-source/DictionaryLiteral
|
||||
single-source/DictionaryRemove
|
||||
single-source/DictionarySwap
|
||||
single-source/DictTest
|
||||
single-source/DictTest2
|
||||
single-source/DictTest3
|
||||
single-source/ErrorHandling
|
||||
single-source/Fibonacci
|
||||
single-source/GlobalClass
|
||||
single-source/Hanoi
|
||||
single-source/Hash
|
||||
single-source/Histogram
|
||||
single-source/Join
|
||||
single-source/LinkedList
|
||||
single-source/MapReduce
|
||||
single-source/Memset
|
||||
single-source/MonteCarloE
|
||||
single-source/MonteCarloPi
|
||||
single-source/NopDeinit
|
||||
single-source/NSDictionaryCastToSwift
|
||||
single-source/NSError
|
||||
single-source/NSStringConversion
|
||||
single-source/ObjectAllocation
|
||||
single-source/OpenClose
|
||||
single-source/Phonebook
|
||||
single-source/PolymorphicCalls
|
||||
single-source/PopFront
|
||||
single-source/PopFrontGeneric
|
||||
single-source/Prims
|
||||
single-source/ProtocolDispatch
|
||||
single-source/RangeAssignment
|
||||
single-source/RC4
|
||||
single-source/RecursiveOwnedParameter
|
||||
single-source/RGBHistogram
|
||||
single-source/SetTests
|
||||
single-source/SevenBoom
|
||||
single-source/Sim2DArray
|
||||
single-source/SortLettersInPlace
|
||||
single-source/SortStrings
|
||||
single-source/StaticArray
|
||||
single-source/StrComplexWalk
|
||||
single-source/StringBuilder
|
||||
single-source/StringInterpolation
|
||||
single-source/StringTests
|
||||
single-source/StringWalk
|
||||
single-source/StrToInt
|
||||
single-source/SuperChars
|
||||
single-source/TwoSum
|
||||
single-source/TypeFlood
|
||||
single-source/Walsh
|
||||
single-source/XorLoop
|
||||
)
|
||||
|
||||
set(SWIFT_MULTISOURCE_BENCHES
|
||||
)
|
||||
|
||||
|
||||
set(BENCH_DRIVER_LIBRARY_MODULES
|
||||
utils/DriverUtils
|
||||
utils/TestsUtils
|
||||
)
|
||||
|
||||
set(BENCH_DRIVER_LIBRARY_FLAGS)
|
||||
if (SWIFT_RUNTIME_ENABLE_LEAK_CHECKER)
|
||||
set(BENCH_DRIVER_LIBRARY_FLAGS -DSWIFT_RUNTIME_ENABLE_LEAK_CHECKER)
|
||||
endif()
|
||||
|
||||
set(BENCH_LIBRARY_MODULES
|
||||
)
|
||||
|
||||
add_definitions(-DSWIFT_EXEC -DSWIFT_LIBRARY_PATH -DONLY_PLATFORMS
|
||||
-DSWIFT_OPTIMIZATION_LEVELS -DSWIFT_BENCHMARK_EMIT_SIB)
|
||||
|
||||
if(NOT ONLY_PLATFORMS)
|
||||
set(ONLY_PLATFORMS "macosx" "iphoneos" "appletvos" "watchos")
|
||||
endif()
|
||||
|
||||
if(NOT SWIFT_EXEC)
|
||||
runcmd(COMMAND "xcrun" "-f" "swiftc"
|
||||
VARIABLE SWIFT_EXEC
|
||||
ERROR "Unable to find Swift driver")
|
||||
endif()
|
||||
|
||||
if(NOT SWIFT_LIBRARY_PATH)
|
||||
get_filename_component(tmp_dir "${SWIFT_EXEC}" DIRECTORY)
|
||||
get_filename_component(tmp_dir "${tmp_dir}" DIRECTORY)
|
||||
set(SWIFT_LIBRARY_PATH "${tmp_dir}/lib/swift")
|
||||
endif()
|
||||
|
||||
runcmd(COMMAND "xcrun" "-f" "clang"
|
||||
VARIABLE CLANG_EXEC
|
||||
ERROR "Unable to find Clang driver")
|
||||
|
||||
# You have to delete CMakeCache.txt in the swift build to force a
|
||||
# reconfiguration.
|
||||
set(SWIFT_EXTRA_BENCH_CONFIGS CACHE STRING
|
||||
"A semicolon separated list of benchmark configurations. \
|
||||
Available configurations: <Optlevel>_SINGLEFILE, <Optlevel>_MULTITHREADED")
|
||||
|
||||
# Syntax for an optset: <optimization-level>_<configuration>
|
||||
# where "_<configuration>" is optional.
|
||||
if(NOT SWIFT_OPTIMIZATION_LEVELS)
|
||||
set(SWIFT_OPTIMIZATION_LEVELS "Onone" "O" "Ounchecked"
|
||||
${SWIFT_EXTRA_BENCH_CONFIGS})
|
||||
endif()
|
||||
|
||||
# Options for the default (= empty) configuration
|
||||
set(BENCHOPTS "-whole-module-optimization")
|
||||
|
||||
# Options for other configurations
|
||||
set(BENCHOPTS_MULTITHREADED
|
||||
"-whole-module-optimization" "-num-threads" "4")
|
||||
set(BENCHOPTS_SINGLEFILE "")
|
||||
|
||||
set(macosx_arch "x86_64")
|
||||
set(iphoneos_arch "arm64" "armv7")
|
||||
set(appletvos_arch "arm64")
|
||||
set(watchos_arch "armv7k")
|
||||
|
||||
set(macosx_ver "10.9")
|
||||
set(iphoneos_ver "8.0")
|
||||
set(appletvos_ver "9.1")
|
||||
set(watchos_ver "2.0")
|
||||
|
||||
set(macosx_triple_platform "macosx")
|
||||
set(iphoneos_triple_platform "ios")
|
||||
set(appletvos_triple_platform "tvos")
|
||||
set(watchos_triple_platform "watchos")
|
||||
|
||||
set(sdks)
|
||||
set(platforms)
|
||||
foreach(platform ${ONLY_PLATFORMS})
|
||||
execute_process(
|
||||
COMMAND "xcrun" "--sdk" "${platform}" "--show-sdk-path"
|
||||
OUTPUT_VARIABLE ${platform}_sdk
|
||||
RESULT_VARIABLE result
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if("${result}" MATCHES "0")
|
||||
list(APPEND sdks "${${platform}_sdk}")
|
||||
list(APPEND platforms ${platform})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message("--")
|
||||
message("-- Swift Benchmark Suite:")
|
||||
message("-- SWIFT_EXEC = ${SWIFT_EXEC}")
|
||||
message("-- SWIFT_LIBRARY_PATH = ${SWIFT_LIBRARY_PATH}")
|
||||
message("-- CLANG_EXEC = ${CLANG_EXEC}")
|
||||
message("-- SWIFT_OPTIMIZATION_LEVELS = ${SWIFT_OPTIMIZATION_LEVELS}")
|
||||
message("-- ONLY_PLATFORMS = ${ONLY_PLATFORMS}")
|
||||
|
||||
message("-- found platforms: ${platforms}")
|
||||
message("-- found sdks:")
|
||||
foreach(sdk ${sdks})
|
||||
message("-- ${sdk}")
|
||||
endforeach()
|
||||
|
||||
set(executable_targets)
|
||||
|
||||
set(srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(bindir "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
set(libdir "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
set(libswiftdir "${CMAKE_CURRENT_BINARY_DIR}/lib/swift")
|
||||
file(MAKE_DIRECTORY "${bindir}")
|
||||
file(MAKE_DIRECTORY "${libdir}")
|
||||
file(MAKE_DIRECTORY "${libswiftdir}")
|
||||
|
||||
if(SWIFT_SDKS)
|
||||
set(IS_SWIFT_BUILD true)
|
||||
endif()
|
||||
|
||||
# Compile the perf test suite for each platform
|
||||
foreach(platform ${platforms})
|
||||
swift_benchmark_compile(PLATFORM ${platform})
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(scripts)
|
||||
|
||||
203
benchmark/README.md
Normal file
203
benchmark/README.md
Normal file
@@ -0,0 +1,203 @@
|
||||
Swift Benchmark Suite
|
||||
=====================
|
||||
|
||||
This directory contains the Swift Benchmark Suite.
|
||||
|
||||
Running Swift Benchmarks
|
||||
------------------------
|
||||
|
||||
To run Swift benchmarks, pass the `--benchmark` flag to `build-script`. The
|
||||
current benchmark results will be compared to the previous run's results if
|
||||
available. Results for each benchmark run are logged for future comparison.
|
||||
|
||||
For branch based development, take a baseline benchmark on the Swift `master`
|
||||
branch, switch to a development branch containing potentially performance
|
||||
impacting changes, and run the benchmarks again. Upon benchmark completion, the
|
||||
benchmark results for the development branch will be compared to the most
|
||||
recent benchmark results for `master`.
|
||||
|
||||
Building with build-script
|
||||
--------------------------
|
||||
|
||||
By default, Swift benchmarks for OS X are compiled during the Swift build
|
||||
process. To build Swift benchmarks for additional platforms, pass the following
|
||||
flags:
|
||||
|
||||
$ swift/utils/build-script --ios --watchos --tvos
|
||||
|
||||
OS X benchmark driver binaries are placed in `bin` alongside `swiftc`.
|
||||
Additional platform binaries are placed in the `benchmark/bin` build directory.
|
||||
|
||||
Building Independently
|
||||
----------------------
|
||||
|
||||
To build the Swift benchmarks using only an Xcode installation: install an
|
||||
Xcode version with Swift support, install cmake 2.8.12, and ensure Xcode is
|
||||
selected with xcode-select.
|
||||
|
||||
The following build options are available:
|
||||
|
||||
* `-DSWIFT_EXEC`
|
||||
* An absolute path to the Swift driver (`swiftc`) to use to compile the
|
||||
benchmarks (default: Xcode's `swiftc`)
|
||||
* `-DSWIFT_LIBRARY_PATH`
|
||||
* An absolute path to the Swift standard library to use during compilation
|
||||
(default: `swiftc_directory`/../lib/swift)
|
||||
* `-DONLY_PLATFORMS`
|
||||
* A list of platforms to build the benchmarks for
|
||||
(default: "macosx;iphoneos;appletvos;watchos")
|
||||
* `-DSWIFT_OPTIMIZATION_LEVELS`
|
||||
* A list of Swift optimization levels to build against
|
||||
(default: "O;Onone;Ounchecked")
|
||||
* `-DSWIFT_BENCHMARK_EMIT_SIB`
|
||||
* A boolean value indicating whether .sib files should be generated
|
||||
alongside .o files (default: FALSE)
|
||||
|
||||
The following build targets are available:
|
||||
|
||||
1. `swift-benchmark-macosx-x86_64`
|
||||
2. `swift-benchmark-iphoneos-arm64`
|
||||
3. `swift-benchmark-iphoneos-armv7`
|
||||
4. `swift-benchmark-appletvos-arm64`
|
||||
5. `swift-benchmark-watchos-armv7k`
|
||||
|
||||
Build steps (with example options):
|
||||
|
||||
1. `$ cd benchmark`
|
||||
2. `$ mkdir build`
|
||||
3. `$ cd build`
|
||||
4. `$ cmake ..`
|
||||
5. `$ make -j8 swift-benchmark-macosx-x86_64`
|
||||
|
||||
Benchmark driver binaries are placed in `build/bin` and the required Swift
|
||||
standard library dylibs are placed in `build/lib`. The drivers dynamically link
|
||||
Swift standard library dylibs from a path relative to their location
|
||||
(../lib/swift) so the standard library should be distributed alongside them.
|
||||
|
||||
Using the Benchmark Driver
|
||||
--------------------------
|
||||
|
||||
### Usage
|
||||
|
||||
`./Driver [ test_name [ test_name ] ] [ option [ option ] ]`
|
||||
|
||||
* `--num-iters`
|
||||
* Control the number of loop iterations in each test sample
|
||||
* `--num-samples`
|
||||
* Control the number of samples to take for each test
|
||||
* `--list`
|
||||
* Print a list of available tests
|
||||
|
||||
### Examples
|
||||
|
||||
1. `$ ./Benchmark_O --num-iters=1 --num-samples=1`
|
||||
2. `$ ./Benchmark_Onone --list`
|
||||
3. `$ ./Benchmark_Ounchecked Ackermann`
|
||||
|
||||
Using the Harness Generator
|
||||
---------------------------
|
||||
|
||||
`scripts/generate_harness/generate_harness.py` generates and replaces
|
||||
`CMakeLists.txt` and `utils/main.swift` from single and multiple file tests
|
||||
contained in the directories `single-source` and `multi-source`. It gathers
|
||||
information about the tests and then generates the files from templates using
|
||||
jinja2. The motivation for creating this script was to eliminate the need to
|
||||
manually add at least three lines to harness files (one to `CMakeLists.txt` and
|
||||
two to `utils/main.swift`) for every new benchmark added.
|
||||
|
||||
**Warning:**
|
||||
|
||||
Since `CMakeLists.txt` and `utils/main.swift` are now generated from templates,
|
||||
they should not be directly modified. Work may be lost if the harness is
|
||||
executed after making changes to derived files. Instead, modifications should
|
||||
be made to the template files stored in the `scripts/generate_harness`
|
||||
directory.
|
||||
|
||||
### Generating harness files
|
||||
|
||||
Start by installing jinja2 if it isn't already installed:
|
||||
|
||||
$ sudo easy_install -U jinja2
|
||||
|
||||
To generate `CMakeLists.txt` and `utils/main.swift` from test sources, run the
|
||||
command:
|
||||
|
||||
$ scripts/generate_harness/generate_harness.py
|
||||
|
||||
**Note:**
|
||||
|
||||
Ensure `generate_harness.py` remains in `scripts/generate_harness` as it
|
||||
modifies files relative to its location instead of the current working
|
||||
directory.
|
||||
|
||||
### Modifying CMakeLists.txt or utils/main.swift
|
||||
|
||||
To make changes to `CMakeLists.txt` or `utils/main.swift`, modify the template
|
||||
files `CMakeLists.txt_template` and `main.swift_template` stored in the
|
||||
`scripts/generate_harness` directory. These are jinja2 templates, rendered by
|
||||
jinja2 calls in `generate_harness.py`, so ensure static changes don't interfere
|
||||
with the template portions. Test changes by regenerating the harness
|
||||
(*Generating harness files*) and rebuilding the repository with `build-script`.
|
||||
|
||||
Adding New Benchmarks
|
||||
---------------------
|
||||
|
||||
The harness generator supports both single and multiple file tests.
|
||||
|
||||
To add a new single file test:
|
||||
|
||||
1. Add a new Swift file (`YourTestNameHere.swift`), built according to
|
||||
the template below, to the `single-source` directory.
|
||||
2. Regenerate harness files by following the directions in
|
||||
*Generating harness files* before committing changes.
|
||||
|
||||
To add a new multiple file test:
|
||||
|
||||
1. Add a new directory and files under the `multi-source` directory as
|
||||
specified below:
|
||||
|
||||
├── multi-source
|
||||
│ ├── YourTestName
|
||||
│ │ ├── TestFile1.swift
|
||||
│ │ ├── TestFile2.swift
|
||||
│ │ ├── TestFile3.swift
|
||||
|
||||
At least one run function (specified in the template below) must
|
||||
exist in the files.
|
||||
|
||||
2. Regenerate harness files by following the directions in
|
||||
*Generating harness files* before committing changes.
|
||||
|
||||
**Note:**
|
||||
|
||||
The generator script looks for functions prefixed with `run_` in order to
|
||||
populate `utils/main.swift`.
|
||||
|
||||
Each iteration of work performed in the for-loop below should run in under a
|
||||
few milliseconds. The benchmark driver will automatically calculate the
|
||||
necessary number of iterations to run each benchmark in approximately one
|
||||
second.
|
||||
|
||||
**Performance Test Template**
|
||||
|
||||
``` {.sourceCode .swift}
|
||||
// YourTestNameHere benchmark
|
||||
//
|
||||
// rdar://problem/00000000
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_YourTestNameHere(N: Int) {
|
||||
# Declare variables
|
||||
|
||||
for i in 1...N {
|
||||
# Perform work
|
||||
|
||||
# Verify work was done; break otherwise
|
||||
}
|
||||
|
||||
# Assert with CheckResults that work was done
|
||||
}
|
||||
```
|
||||
|
||||
372
benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
Normal file
372
benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake
Normal file
@@ -0,0 +1,372 @@
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
|
||||
# Run a shell command and assign output to a variable or fail with an error.
|
||||
# Example usage:
|
||||
# runcmd(COMMAND "xcode-select" "-p"
|
||||
# VARIABLE xcodepath
|
||||
# ERROR "Unable to find current Xcode path")
|
||||
function(runcmd)
|
||||
cmake_parse_arguments(RUNCMD "" "VARIABLE;ERROR" "COMMAND" ${ARGN})
|
||||
execute_process(
|
||||
COMMAND ${RUNCMD_COMMAND}
|
||||
OUTPUT_VARIABLE ${RUNCMD_VARIABLE}
|
||||
RESULT_VARIABLE result
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT "${result}" MATCHES "0")
|
||||
message(FATAL_ERROR "${RUNCMD_ERROR}")
|
||||
endif()
|
||||
set(${RUNCMD_VARIABLE} ${${RUNCMD_VARIABLE}} PARENT_SCOPE)
|
||||
endfunction(runcmd)
|
||||
|
||||
function (swift_benchmark_compile_archopts)
|
||||
cmake_parse_arguments(BENCH_COMPILE_ARCHOPTS "" "PLATFORM;ARCH;OPT" "" ${ARGN})
|
||||
set(sdk ${${BENCH_COMPILE_ARCHOPTS_PLATFORM}_sdk})
|
||||
set(ver ${${BENCH_COMPILE_ARCHOPTS_PLATFORM}_ver})
|
||||
set(triple_platform ${${BENCH_COMPILE_ARCHOPTS_PLATFORM}_triple_platform})
|
||||
|
||||
set(target "${BENCH_COMPILE_ARCHOPTS_ARCH}-apple-${triple_platform}${ver}")
|
||||
|
||||
set(objdir "${CMAKE_CURRENT_BINARY_DIR}/${BENCH_COMPILE_ARCHOPTS_OPT}-${target}")
|
||||
file(MAKE_DIRECTORY "${objdir}")
|
||||
|
||||
string(REGEX REPLACE "_.*" "" optflag "${BENCH_COMPILE_ARCHOPTS_OPT}")
|
||||
string(REGEX REPLACE "^[^_]+" "" opt_suffix "${BENCH_COMPILE_ARCHOPTS_OPT}")
|
||||
|
||||
set(benchvar "BENCHOPTS${opt_suffix}")
|
||||
if (NOT DEFINED ${benchvar})
|
||||
message(FATAL_ERROR "Invalid benchmark configuration ${BENCH_COMPILE_ARCHOPTS_OPT}")
|
||||
endif()
|
||||
|
||||
set(bench_flags "${${benchvar}}")
|
||||
|
||||
set(common_options
|
||||
"-c"
|
||||
"-sdk" "${sdk}"
|
||||
"-target" "${target}"
|
||||
"-F" "${sdk}/../../../Developer/Library/Frameworks"
|
||||
"-${BENCH_COMPILE_ARCHOPTS_OPT}"
|
||||
"-D" "INTERNAL_CHECKS_ENABLED"
|
||||
"-D" "SWIFT_ENABLE_OBJECT_LITERALS"
|
||||
"-no-link-objc-runtime")
|
||||
|
||||
# Always optimize the driver modules.
|
||||
# Note that we compile the driver for Ounchecked also with -Ounchecked
|
||||
# (and not with -O), because of <rdar://problem/19614516>.
|
||||
string(REPLACE "Onone" "O" driver_opt "${optflag}")
|
||||
|
||||
set(common_options_driver
|
||||
"-c"
|
||||
"-sdk" "${sdk}"
|
||||
"-target" "${target}"
|
||||
"-F" "${sdk}/../../../Developer/Library/Frameworks"
|
||||
"-${driver_opt}"
|
||||
"-D" "INTERNAL_CHECKS_ENABLED"
|
||||
"-D" "SWIFT_ENABLE_OBJECT_LITERALS"
|
||||
"-no-link-objc-runtime")
|
||||
|
||||
set(bench_library_objects)
|
||||
set(bench_library_sibfiles)
|
||||
foreach(module_name_path ${BENCH_DRIVER_LIBRARY_MODULES})
|
||||
get_filename_component(module_name "${module_name_path}" NAME)
|
||||
|
||||
if("${module_name}" STREQUAL "DriverUtils")
|
||||
set(extra_sources "${srcdir}/utils/ArgParse.swift")
|
||||
endif()
|
||||
|
||||
set(objfile "${objdir}/${module_name}.o")
|
||||
set(swiftmodule "${objdir}/${module_name}.swiftmodule")
|
||||
list(APPEND bench_library_objects "${objfile}")
|
||||
set(source "${srcdir}/${module_name_path}.swift")
|
||||
add_custom_command(
|
||||
OUTPUT "${objfile}"
|
||||
DEPENDS ${stdlib_dependencies} "${source}" ${extra_sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options_driver}
|
||||
${BENCH_DRIVER_LIBRARY_FLAGS}
|
||||
"-force-single-frontend-invocation"
|
||||
"-parse-as-library"
|
||||
"-module-name" "${module_name}"
|
||||
"-emit-module" "-emit-module-path" "${swiftmodule}"
|
||||
"-o" "${objfile}"
|
||||
"${source}" ${extra_sources})
|
||||
if(SWIFT_BENCHMARK_EMIT_SIB)
|
||||
set(sibfile "${objdir}/${module_name}.sib")
|
||||
list(APPEND bench_library_sibfiles "${sibfile}")
|
||||
add_custom_command(
|
||||
OUTPUT "${sibfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} "${srcdir}/${module_name_path}.swift"
|
||||
${extra_sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options_driver}
|
||||
${BENCH_DRIVER_LIBRARY_FLAGS}
|
||||
"-force-single-frontend-invocation"
|
||||
"-parse-as-library"
|
||||
"-module-name" "${module_name}"
|
||||
"-emit-sib"
|
||||
"-o" "${sibfile}"
|
||||
"${srcdir}/${module_name_path}.swift" ${extra_sources})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(module_name_path ${BENCH_LIBRARY_MODULES})
|
||||
get_filename_component(module_name "${module_name_path}" NAME)
|
||||
|
||||
set(objfile "${objdir}/${module_name}.o")
|
||||
set(swiftmodule "${objdir}/${module_name}.swiftmodule")
|
||||
list(APPEND bench_library_objects "${objfile}")
|
||||
add_custom_command(
|
||||
OUTPUT "${objfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} "${srcdir}/${module_name_path}.swift"
|
||||
${extra_sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
"-force-single-frontend-invocation"
|
||||
"-parse-as-library"
|
||||
"-module-name" "${module_name}"
|
||||
"-emit-module" "-emit-module-path" "${swiftmodule}"
|
||||
"-o" "${objfile}"
|
||||
"${srcdir}/${module_name_path}.swift" ${extra_sources})
|
||||
if (SWIFT_BENCHMARK_EMIT_SIB)
|
||||
set(sibfile "${objdir}/${module_name}.sib")
|
||||
list(APPEND bench_library_sibfiles "${sibfile}")
|
||||
add_custom_command(
|
||||
OUTPUT "${sibfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} "${srcdir}/${module_name_path}.swift"
|
||||
${extra_sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
"-force-single-frontend-invocation"
|
||||
"-parse-as-library"
|
||||
"-module-name" "${module_name}"
|
||||
"-emit-sib"
|
||||
"-o" "${sibfile}"
|
||||
"${srcdir}/${module_name_path}.swift" ${extra_sources})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(SWIFT_BENCH_OBJFILES)
|
||||
set(SWIFT_BENCH_SIBFILES)
|
||||
foreach(module_name_path ${SWIFT_BENCH_MODULES})
|
||||
get_filename_component(module_name "${module_name_path}" NAME)
|
||||
|
||||
if(module_name)
|
||||
set(objfile "${objdir}/${module_name}.o")
|
||||
set(swiftmodule "${objdir}/${module_name}.swiftmodule")
|
||||
list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
|
||||
add_custom_command(
|
||||
OUTPUT "${objfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} ${bench_library_objects}
|
||||
"${srcdir}/${module_name_path}.swift"
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
"-parse-as-library"
|
||||
${bench_flags}
|
||||
"-module-name" "${module_name}"
|
||||
"-emit-module" "-emit-module-path" "${swiftmodule}"
|
||||
"-I" "${objdir}"
|
||||
"-o" "${objfile}"
|
||||
"${srcdir}/${module_name_path}.swift")
|
||||
if (SWIFT_BENCHMARK_EMIT_SIB)
|
||||
set(sibfile "${objdir}/${module_name}.sib")
|
||||
list(APPEND SWIFT_BENCH_SIBFILES "${sibfile}")
|
||||
add_custom_command(
|
||||
OUTPUT "${sibfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} ${bench_library_sibfiles}
|
||||
"${srcdir}/${module_name_path}.swift"
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
"-parse-as-library"
|
||||
${bench_flags}
|
||||
"-module-name" "${module_name}"
|
||||
"-I" "${objdir}"
|
||||
"-emit-sib"
|
||||
"-o" "${sibfile}"
|
||||
"${srcdir}/${module_name_path}.swift")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
foreach(module_name_path ${SWIFT_MULTISOURCE_BENCHES})
|
||||
get_filename_component(module_name "${module_name_path}" NAME)
|
||||
|
||||
if ("${bench_flags}" MATCHES "-whole-module.*" AND
|
||||
NOT "${bench_flags}" MATCHES "-num-threads.*")
|
||||
# Regular whole-module-compilation: only a single object file is
|
||||
# generated.
|
||||
set(objfile "${objdir}/${module_name}.o")
|
||||
list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
|
||||
set(sources)
|
||||
foreach(source ${${module_name}_sources})
|
||||
list(APPEND sources "${srcdir}/${source}")
|
||||
endforeach()
|
||||
add_custom_command(
|
||||
OUTPUT "${objfile}"
|
||||
DEPENDS
|
||||
${stdlib_dependencies} ${bench_library_objects} ${sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
${bench_flags}
|
||||
"-parse-as-library"
|
||||
"-emit-module" "-module-name" "${module_name}"
|
||||
"-I" "${objdir}"
|
||||
"-o" "${objfile}"
|
||||
${sources})
|
||||
else()
|
||||
|
||||
# No whole-module-compilation or multi-threaded compilation.
|
||||
# There is an output object file for each input file. We have to write
|
||||
# an output-map-file to specify the output object file names.
|
||||
set(sources)
|
||||
set(objfiles)
|
||||
set(json "{\n")
|
||||
foreach(source ${${module_name}_sources})
|
||||
list(APPEND sources "${srcdir}/${source}")
|
||||
|
||||
get_filename_component(basename "${source}" NAME_WE)
|
||||
set(objfile "${objdir}/${module_name}/${basename}.o")
|
||||
|
||||
string(CONCAT json "${json}"
|
||||
" \"${srcdir}/${source}\": { \"object\": \"${objfile}\" },\n")
|
||||
|
||||
list(APPEND objfiles "${objfile}")
|
||||
list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
|
||||
endforeach()
|
||||
string(CONCAT json "${json}" "}")
|
||||
file(WRITE "${objdir}/${module_name}/outputmap.json" ${json})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${objfiles}
|
||||
DEPENDS
|
||||
${stdlib_dependencies} ${bench_library_objects} ${sources}
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
${bench_flags}
|
||||
"-parse-as-library"
|
||||
"-module-name" "${module_name}"
|
||||
"-I" "${objdir}"
|
||||
"-output-file-map" "${objdir}/${module_name}/outputmap.json"
|
||||
${sources})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(module_name "main")
|
||||
set(source "${srcdir}/utils/${module_name}.swift")
|
||||
add_custom_command(
|
||||
OUTPUT "${objdir}/${module_name}.o"
|
||||
DEPENDS
|
||||
${stdlib_dependencies}
|
||||
${bench_library_objects} ${SWIFT_BENCH_OBJFILES}
|
||||
${bench_library_sibfiles} ${SWIFT_BENCH_SIBFILES} "${source}"
|
||||
COMMAND "${SWIFT_EXEC}"
|
||||
${common_options}
|
||||
"-force-single-frontend-invocation"
|
||||
"-emit-module" "-module-name" "${module_name}"
|
||||
"-I" "${objdir}"
|
||||
"-o" "${objdir}/${module_name}.o"
|
||||
"${source}")
|
||||
list(APPEND SWIFT_BENCH_OBJFILES "${objdir}/${module_name}.o")
|
||||
|
||||
if("${BENCH_COMPILE_ARCHOPTS_PLATFORM}" STREQUAL "macosx")
|
||||
set(OUTPUT_EXEC "${bindir}/Benchmark_${BENCH_COMPILE_ARCHOPTS_OPT}")
|
||||
else()
|
||||
set(OUTPUT_EXEC "${bindir}/Benchmark_${BENCH_COMPILE_ARCHOPTS_OPT}-${target}")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${OUTPUT_EXEC}"
|
||||
DEPENDS
|
||||
${bench_library_objects} ${SWIFT_BENCH_OBJFILES}
|
||||
"adhoc-sign-swift-stdlib-${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
|
||||
COMMAND
|
||||
"${CLANG_EXEC}"
|
||||
"-fno-stack-protector"
|
||||
"-fPIC"
|
||||
"-Werror=date-time"
|
||||
"-fcolor-diagnostics"
|
||||
"-O3"
|
||||
"-Wl,-search_paths_first"
|
||||
"-Wl,-headerpad_max_install_names"
|
||||
"-target" "${target}"
|
||||
"-isysroot" "${sdk}"
|
||||
"-arch" "${BENCH_COMPILE_ARCHOPTS_ARCH}"
|
||||
"-F" "${sdk}/../../../Developer/Library/Frameworks"
|
||||
"-m${triple_platform}-version-min=${ver}"
|
||||
"-lobjc"
|
||||
"-L${SWIFT_LIBRARY_PATH}/${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
|
||||
"-Xlinker" "-rpath"
|
||||
"-Xlinker" "@executable_path/../lib/swift/${BENCH_COMPILE_ARCHOPTS_PLATFORM}"
|
||||
${bench_library_objects}
|
||||
${SWIFT_BENCH_OBJFILES}
|
||||
"-o" "${OUTPUT_EXEC}"
|
||||
COMMAND
|
||||
"codesign" "-f" "-s" "-" "${OUTPUT_EXEC}")
|
||||
set(new_output_exec "${OUTPUT_EXEC}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(swift_benchmark_compile)
|
||||
cmake_parse_arguments(SWIFT_BENCHMARK_COMPILE "" "PLATFORM" "" ${ARGN})
|
||||
if(IS_SWIFT_BUILD)
|
||||
set(stdlib_dependencies "swift"
|
||||
${UNIVERSAL_LIBRARY_NAMES_${SWIFT_BENCHMARK_COMPILE_PLATFORM}})
|
||||
endif()
|
||||
|
||||
add_custom_target("copy-swift-stdlib-${SWIFT_BENCHMARK_COMPILE_PLATFORM}"
|
||||
DEPENDS ${stdlib_dependencies}
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" "-E" "copy_directory"
|
||||
"${SWIFT_LIBRARY_PATH}/${SWIFT_BENCHMARK_COMPILE_PLATFORM}"
|
||||
"${libswiftdir}/${SWIFT_BENCHMARK_COMPILE_PLATFORM}")
|
||||
|
||||
add_custom_target("adhoc-sign-swift-stdlib-${SWIFT_BENCHMARK_COMPILE_PLATFORM}"
|
||||
DEPENDS "copy-swift-stdlib-${SWIFT_BENCHMARK_COMPILE_PLATFORM}"
|
||||
COMMAND
|
||||
"codesign" "-f" "-s" "-"
|
||||
"${libswiftdir}/${SWIFT_BENCHMARK_COMPILE_PLATFORM}/*.dylib" "2>/dev/null")
|
||||
|
||||
set(platform_executables)
|
||||
foreach(arch ${${SWIFT_BENCHMARK_COMPILE_PLATFORM}_arch})
|
||||
set(platform_executables)
|
||||
foreach(optset ${SWIFT_OPTIMIZATION_LEVELS})
|
||||
swift_benchmark_compile_archopts(
|
||||
PLATFORM "${platform}"
|
||||
ARCH "${arch}"
|
||||
OPT "${optset}")
|
||||
list(APPEND platform_executables ${new_output_exec})
|
||||
endforeach()
|
||||
|
||||
set(executable_target "swift-benchmark-${SWIFT_BENCHMARK_COMPILE_PLATFORM}-${arch}")
|
||||
|
||||
add_custom_target("${executable_target}"
|
||||
DEPENDS ${platform_executables})
|
||||
|
||||
if(IS_SWIFT_BUILD AND "${SWIFT_BENCHMARK_COMPILE_PLATFORM}" STREQUAL "macosx")
|
||||
add_custom_command(
|
||||
TARGET "${executable_target}"
|
||||
POST_BUILD
|
||||
COMMAND
|
||||
"mv" ${platform_executables} "${SWIFT_RUNTIME_OUTPUT_INTDIR}")
|
||||
|
||||
add_custom_target("check-${executable_target}"
|
||||
COMMAND "${SWIFT_RUNTIME_OUTPUT_INTDIR}/Benchmark_Driver" "run"
|
||||
"-o" "O" "--output-dir" "${CMAKE_CURRENT_BINARY_DIR}/logs"
|
||||
"--swift-repo" "${SWIFT_SOURCE_DIR}"
|
||||
"--iterations" "3"
|
||||
COMMAND "${SWIFT_RUNTIME_OUTPUT_INTDIR}/Benchmark_Driver" "run"
|
||||
"-o" "Onone" "--output-dir" "${CMAKE_CURRENT_BINARY_DIR}/logs"
|
||||
"--swift-repo" "${SWIFT_SOURCE_DIR}"
|
||||
"--iterations" "3"
|
||||
COMMAND "${SWIFT_RUNTIME_OUTPUT_INTDIR}/Benchmark_Driver" "compare"
|
||||
"--log-dir" "${CMAKE_CURRENT_BINARY_DIR}/logs"
|
||||
"--swift-repo" "${SWIFT_SOURCE_DIR}"
|
||||
"--compare-script"
|
||||
"${SWIFT_SOURCE_DIR}/benchmark/scripts/compare_perf_tests.py")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
||||
111
benchmark/scripts/Benchmark_DTrace.in
Normal file
111
benchmark/scripts/Benchmark_DTrace.in
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- Benchmark_DTrace.in ----------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
DRIVER_LIBRARY_PATH = "@PATH_TO_DRIVER_LIBRARY@"
|
||||
sys.path.append(DRIVER_LIBRARY_PATH)
|
||||
DTRACE_PATH = os.path.join(DRIVER_LIBRARY_PATH, 'swift_stats.d')
|
||||
|
||||
import perf_test_driver
|
||||
|
||||
# Regexes for the XFAIL_LIST. Matches against '([Onone|O|Ounchecked],TestName)'
|
||||
XFAIL_LIST = [
|
||||
]
|
||||
|
||||
class DTraceResult(perf_test_driver.Result):
|
||||
|
||||
def __init__(self, name, status, output, csv_output):
|
||||
perf_test_driver.Result.__init__(self, name, status, output, XFAIL_LIST)
|
||||
self.csv_output = csv_output
|
||||
|
||||
@classmethod
|
||||
def data_headers(cls):
|
||||
return ['Name', 'Result', 'strong_retain', 'strong_retain/iter', 'strong_release', 'strong_release/iter']
|
||||
|
||||
@classmethod
|
||||
def data_format(cls, max_test_len):
|
||||
non_name_headers = DTraceResult.data_headers()[1:]
|
||||
fmt = ('{:<%d}' % (max_test_len + 5)) + ''.join(['{:<%d}' % (len(h) + 2) for h in non_name_headers])
|
||||
return fmt
|
||||
|
||||
@classmethod
|
||||
def print_data_header(cls, max_test_len, csv_output):
|
||||
headers = cls.data_headers()
|
||||
if csv_output:
|
||||
print(','.join(headers))
|
||||
return
|
||||
print(cls.data_format(max_test_len).format(*headers))
|
||||
|
||||
def print_data(self, max_test_len):
|
||||
result = [self.get_name(), self.get_result()] + map(str, self.output)
|
||||
if self.csv_output:
|
||||
print(','.join(result))
|
||||
return
|
||||
|
||||
print(DTraceResult.data_format(max_test_len).format(*result))
|
||||
|
||||
class DTraceBenchmarkDriver(perf_test_driver.BenchmarkDriver):
|
||||
def __init__(self, binary, xfail_list, csv_output):
|
||||
perf_test_driver.BenchmarkDriver.__init__(self, binary, xfail_list,
|
||||
enable_parallel=False,
|
||||
opt_levels=['O'])
|
||||
self.csv_output = csv_output
|
||||
|
||||
def print_data_header(self, max_test_len):
|
||||
DTraceResult.print_data_header(max_test_len, self.csv_output)
|
||||
|
||||
def prepare_input(self, name):
|
||||
return {}
|
||||
|
||||
def process_input(self, data):
|
||||
test_name = '({}_{})'.format(data['opt'], data['test_name'])
|
||||
print "Running {}...".format(test_name)
|
||||
sys.stdout.flush()
|
||||
|
||||
def get_results_with_iters(iters):
|
||||
p = subprocess.Popen(['sudo', 'dtrace', '-s', DTRACE_PATH, '-c', '%s %s %s' % (data['path'], data['test_name'], '--num-iters=%d' % iters)],
|
||||
stdout=subprocess.PIPE, stderr=open('/dev/null', 'w'))
|
||||
results = [x for x in p.communicate()[0].split("\n") if len(x) > 0]
|
||||
return [x.split(',')[1] for x in results[results.index('DTRACE RESULTS') + 1:]]
|
||||
iter_2_results = get_results_with_iters(2)
|
||||
iter_3_results = get_results_with_iters(3)
|
||||
|
||||
results = []
|
||||
for x in zip(iter_2_results, iter_3_results):
|
||||
results.append(x[1])
|
||||
results.append(int(x[1]) - int(x[0]))
|
||||
|
||||
return DTraceResult(test_name, 0, results, self.csv_output)
|
||||
|
||||
SWIFT_BIN_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-filter', type=str, default=None,
|
||||
help='Filter out any test that does not match the given regex')
|
||||
parser.add_argument('-csv', default=False, action='store_true',
|
||||
help="Emit csv output", dest='csv_output')
|
||||
return parser.parse_args()
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
g = DTraceBenchmarkDriver(SWIFT_BIN_DIR, XFAIL_LIST, args.csv_output)
|
||||
if g.run(args.filter):
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(-1)
|
||||
379
benchmark/scripts/Benchmark_Driver
Executable file
379
benchmark/scripts/Benchmark_Driver
Executable file
@@ -0,0 +1,379 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===--- Benchmark_Driver -------------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import urllib2
|
||||
import urllib
|
||||
import datetime
|
||||
import argparse
|
||||
import time
|
||||
import glob
|
||||
|
||||
DRIVER_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
def parse_results(res, optset):
|
||||
# Parse lines like this
|
||||
# #,TEST,SAMPLES,MIN(μs),MAX(μs),MEAN(μs),SD(μs),MEDIAN(μs),PEAK_MEMORY(B)
|
||||
SCORERE = re.compile(r"(\d+),[ \t]*(\w+)," +
|
||||
",".join([r"[ \t]*([\d.]+)"] * 7))
|
||||
# The Totals line would be parsed like this.
|
||||
TOTALRE = re.compile(r"()(Totals)," +
|
||||
",".join([r"[ \t]*([\d.]+)"] * 7))
|
||||
KEYGROUP = 2
|
||||
VALGROUP = 4
|
||||
MEMGROUP = 9
|
||||
|
||||
tests = []
|
||||
for line in res.split():
|
||||
m = SCORERE.match(line)
|
||||
if not m:
|
||||
m = TOTALRE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
testresult = int(m.group(VALGROUP))
|
||||
testname = m.group(KEYGROUP)
|
||||
test = {}
|
||||
test['Data'] = [testresult]
|
||||
test['Info'] = {}
|
||||
test['Name'] = "nts.swift/" + optset + "." + testname + ".exec"
|
||||
tests.append(test)
|
||||
if testname != 'Totals':
|
||||
mem_testresult = int(m.group(MEMGROUP))
|
||||
mem_test = {}
|
||||
mem_test['Data'] = [mem_testresult]
|
||||
mem_test['Info'] = {}
|
||||
mem_test['Name'] = "nts.swift/mem_maxrss." + optset + "." + testname + ".mem"
|
||||
tests.append(mem_test)
|
||||
return tests
|
||||
|
||||
def submit_to_LNT(data, url):
|
||||
print "\nSubmitting results to LNT server..."
|
||||
json_report = {'input_data': json.dumps(data), 'commit': '1'}
|
||||
data = urllib.urlencode(json_report)
|
||||
response_str = urllib2.urlopen(urllib2.Request(url, data))
|
||||
response = json.loads(response_str.read())
|
||||
if 'success' in response:
|
||||
print "Server response:\tSuccess"
|
||||
else:
|
||||
print "Server response:\tError"
|
||||
print "Error:\t", response['error']
|
||||
sys.exit(1)
|
||||
|
||||
def instrument_test(driver_path, test, num_samples):
|
||||
"""Run a test and instrument its peak memory use"""
|
||||
test_outputs = []
|
||||
for _ in range(num_samples):
|
||||
test_output_raw = subprocess.check_output(
|
||||
['time', '-lp', driver_path, test],
|
||||
stderr=subprocess.STDOUT
|
||||
)
|
||||
peak_memory = re.match('\s*(\d+)\s*maximum resident set size',
|
||||
test_output_raw.split('\n')[-15]).group(1)
|
||||
test_outputs.append(test_output_raw.split()[1].split(',') +
|
||||
[peak_memory])
|
||||
|
||||
# Average sample results
|
||||
NUM_SAMPLES_INDEX = 2
|
||||
MIN_INDEX = 3
|
||||
MAX_INDEX = 4
|
||||
AVG_START_INDEX = 5
|
||||
|
||||
# TODO: Correctly take stdev
|
||||
avg_test_output = test_outputs[0]
|
||||
avg_test_output[AVG_START_INDEX:] = map(int,
|
||||
avg_test_output[AVG_START_INDEX:])
|
||||
for test_output in test_outputs[1:]:
|
||||
for i in range(AVG_START_INDEX, len(test_output)):
|
||||
avg_test_output[i] += int(test_output[i])
|
||||
for i in range(AVG_START_INDEX, len(avg_test_output)):
|
||||
avg_test_output[i] = int(round(avg_test_output[i] /
|
||||
float(len(test_outputs))))
|
||||
avg_test_output[NUM_SAMPLES_INDEX] = num_samples
|
||||
avg_test_output[MIN_INDEX] = min(test_outputs,
|
||||
key=lambda x: x[MIN_INDEX])[MIN_INDEX]
|
||||
avg_test_output[MAX_INDEX] = max(test_outputs,
|
||||
key=lambda x: x[MAX_INDEX])[MAX_INDEX]
|
||||
avg_test_output = map(str, avg_test_output)
|
||||
|
||||
return avg_test_output
|
||||
|
||||
def get_tests(driver_path):
|
||||
"""Return a list of available performance tests"""
|
||||
return subprocess.check_output([driver_path, '--list']).split()[2:]
|
||||
|
||||
def get_current_git_branch(git_repo_path):
|
||||
"""Return the selected branch for the repo `git_repo_path`"""
|
||||
return subprocess.check_output(['git', '-C', git_repo_path, 'rev-parse',
|
||||
'--abbrev-ref', 'HEAD'], stderr=subprocess.STDOUT).strip()
|
||||
|
||||
def log_results(log_directory, driver, formatted_output, swift_repo=None):
|
||||
"""Log `formatted_output` to a branch specific directory in
|
||||
`log_directory`"""
|
||||
try:
|
||||
branch = get_current_git_branch(swift_repo)
|
||||
except:
|
||||
branch = None
|
||||
timestamp = time.strftime("%Y%m%d%H%M%S", time.localtime())
|
||||
if branch:
|
||||
output_directory = os.path.join(log_directory, branch)
|
||||
else:
|
||||
output_directory = log_directory
|
||||
driver_name = os.path.basename(driver)
|
||||
try:
|
||||
os.makedirs(output_directory)
|
||||
except:
|
||||
pass
|
||||
log_file = os.path.join(output_directory,
|
||||
driver_name + '-' + timestamp + '.log')
|
||||
print 'Logging results to: %s' % log_file
|
||||
with open(log_file, 'w') as f:
|
||||
f.write(formatted_output)
|
||||
|
||||
def run_benchmarks(driver, benchmarks=[], num_samples=10, verbose=False,
|
||||
log_directory=None, swift_repo=None):
|
||||
"""Run perf tests individually and return results in a format that's
|
||||
compatible with `parse_results`. If `benchmarks` is not empty,
|
||||
only run tests included in it."""
|
||||
(total_tests, total_min, total_max, total_mean) = (0, 0, 0, 0)
|
||||
output = []
|
||||
headings = ['#', 'TEST', 'SAMPLES', 'MIN(μs)', 'MAX(μs)', 'MEAN(μs)',
|
||||
'SD(μs)', 'MEDIAN(μs)', 'MAX_RSS(B)']
|
||||
line_format = '{:>3} {:<25} {:>7} {:>7} {:>7} {:>8} {:>6} {:>10} {:>10}'
|
||||
if verbose and log_directory:
|
||||
print line_format.format(*headings)
|
||||
for test in get_tests(driver):
|
||||
if benchmarks and test not in benchmarks:
|
||||
continue
|
||||
test_output = instrument_test(driver, test, num_samples)
|
||||
if test_output[0] == 'Totals':
|
||||
continue
|
||||
if verbose:
|
||||
if log_directory:
|
||||
print line_format.format(*test_output)
|
||||
else:
|
||||
print ','.join(test_output)
|
||||
output.append(test_output)
|
||||
(samples, _min, _max, mean) = map(int, test_output[2:6])
|
||||
total_tests += 1
|
||||
total_min += _min
|
||||
total_max += _max
|
||||
total_mean += mean
|
||||
if not output:
|
||||
return
|
||||
formatted_output = '\n'.join([','.join(l) for l in output])
|
||||
totals = map(str, ['Totals', total_tests, total_min, total_max,
|
||||
total_mean, '0', '0', '0'])
|
||||
totals_output = '\n\n' + ','.join(totals)
|
||||
if verbose:
|
||||
if log_directory:
|
||||
print line_format.format(*([''] + totals))
|
||||
else:
|
||||
print totals_output[1:]
|
||||
formatted_output += totals_output
|
||||
if log_directory:
|
||||
log_results(log_directory, driver, formatted_output, swift_repo)
|
||||
return formatted_output
|
||||
|
||||
def submit(args):
|
||||
print "SVN revision:\t", args.revision
|
||||
print "Machine name:\t", args.machine
|
||||
print "Iterations:\t", args.iterations
|
||||
print "Optimizations:\t", ','.join(args.optimization)
|
||||
print "LNT host:\t", args.lnt_host
|
||||
starttime = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||
print "Start time:\t", starttime
|
||||
data = {}
|
||||
data['Tests'] = []
|
||||
data['Machine'] = {'Info': {'name': args.machine}, 'Name': args.machine}
|
||||
print "\nRunning benchmarks..."
|
||||
for optset in args.optimization:
|
||||
print "Opt level:\t", optset
|
||||
file = os.path.join(args.tests, "Benchmark_" + optset)
|
||||
try:
|
||||
res = run_benchmarks(file, benchmarks=args.benchmark,
|
||||
num_samples=args.iterations)
|
||||
data['Tests'].extend(parse_results(res, optset))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print "Execution failed.. Test results are empty."
|
||||
print "Process output:\n", e.output
|
||||
|
||||
endtime = datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
|
||||
data['Run'] = {'End Time': endtime,
|
||||
'Info': {'inferred_run_order': str(args.revision),
|
||||
'run_order': str(args.revision),
|
||||
'tag': 'nts',
|
||||
'test_suite_revision': 'None'},
|
||||
'Start Time': starttime}
|
||||
print "End time:\t", endtime
|
||||
|
||||
submit_to_LNT(data, args.lnt_host)
|
||||
return 0
|
||||
|
||||
def run(args):
|
||||
optset = args.optimization
|
||||
file = os.path.join(args.tests, "Benchmark_" + optset)
|
||||
run_benchmarks(file, benchmarks=args.benchmarks,
|
||||
num_samples=args.iterations, verbose=True,
|
||||
log_directory=args.output_dir,
|
||||
swift_repo=args.swift_repo)
|
||||
return 0
|
||||
|
||||
def format_name(log_path):
|
||||
"""Return the filename and directory for a log file"""
|
||||
return '/'.join(log_path.split('/')[-2:])
|
||||
|
||||
def compare_logs(compare_script, new_log, old_log):
|
||||
"""Return diff of log files at paths `new_log` and `old_log`"""
|
||||
print 'Comparing %s %s ...' % (format_name(old_log), format_name(new_log))
|
||||
subprocess.call([compare_script, old_log, new_log])
|
||||
|
||||
def compare(args):
|
||||
log_dir = args.log_dir
|
||||
swift_repo = args.swift_repo
|
||||
compare_script = args.compare_script
|
||||
current_branch = get_current_git_branch(swift_repo)
|
||||
current_branch_dir = os.path.join(log_dir, current_branch)
|
||||
master_branch_dir = os.path.join(log_dir, 'master')
|
||||
|
||||
if current_branch != 'master' and not os.path.isdir(master_branch_dir):
|
||||
print 'Unable to find benchmark logs for master branch. Set a ' + \
|
||||
'baseline benchmark log by passing --benchmark to ' + \
|
||||
'build-script while on master branch.'
|
||||
return 1
|
||||
|
||||
recent_logs = {}
|
||||
for branch_dir in [current_branch_dir, master_branch_dir]:
|
||||
for opt in ['O', 'Onone']:
|
||||
recent_logs[os.path.basename(branch_dir) + '_' + opt] = sorted(
|
||||
glob.glob(os.path.join(branch_dir, 'Benchmark_' + opt + '-*.log')),
|
||||
key=os.path.getctime, reverse=True)
|
||||
|
||||
if current_branch == 'master':
|
||||
if len(recent_logs['master_O']) > 1 and \
|
||||
len(recent_logs['master_Onone']) > 1:
|
||||
compare_logs(compare_script,
|
||||
recent_logs['master_O'][0],
|
||||
recent_logs['master_O'][1])
|
||||
compare_logs(compare_script,
|
||||
recent_logs['master_Onone'][0],
|
||||
recent_logs['master_Onone'][1])
|
||||
else:
|
||||
print 'master/master comparison skipped: no previous master logs'
|
||||
else:
|
||||
# TODO: Check for outdated master branch log
|
||||
if len(recent_logs[current_branch + '_O']) == 0 or \
|
||||
len(recent_logs[current_branch + '_Onone']) == 0:
|
||||
print 'branch sanity failure: missing branch logs'
|
||||
return 1
|
||||
|
||||
if len(recent_logs[current_branch + '_O']) == 1 or \
|
||||
len(recent_logs[current_branch + '_Onone']) == 1:
|
||||
print 'branch/branch comparison skipped: no previous branch logs'
|
||||
else:
|
||||
compare_logs(compare_script,
|
||||
recent_logs[current_branch + '_O'][0],
|
||||
recent_logs[current_branch + '_O'][1])
|
||||
compare_logs(compare_script,
|
||||
recent_logs[current_branch + '_Onone'][0],
|
||||
recent_logs[current_branch + '_Onone'][1])
|
||||
|
||||
if len(recent_logs['master_O']) == 0 or \
|
||||
len(recent_logs['master_Onone']) == 0:
|
||||
print 'branch/master failure: no master logs'
|
||||
return 1
|
||||
else:
|
||||
compare_logs(compare_script,
|
||||
recent_logs[current_branch + '_O'][0],
|
||||
recent_logs['master_O'][0])
|
||||
compare_logs(compare_script,
|
||||
recent_logs[current_branch + '_Onone'][0],
|
||||
recent_logs['master_Onone'][0])
|
||||
|
||||
# TODO: Fail on large regressions
|
||||
|
||||
return 0
|
||||
|
||||
def positive_int(value):
|
||||
ivalue = int(value)
|
||||
if not (ivalue > 0):
|
||||
raise ValueError
|
||||
return ivalue
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Swift benchmarks driver')
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
submit_parser = subparsers.add_parser('submit',
|
||||
help='run benchmarks and submit results to LNT')
|
||||
submit_parser.add_argument('-t', '--tests',
|
||||
help='directory containing Benchmark_O{,none,unchecked} ' +
|
||||
'(default: DRIVER_DIR)',
|
||||
default=DRIVER_DIR)
|
||||
submit_parser.add_argument('-m', '--machine', required=True,
|
||||
help='LNT machine name')
|
||||
submit_parser.add_argument('-r', '--revision', required=True,
|
||||
help='SVN revision of compiler to identify the LNT run', type=int)
|
||||
submit_parser.add_argument('-l', '--lnt_host', required=True,
|
||||
help='LNT host to submit results to')
|
||||
submit_parser.add_argument('-i', '--iterations',
|
||||
help='number of times to run each test (default: 10)',
|
||||
type=positive_int, default=10)
|
||||
submit_parser.add_argument('-o', '--optimization', nargs='+',
|
||||
help='optimization levels to use (default: O Onone Ounchecked)',
|
||||
default=['O', 'Onone', 'Ounchecked'])
|
||||
submit_parser.add_argument('benchmark',
|
||||
help='benchmark to run (default: all)', nargs='*')
|
||||
submit_parser.set_defaults(func=submit)
|
||||
|
||||
run_parser = subparsers.add_parser('run',
|
||||
help='run benchmarks and output results to stdout')
|
||||
run_parser.add_argument('-t', '--tests',
|
||||
help='directory containing Benchmark_O{,none,unchecked} ' +
|
||||
'(default: DRIVER_DIR)',
|
||||
default=DRIVER_DIR)
|
||||
run_parser.add_argument('-i', '--iterations',
|
||||
help='number of times to run each test (default: 1)',
|
||||
type=positive_int, default=1)
|
||||
run_parser.add_argument('-o', '--optimization',
|
||||
help='optimization level to use (default: O)', default='O')
|
||||
run_parser.add_argument('--output-dir',
|
||||
help='log results to directory (default: no logging)')
|
||||
run_parser.add_argument('--swift-repo',
|
||||
help='absolute path to Swift source repo for branch comparison')
|
||||
run_parser.add_argument('benchmarks',
|
||||
help='benchmark to run (default: all)', nargs='*')
|
||||
run_parser.set_defaults(func=run)
|
||||
|
||||
compare_parser = subparsers.add_parser('compare',
|
||||
help='compare benchmark results')
|
||||
compare_parser.add_argument('--log-dir', required=True,
|
||||
help='directory containing benchmark logs')
|
||||
compare_parser.add_argument('--swift-repo', required=True,
|
||||
help='absolute path to Swift source repo')
|
||||
compare_parser.add_argument('--compare-script', required=True,
|
||||
help='absolute path to compare script')
|
||||
compare_parser.set_defaults(func=compare)
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.func != compare and isinstance(args.optimization, list):
|
||||
args.optimization = sorted(list(set(args.optimization)))
|
||||
return args.func(args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
58
benchmark/scripts/Benchmark_GuardMalloc.in
Normal file
58
benchmark/scripts/Benchmark_GuardMalloc.in
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- Benchmark_GuardMalloc.in -----------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
sys.path.append("@PATH_TO_DRIVER_LIBRARY@")
|
||||
|
||||
import perf_test_driver
|
||||
|
||||
# Regexes for the XFAIL_LIST. Matches against '([Onone|O|Ounchecked],TestName)'
|
||||
XFAIL_LIST = [
|
||||
]
|
||||
|
||||
class GuardMallocResult(perf_test_driver.Result):
|
||||
|
||||
def __init__(self, name, status):
|
||||
perf_test_driver.Result.__init__(self, name, status, "", XFAIL_LIST)
|
||||
|
||||
class GuardMallocBenchmarkDriver(perf_test_driver.BenchmarkDriver):
|
||||
def __init__(self, binary, xfail_list):
|
||||
perf_test_driver.BenchmarkDriver.__init__(self, binary, xfail_list,
|
||||
enable_parallel=True)
|
||||
self.new_env = os.environ.copy()
|
||||
self.new_env['DYLD_INSERT_LIBRARIES'] = '/usr/lib/libgmalloc.dylib'
|
||||
|
||||
def prepare_input(self, name):
|
||||
return {'env': self.new_env}
|
||||
|
||||
def process_input(self, data):
|
||||
test_name = '({},{})'.format(data['opt'], data['test_name'])
|
||||
print "Running {}...".format(test_name)
|
||||
sys.stdout.flush()
|
||||
status = subprocess.call([data['path'], data['test_name'], '--num-iters=2'],
|
||||
env=data['env'], stderr=open('/dev/null', 'w'),
|
||||
stdout=open('/dev/null', 'w'))
|
||||
return GuardMallocResult(test_name, status)
|
||||
|
||||
SWIFT_BIN_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
if __name__ == "__main__":
|
||||
g = GuardMallocBenchmarkDriver(SWIFT_BIN_DIR, XFAIL_LIST)
|
||||
if g.run():
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(-1)
|
||||
108
benchmark/scripts/Benchmark_RuntimeLeaksRunner.in
Normal file
108
benchmark/scripts/Benchmark_RuntimeLeaksRunner.in
Normal file
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- Benchmark_RuntimeLeaksRunner.in ----------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
sys.path.append("@PATH_TO_DRIVER_LIBRARY@")
|
||||
|
||||
import perf_test_driver
|
||||
|
||||
# This is a hacked up XFAIL list. It should really be a json file, but it will
|
||||
# work for now. Add in the exact name of the pass to XFAIL.
|
||||
XFAIL_LIST = [
|
||||
]
|
||||
|
||||
# A list of Functions mapped to the number of globals in that function. These
|
||||
# show up as leaks. But we can count them, whitelist them, and then ignore them.
|
||||
FUNC_TO_GLOBAL_COUNTS = {
|
||||
'Ackermann': {"swift_count": 1, "objc_count": 0},
|
||||
'AngryPhonebook': {"swift_count": 1, "objc_count": 0},
|
||||
'GlobalClass': {'swift_count': 1, 'objc_count': 0},
|
||||
'Histogram': {'swift_count': 1, 'objc_count': 0},
|
||||
'Phonebook': {'swift_count': 1, 'objc_count': 0},
|
||||
'RC4': {'swift_count': 1, 'objc_count': 0},
|
||||
'RGBHistogram': {'swift_count': 1, 'objc_count': 0},
|
||||
'SortStrings': {'swift_count': 1, 'objc_count': 0},
|
||||
'TwoSum': {'swift_count': 1, 'objc_count': 0},
|
||||
}
|
||||
|
||||
# Global objective-c classes created by various frameworks. We do not care about these.
|
||||
IGNORABLE_GLOBAL_OBJC_CLASSES = set([
|
||||
'__NSPlaceholderDate',
|
||||
'NSCache',
|
||||
'__NSPlaceholderTimeZone',
|
||||
'NSPlaceholderNumber',
|
||||
'NSPlaceholderString',
|
||||
'__NSPlaceholderArray',
|
||||
'__NSPlaceholderDictionary',
|
||||
'_NSPlaceholderData',
|
||||
'_NSJSONReader'
|
||||
])
|
||||
|
||||
class LeaksRunnerResult(perf_test_driver.Result):
|
||||
|
||||
def __init__(self, name, status):
|
||||
perf_test_driver.Result.__init__(self, name, status, "", XFAIL_LIST)
|
||||
|
||||
class LeaksRunnerBenchmarkDriver(perf_test_driver.BenchmarkDriver):
|
||||
|
||||
def __init__(self, binary, xfail_list):
|
||||
perf_test_driver.BenchmarkDriver.__init__(self, binary, xfail_list,
|
||||
enable_parallel=True)
|
||||
|
||||
def prepare_input(self, name):
|
||||
return {}
|
||||
|
||||
def process_input(self, data):
|
||||
test_name = '({},{})'.format(data['opt'], data['test_name'])
|
||||
print "Running {}...".format(test_name)
|
||||
sys.stdout.flush()
|
||||
try:
|
||||
p = subprocess.Popen([data['path'], "--run-all", "--num-samples=2",
|
||||
"--num-iters={}".format(2), data['test_name']],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
p.wait()
|
||||
error_out = p.stderr.readlines()
|
||||
except:
|
||||
print("Child Process Failed! (%s,%s)" % (data['path'], data['test_name']))
|
||||
return LeaksRunnerResult(test_name, True)
|
||||
|
||||
try:
|
||||
# We grab the second line since swift globals get lazily created in the
|
||||
# first iteration.
|
||||
d = json.loads(error_out[1])
|
||||
d['objc_objects'] = [x for x in d['objc_objects'] if x not in IGNORABLE_GLOBAL_OBJC_CLASSES]
|
||||
d['objc_count'] = len(d['objc_objects'])
|
||||
|
||||
# Subtract out known global counts.
|
||||
if data['test_name'] in FUNC_TO_GLOBAL_COUNTS:
|
||||
d['swift_count'] -= FUNC_TO_GLOBAL_COUNTS[data['test_name']]['swift_count']
|
||||
d['objc_count'] -= FUNC_TO_GLOBAL_COUNTS[data['test_name']]['objc_count']
|
||||
|
||||
return LeaksRunnerResult(test_name, (d['objc_count'] + d['swift_count']) > 0)
|
||||
except:
|
||||
print "Failed parse output! (%s,%s)" % (data['path'], data['test_name'])
|
||||
return LeaksRunnerResult(test_name, True)
|
||||
|
||||
SWIFT_BIN_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
if __name__ == "__main__":
|
||||
l = LeaksRunnerBenchmarkDriver(SWIFT_BIN_DIR, XFAIL_LIST)
|
||||
if l.run():
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(-1)
|
||||
35
benchmark/scripts/CMakeLists.txt
Normal file
35
benchmark/scripts/CMakeLists.txt
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
set(PATH_TO_DRIVER_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/perf_test_driver")
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Benchmark_GuardMalloc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Benchmark_GuardMalloc
|
||||
@ONLY)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Benchmark_RuntimeLeaksRunner.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Benchmark_RuntimeLeaksRunner
|
||||
@ONLY)
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Benchmark_DTrace.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Benchmark_DTrace
|
||||
@ONLY)
|
||||
set(PATH_TO_DRIVER_LIBRARY)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/Benchmark_GuardMalloc
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/bin
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
||||
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/Benchmark_RuntimeLeaksRunner
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/bin
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
||||
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_BINARY_DIR}/Benchmark_DTrace
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/bin
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
||||
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Benchmark_Driver
|
||||
DESTINATION ${CMAKE_BINARY_DIR}/bin
|
||||
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ
|
||||
GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
204
benchmark/scripts/compare_perf_tests.py
Executable file
204
benchmark/scripts/compare_perf_tests.py
Executable file
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# ===--- compare_perf_tests.py --------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
# e.g.
|
||||
# repeat.sh 3 tot/bin/Benchmark_Driver run -o -O > tot.O.times
|
||||
# repeat.sh 3 mypatch/bin/Benchmark_Driver run -o -O > mypatch.O.times
|
||||
# compare_perf_tests.py tot.O.times mypatch.O.times | sort -t, -n -k 6 | column -s, -t
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
VERBOSE = 0
|
||||
|
||||
# #,TEST,SAMPLES,MIN(ms),MAX(ms),MEAN(ms),SD(ms),MEDIAN(ms)
|
||||
SCORERE = re.compile(r"(\d+),[ \t]*(\w+),[ \t]*([\d.]+),[ \t]*([\d.]+)")
|
||||
TOTALRE = re.compile(r"()(Totals),[ \t]*([\d.]+),[ \t]*([\d.]+)")
|
||||
KEYGROUP = 2
|
||||
VALGROUP = 4
|
||||
NUMGROUP = 1
|
||||
|
||||
IsTime = 1
|
||||
ShowSpeedup = 1
|
||||
PrintAllScores = 0
|
||||
|
||||
def parseInt(word):
|
||||
try:
|
||||
return int(word)
|
||||
except:
|
||||
raise Exception("Expected integer value, not " + word)
|
||||
|
||||
def getScores(fname):
|
||||
scores = {}
|
||||
nums = {}
|
||||
runs = 0
|
||||
f = open(fname)
|
||||
try:
|
||||
for line in f:
|
||||
if VERBOSE:
|
||||
print "Parsing", line,
|
||||
m = SCORERE.match(line)
|
||||
is_total = False
|
||||
if not m:
|
||||
is_total = True
|
||||
m = TOTALRE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
if VERBOSE:
|
||||
print " match", m.group(KEYGROUP), m.group(VALGROUP)
|
||||
|
||||
if not m.group(KEYGROUP) in scores:
|
||||
scores[m.group(KEYGROUP)] = []
|
||||
scores[m.group(KEYGROUP)].append(parseInt(m.group(VALGROUP)))
|
||||
if is_total:
|
||||
nums[m.group(KEYGROUP)] = ""
|
||||
else:
|
||||
nums[m.group(KEYGROUP)] = m.group(NUMGROUP)
|
||||
if len(scores[m.group(KEYGROUP)]) > runs:
|
||||
runs = len(scores[m.group(KEYGROUP)])
|
||||
finally:
|
||||
f.close()
|
||||
return scores, runs, nums
|
||||
|
||||
def isMaxScore(newscore, maxscore, invert):
|
||||
return not maxscore or (newscore > maxscore if not invert else newscore < maxscore)
|
||||
|
||||
def compareScores(key, score1, score2, runs, num):
|
||||
print num.rjust(3),
|
||||
print key.ljust(25),
|
||||
bestscore1 = None
|
||||
bestscore2 = None
|
||||
worstscore1 = None
|
||||
worstscore2 = None
|
||||
minbest = IsTime
|
||||
minworst = not minbest
|
||||
r = 0
|
||||
for score in score1:
|
||||
if isMaxScore(newscore=score, maxscore=bestscore1, invert=minbest):
|
||||
bestscore1 = score
|
||||
if isMaxScore(newscore=score, maxscore=worstscore1, invert=minworst):
|
||||
worstscore1 = score
|
||||
if PrintAllScores:
|
||||
print ("%d" % score).rjust(16),
|
||||
for score in score2:
|
||||
if isMaxScore(newscore=score, maxscore=bestscore2, invert=minbest):
|
||||
bestscore2 = score
|
||||
if isMaxScore(newscore=score, maxscore=worstscore2, invert=minworst):
|
||||
worstscore2 = score
|
||||
if PrintAllScores:
|
||||
print ("%d" % score).rjust(16),
|
||||
r += 1
|
||||
while r < runs:
|
||||
if PrintAllScores:
|
||||
print ("0").rjust(9),
|
||||
r += 1
|
||||
|
||||
if not PrintAllScores:
|
||||
print ("%d" % bestscore1).rjust(16),
|
||||
print ("%d" % bestscore2).rjust(16),
|
||||
|
||||
print ("%+d" % (bestscore2 - bestscore1)).rjust(9),
|
||||
|
||||
if bestscore1 != 0 and bestscore2 != 0:
|
||||
print ("%+.1f%%" % (((float(bestscore2) / bestscore1) - 1) * 100)).rjust(9),
|
||||
if ShowSpeedup:
|
||||
Num, Den = float(bestscore2), float(bestscore1)
|
||||
if IsTime:
|
||||
Num, Den = Den, Num
|
||||
print ("%.2fx" % (Num / Den)).rjust(9),
|
||||
else:
|
||||
print "*".rjust(9),
|
||||
if ShowSpeedup:
|
||||
print "*".rjust(9),
|
||||
# if the interval endpoints have inverse relationship, then they overlap
|
||||
if minbest:
|
||||
if bestscore1 < worstscore2:
|
||||
print "(!)",
|
||||
else:
|
||||
if bestscore1 > worstscore2:
|
||||
print "(!)",
|
||||
print
|
||||
|
||||
def printBestScores(key, scores):
|
||||
print key,
|
||||
bestscore = None
|
||||
minbest = IsTime
|
||||
for score in scores:
|
||||
if isMaxScore(newscore=score, maxscore=bestscore, invert=minbest):
|
||||
bestscore = score
|
||||
print ", %d" % bestscore
|
||||
|
||||
def usage():
|
||||
print "repeat.sh <n> Benchmark_O[none|unchecked] > file.times"
|
||||
print "compare_perf_tests.py <file.times> [<file2.times>]"
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
usage()
|
||||
sys.exit(1)
|
||||
file1 = sys.argv[1]
|
||||
if len(sys.argv) < 3:
|
||||
scores, runs, nums = getScores(file1)
|
||||
keys = list(set(scores.keys()))
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
printBestScores(key, scores[key])
|
||||
sys.exit(0)
|
||||
|
||||
file2 = sys.argv[2]
|
||||
if len(sys.argv) > 3:
|
||||
SCORERE = re.compile(sys.argv[3])
|
||||
|
||||
scores1, runs1, nums = getScores(file1)
|
||||
scores2, runs2, nums = getScores(file2)
|
||||
|
||||
runs = runs1
|
||||
if runs2 > runs:
|
||||
runs = runs2
|
||||
|
||||
if VERBOSE:
|
||||
print scores1
|
||||
print scores2
|
||||
|
||||
keys = list(set(scores1.keys() + scores2.keys()))
|
||||
keys.sort()
|
||||
if VERBOSE:
|
||||
print "comparing ", file1, "vs", file2, "=",
|
||||
if IsTime:
|
||||
print file1, "/", file2
|
||||
else:
|
||||
print file2, "/", file1
|
||||
|
||||
print "#".rjust(3),
|
||||
print "TEST".ljust(25),
|
||||
if PrintAllScores:
|
||||
for i in range(0, runs):
|
||||
print ("OLD_RUN%d" % i).rjust(9),
|
||||
for i in range(0, runs):
|
||||
print ("NEW_RUN%d" % i).rjust(9),
|
||||
else:
|
||||
print "BEST_OLD_MIN(μs)".rjust(17),
|
||||
print "BEST_NEW_MIN(μs)".rjust(17),
|
||||
print 'DELTA'.rjust(9), '%DELTA'.rjust(9), 'SPEEDUP'.rjust(9)
|
||||
|
||||
for key in keys:
|
||||
if key not in scores1:
|
||||
print key, "not in", file1
|
||||
continue
|
||||
if key not in scores2:
|
||||
print key, "not in", file2
|
||||
continue
|
||||
compareScores(key, scores1[key], scores2[key], runs, nums[key])
|
||||
158
benchmark/scripts/generate_harness/CMakeLists.txt_template
Normal file
158
benchmark/scripts/generate_harness/CMakeLists.txt_template
Normal file
@@ -0,0 +1,158 @@
|
||||
# -*- mode: cmake -*-
|
||||
################################################################################
|
||||
# WARNING: This file is automatically generated from templates and should not
|
||||
# be directly modified. Instead, make changes to
|
||||
# scripts/generate_harness/CMakeLists.txt_template and run
|
||||
# scripts/generate_harness/generate_harness.py to regenerate this file.
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
# Add path for custom CMake modules.
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include(AddSwiftBenchmarkSuite)
|
||||
|
||||
set(SWIFT_BENCH_MODULES
|
||||
{% for test in tests %}
|
||||
single-source/{{ test }}
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
set(SWIFT_MULTISOURCE_BENCHES
|
||||
{% for multisource_bench in multisource_benches %}
|
||||
multi-source/{{ multisource_bench.name }}
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
{% for multisource_bench in multisource_benches %}
|
||||
set({{ multisource_bench.name }}_sources
|
||||
{% for file in multisource_bench.files %}
|
||||
multi-source/{{ multisource_bench.name }}/{{ file }}
|
||||
{% endfor %}
|
||||
)
|
||||
|
||||
{% endfor %}
|
||||
|
||||
set(BENCH_DRIVER_LIBRARY_MODULES
|
||||
utils/DriverUtils
|
||||
utils/TestsUtils
|
||||
)
|
||||
|
||||
set(BENCH_DRIVER_LIBRARY_FLAGS)
|
||||
if (SWIFT_RUNTIME_ENABLE_LEAK_CHECKER)
|
||||
set(BENCH_DRIVER_LIBRARY_FLAGS -DSWIFT_RUNTIME_ENABLE_LEAK_CHECKER)
|
||||
endif()
|
||||
|
||||
set(BENCH_LIBRARY_MODULES
|
||||
)
|
||||
|
||||
add_definitions(-DSWIFT_EXEC -DSWIFT_LIBRARY_PATH -DONLY_PLATFORMS
|
||||
-DSWIFT_OPTIMIZATION_LEVELS -DSWIFT_BENCHMARK_EMIT_SIB)
|
||||
|
||||
if(NOT ONLY_PLATFORMS)
|
||||
set(ONLY_PLATFORMS "macosx" "iphoneos" "appletvos" "watchos")
|
||||
endif()
|
||||
|
||||
if(NOT SWIFT_EXEC)
|
||||
runcmd(COMMAND "xcrun" "-f" "swiftc"
|
||||
VARIABLE SWIFT_EXEC
|
||||
ERROR "Unable to find Swift driver")
|
||||
endif()
|
||||
|
||||
if(NOT SWIFT_LIBRARY_PATH)
|
||||
get_filename_component(tmp_dir "${SWIFT_EXEC}" DIRECTORY)
|
||||
get_filename_component(tmp_dir "${tmp_dir}" DIRECTORY)
|
||||
set(SWIFT_LIBRARY_PATH "${tmp_dir}/lib/swift")
|
||||
endif()
|
||||
|
||||
runcmd(COMMAND "xcrun" "-f" "clang"
|
||||
VARIABLE CLANG_EXEC
|
||||
ERROR "Unable to find Clang driver")
|
||||
|
||||
# You have to delete CMakeCache.txt in the swift build to force a
|
||||
# reconfiguration.
|
||||
set(SWIFT_EXTRA_BENCH_CONFIGS CACHE STRING
|
||||
"A semicolon separated list of benchmark configurations. \
|
||||
Available configurations: <Optlevel>_SINGLEFILE, <Optlevel>_MULTITHREADED")
|
||||
|
||||
# Syntax for an optset: <optimization-level>_<configuration>
|
||||
# where "_<configuration>" is optional.
|
||||
if(NOT SWIFT_OPTIMIZATION_LEVELS)
|
||||
set(SWIFT_OPTIMIZATION_LEVELS "Onone" "O" "Ounchecked"
|
||||
${SWIFT_EXTRA_BENCH_CONFIGS})
|
||||
endif()
|
||||
|
||||
# Options for the default (= empty) configuration
|
||||
set(BENCHOPTS "-whole-module-optimization")
|
||||
|
||||
# Options for other configurations
|
||||
set(BENCHOPTS_MULTITHREADED
|
||||
"-whole-module-optimization" "-num-threads" "4")
|
||||
set(BENCHOPTS_SINGLEFILE "")
|
||||
|
||||
set(macosx_arch "x86_64")
|
||||
set(iphoneos_arch "arm64" "armv7")
|
||||
set(appletvos_arch "arm64")
|
||||
set(watchos_arch "armv7k")
|
||||
|
||||
set(macosx_ver "10.9")
|
||||
set(iphoneos_ver "8.0")
|
||||
set(appletvos_ver "9.1")
|
||||
set(watchos_ver "2.0")
|
||||
|
||||
set(macosx_triple_platform "macosx")
|
||||
set(iphoneos_triple_platform "ios")
|
||||
set(appletvos_triple_platform "tvos")
|
||||
set(watchos_triple_platform "watchos")
|
||||
|
||||
set(sdks)
|
||||
set(platforms)
|
||||
foreach(platform ${ONLY_PLATFORMS})
|
||||
execute_process(
|
||||
COMMAND "xcrun" "--sdk" "${platform}" "--show-sdk-path"
|
||||
OUTPUT_VARIABLE ${platform}_sdk
|
||||
RESULT_VARIABLE result
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if("${result}" MATCHES "0")
|
||||
list(APPEND sdks "${${platform}_sdk}")
|
||||
list(APPEND platforms ${platform})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message("--")
|
||||
message("-- Swift Benchmark Suite:")
|
||||
message("-- SWIFT_EXEC = ${SWIFT_EXEC}")
|
||||
message("-- SWIFT_LIBRARY_PATH = ${SWIFT_LIBRARY_PATH}")
|
||||
message("-- CLANG_EXEC = ${CLANG_EXEC}")
|
||||
message("-- SWIFT_OPTIMIZATION_LEVELS = ${SWIFT_OPTIMIZATION_LEVELS}")
|
||||
message("-- ONLY_PLATFORMS = ${ONLY_PLATFORMS}")
|
||||
|
||||
message("-- found platforms: ${platforms}")
|
||||
message("-- found sdks:")
|
||||
foreach(sdk ${sdks})
|
||||
message("-- ${sdk}")
|
||||
endforeach()
|
||||
|
||||
set(executable_targets)
|
||||
|
||||
set(srcdir "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(bindir "${CMAKE_CURRENT_BINARY_DIR}/bin")
|
||||
set(libdir "${CMAKE_CURRENT_BINARY_DIR}/lib")
|
||||
set(libswiftdir "${CMAKE_CURRENT_BINARY_DIR}/lib/swift")
|
||||
file(MAKE_DIRECTORY "${bindir}")
|
||||
file(MAKE_DIRECTORY "${libdir}")
|
||||
file(MAKE_DIRECTORY "${libswiftdir}")
|
||||
|
||||
if(SWIFT_SDKS)
|
||||
set(IS_SWIFT_BUILD true)
|
||||
endif()
|
||||
|
||||
# Compile the perf test suite for each platform
|
||||
foreach(platform ${platforms})
|
||||
swift_benchmark_compile(PLATFORM ${platform})
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(scripts)
|
||||
|
||||
90
benchmark/scripts/generate_harness/generate_harness.py
Normal file
90
benchmark/scripts/generate_harness/generate_harness.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- generate_harness.py ----------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
# Generate CMakeLists.txt and utils/main.swift from templates.
|
||||
|
||||
import jinja2
|
||||
import os
|
||||
import glob
|
||||
import re
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
perf_dir = os.path.realpath(os.path.join(script_dir, '../..'))
|
||||
single_source_dir = os.path.join(perf_dir, 'single-source')
|
||||
multi_source_dir = os.path.join(perf_dir, 'multi-source')
|
||||
|
||||
template_map = {
|
||||
'CMakeLists.txt_template': os.path.join(perf_dir, 'CMakeLists.txt'),
|
||||
'main.swift_template': os.path.join(perf_dir, 'utils/main.swift')
|
||||
}
|
||||
ignored_run_funcs = ["Ackermann", "Fibonacci"]
|
||||
|
||||
template_loader = jinja2.FileSystemLoader(searchpath="/")
|
||||
template_env = jinja2.Environment(loader=template_loader, trim_blocks=True,
|
||||
lstrip_blocks=True)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# CMakeList single-source
|
||||
tests = [os.path.basename(x).split('.')[0]
|
||||
for x in glob.glob(os.path.join(single_source_dir, '*.swift'))]
|
||||
|
||||
# CMakeList multi-source
|
||||
class multi_source_bench(object):
|
||||
def __init__(self, path):
|
||||
self.name = os.path.basename(path)
|
||||
self.files = [x for x in os.listdir(path)
|
||||
if x.endswith('.swift')]
|
||||
if os.path.isdir(multi_source_dir):
|
||||
multisource_benches = [
|
||||
multi_source_bench(os.path.join(multi_source_dir, x))
|
||||
for x in os.listdir(multi_source_dir)
|
||||
if os.path.isdir(os.path.join(multi_source_dir, x))
|
||||
]
|
||||
else:
|
||||
multisource_benches = []
|
||||
|
||||
# main.swift imports
|
||||
imports = sorted(tests + [msb.name for msb in multisource_benches])
|
||||
|
||||
# main.swift run functions
|
||||
def get_run_funcs(filepath):
|
||||
content = open(filepath).read()
|
||||
matches = re.findall(r'func run_(.*?)\(', content)
|
||||
return filter(lambda x: x not in ignored_run_funcs, matches)
|
||||
|
||||
def find_run_funcs(dirs):
|
||||
ret_run_funcs = []
|
||||
for d in dirs:
|
||||
for root, _, files in os.walk(d):
|
||||
for name in filter(lambda x: x.endswith('.swift'), files):
|
||||
run_funcs = get_run_funcs(os.path.join(root, name))
|
||||
ret_run_funcs.extend(run_funcs)
|
||||
return ret_run_funcs
|
||||
run_funcs = sorted(
|
||||
[(x, x)
|
||||
for x in find_run_funcs([single_source_dir, multi_source_dir])],
|
||||
key=lambda x: x[0]
|
||||
)
|
||||
|
||||
# Replace originals with files generated from templates
|
||||
for template_file in template_map:
|
||||
template_path = os.path.join(script_dir, template_file)
|
||||
template = template_env.get_template(template_path)
|
||||
print template_map[template_file]
|
||||
open(template_map[template_file], 'w').write(
|
||||
template.render(tests=tests,
|
||||
multisource_benches=multisource_benches,
|
||||
imports=imports,
|
||||
run_funcs=run_funcs)
|
||||
)
|
||||
40
benchmark/scripts/generate_harness/main.swift_template
Normal file
40
benchmark/scripts/generate_harness/main.swift_template
Normal file
@@ -0,0 +1,40 @@
|
||||
//===--- main.swift -------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WARNING: This file is automatically generated from templates and should not
|
||||
// be directly modified. Instead, make changes to
|
||||
// scripts/generate_harness/main.swift_template and run
|
||||
// scripts/generate_harness/generate_harness.py to regenerate this file.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This is just a driver for performance overview tests.
|
||||
import TestsUtils
|
||||
import DriverUtils
|
||||
{% for import in imports %}
|
||||
import {{ import }}
|
||||
{% endfor %}
|
||||
|
||||
precommitTests = [
|
||||
{% for run_func in run_funcs %}
|
||||
"{{ run_func[0] }}": run_{{ run_func[1] }},
|
||||
{% endfor %}
|
||||
]
|
||||
|
||||
otherTests = [
|
||||
"Ackermann": run_Ackermann,
|
||||
"Fibonacci": run_Fibonacci,
|
||||
]
|
||||
|
||||
|
||||
main()
|
||||
|
||||
124
benchmark/scripts/perf_test_driver/perf_test_driver.py
Normal file
124
benchmark/scripts/perf_test_driver/perf_test_driver.py
Normal file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- perf_test_driver.py ----------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
import re
|
||||
|
||||
class Result(object):
|
||||
def __init__(self, name, status, output, xfail_list):
|
||||
self.name = name
|
||||
self.status = status
|
||||
self.output = output
|
||||
self.is_xfailed = any((re.match(x, self.name) is not None for x in xfail_list))
|
||||
|
||||
def is_failure(self):
|
||||
return self.get_result() in ['FAIL', 'XPASS']
|
||||
|
||||
def get_result(self):
|
||||
if self.is_xfailed:
|
||||
if self.status:
|
||||
return 'XFAIL'
|
||||
return 'XPASS'
|
||||
if self.status:
|
||||
return 'FAIL'
|
||||
return 'PASS'
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
def get_status(self):
|
||||
return self.status
|
||||
|
||||
def get_output(self):
|
||||
return self.output
|
||||
|
||||
def get_data(self):
|
||||
return self.data
|
||||
|
||||
def merge_in_extra_data(self, d):
|
||||
"""Rather than modifying the extra data dict, just return it as a no-op"""
|
||||
return d
|
||||
|
||||
def print_data(self, max_test_len):
|
||||
fmt = '{:<%d}{:}' % (max_test_len + 5)
|
||||
print(fmt.format(self.get_name(), self.get_result()))
|
||||
|
||||
def _unwrap_self(args):
|
||||
return type(args[0]).process_input(*args)
|
||||
|
||||
BenchmarkDriver_OptLevels = ['Onone', 'O', 'Ounchecked']
|
||||
|
||||
class BenchmarkDriver(object):
|
||||
|
||||
def __init__(self, binary_dir, xfail_list, enable_parallel=False, opt_levels=BenchmarkDriver_OptLevels):
|
||||
self.targets = [(os.path.join(binary_dir, 'Benchmark_%s' % o), o) for o in opt_levels]
|
||||
self.xfail_list = xfail_list
|
||||
self.enable_parallel = enable_parallel
|
||||
self.data = None
|
||||
|
||||
def print_data_header(self, max_test_len):
|
||||
fmt = '{:<%d}{:}' % (max_test_len + 5)
|
||||
print(fmt.format('Name', 'Result'))
|
||||
|
||||
def prepare_input(self, name, opt_level):
|
||||
raise RuntimeError("Abstract method")
|
||||
|
||||
def process_input(self, data):
|
||||
raise RuntimeError("Abstract method")
|
||||
|
||||
def run_for_opt_level(self, binary, opt_level, test_filter):
|
||||
print("testing driver at path: %s" % binary)
|
||||
names = [n.strip() for n in subprocess.check_output([binary, "--list"]).split()[2:]]
|
||||
if test_filter:
|
||||
regex = re.compile(test_filter)
|
||||
names = [n for n in names if regex.match(n)]
|
||||
|
||||
def prepare_input_wrapper(name):
|
||||
x = {'opt': opt_level, 'path': binary, 'test_name': name}
|
||||
x.update(self.prepare_input(name))
|
||||
return x
|
||||
|
||||
prepared_input = [prepare_input_wrapper(n) for n in names]
|
||||
results = None
|
||||
if self.enable_parallel:
|
||||
p = multiprocessing.Pool()
|
||||
z = zip([self] * len(prepared_input), prepared_input)
|
||||
results = p.map(_unwrap_self, z)
|
||||
else:
|
||||
results = map(self.process_input, prepared_input)
|
||||
|
||||
def reduce_results(acc, r):
|
||||
acc['result'].append(r)
|
||||
acc['has_failure'] = acc['has_failure'] or r.is_failure()
|
||||
acc['max_test_len'] = max(acc['max_test_len'], len(r.get_name()))
|
||||
acc['extra_data'] = r.merge_in_extra_data(acc['extra_data'])
|
||||
return acc
|
||||
|
||||
return reduce(reduce_results, results, {'result': [], 'has_failure': False, 'max_test_len': 0, 'extra_data': {}})
|
||||
|
||||
def print_data(self, data, max_test_len):
|
||||
print("Results:")
|
||||
self.print_data_header(max_test_len)
|
||||
for d in data:
|
||||
for r in d['result']:
|
||||
r.print_data(max_test_len)
|
||||
|
||||
def run(self, test_filter=None):
|
||||
self.data = [self.run_for_opt_level(binary, opt_level, test_filter) for binary, opt_level in self.targets]
|
||||
max_test_len = reduce(max, [d['max_test_len']for d in self.data])
|
||||
has_failure = reduce(max, [d['has_failure']for d in self.data])
|
||||
self.print_data(self.data, max_test_len)
|
||||
return not has_failure
|
||||
27
benchmark/scripts/perf_test_driver/swift_stats.d
Normal file
27
benchmark/scripts/perf_test_driver/swift_stats.d
Normal file
@@ -0,0 +1,27 @@
|
||||
/*===--- swift_stats.d ----------------------------------------------------===//
|
||||
*
|
||||
* This source file is part of the Swift.org open source project
|
||||
*
|
||||
* Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
* Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
*
|
||||
* See http://swift.org/LICENSE.txt for license information
|
||||
* See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
*
|
||||
*===----------------------------------------------------------------------===*/
|
||||
|
||||
pid$target:*:swift_retain:entry
|
||||
{
|
||||
@counts[probefunc] = count();
|
||||
}
|
||||
|
||||
pid$target:*:swift_release:entry
|
||||
{
|
||||
@counts[probefunc] = count();
|
||||
}
|
||||
|
||||
END
|
||||
{
|
||||
printf("\nDTRACE RESULTS\n");
|
||||
printa("%s,%@u\n", @counts)
|
||||
}
|
||||
47
benchmark/single-source/Ackermann.swift
Normal file
47
benchmark/single-source/Ackermann.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
//===--- Ackermann.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test is based on test Ackermann from utils/benchmark, with modifications
|
||||
// for performance measuring.
|
||||
import TestsUtils
|
||||
|
||||
func ackermann(M : Int, _ N : Int) -> Int {
|
||||
if (M == 0) { return N + 1 }
|
||||
if (N == 0) { return ackermann(M - 1, 1) }
|
||||
return ackermann(M - 1, ackermann(M, N - 1))
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func Ackermann(M : Int, _ N : Int) -> Int {
|
||||
// This if prevents optimizer from computing return value of Ackermann(3,9)
|
||||
// at compile time.
|
||||
if False() { return 0 }
|
||||
if (M == 0) { return N + 1 }
|
||||
if (N == 0) { return ackermann(M - 1, 1) }
|
||||
return ackermann(M - 1, ackermann(M, N - 1))
|
||||
}
|
||||
|
||||
let ref_result = [5, 13, 29, 61, 125, 253, 509, 1021, 2045, 4093, 8189, 16381, 32765, 65533, 131069];
|
||||
|
||||
@inline(never)
|
||||
public func run_Ackermann(N: Int) {
|
||||
let (m, n) = (3, 9)
|
||||
var result = 0
|
||||
for _ in 1...N {
|
||||
result = Ackermann(m, n)
|
||||
if result != ref_result[n] {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(result == ref_result[n],
|
||||
"IncorrectResults in Ackermann: \(result) != \(ref_result[n]).")
|
||||
}
|
||||
43
benchmark/single-source/AngryPhonebook.swift
Normal file
43
benchmark/single-source/AngryPhonebook.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//===--- AngryPhonebook.swift ---------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test is based on single-source/Phonebook, with
|
||||
// to test uppercase and lowercase ASCII string fast paths.
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
var words = [
|
||||
"James", "John", "Robert", "Michael", "William", "David", "Richard", "Joseph",
|
||||
"Charles", "Thomas", "Christopher", "Daniel", "Matthew", "Donald", "Anthony",
|
||||
"Paul", "Mark", "George", "Steven", "Kenneth", "Andrew", "Edward", "Brian",
|
||||
"Joshua", "Kevin", "Ronald", "Timothy", "Jason", "Jeffrey", "Gary", "Ryan",
|
||||
"Nicholas", "Eric", "Stephen", "Jacob", "Larry", "Frank", "Jonathan", "Scott",
|
||||
"Justin", "Raymond", "Brandon", "Gregory", "Samuel", "Patrick", "Benjamin",
|
||||
"Jack", "Dennis", "Jerry", "Alexander", "Tyler", "Douglas", "Henry", "Peter",
|
||||
"Walter", "Aaron", "Jose", "Adam", "Harold", "Zachary", "Nathan", "Carl",
|
||||
"Kyle", "Arthur", "Gerald", "Lawrence", "Roger", "Albert", "Keith", "Jeremy",
|
||||
"Terry", "Joe", "Sean", "Willie", "Jesse", "Ralph", "Billy", "Austin", "Bruce",
|
||||
"Christian", "Roy", "Bryan", "Eugene", "Louis", "Harry", "Wayne", "Ethan",
|
||||
"Jordan", "Russell", "Alan", "Philip", "Randy", "Juan", "Howard", "Vincent",
|
||||
"Bobby", "Dylan", "Johnny", "Phillip", "Craig"]
|
||||
|
||||
@inline(never)
|
||||
public func run_AngryPhonebook(N: Int) {
|
||||
// Permute the names.
|
||||
for _ in 1...N {
|
||||
for firstname in words {
|
||||
for lastname in words {
|
||||
(firstname.uppercased, lastname.lowercased)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
benchmark/single-source/Array2D.swift
Normal file
31
benchmark/single-source/Array2D.swift
Normal file
@@ -0,0 +1,31 @@
|
||||
//===--- Array2D.swift ----------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@inline(never)
|
||||
public func run_Array2D(N: Int) {
|
||||
var A: [[Int]] = []
|
||||
for _ in 0 ..< 1024 {
|
||||
var B: [Int] = []
|
||||
for y in 0 ..< 1024 {
|
||||
B.append(y)
|
||||
}
|
||||
A.append(B)
|
||||
}
|
||||
for _ in 0..<N {
|
||||
for i in 0 ..< 1024 {
|
||||
for y in 0 ..< 1024 {
|
||||
A[i][y] = A[i][y] + 1
|
||||
A[i][y] = A[i][y] - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
40
benchmark/single-source/ArrayAppend.swift
Normal file
40
benchmark/single-source/ArrayAppend.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
//===--- ArrayAppend.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks the performance of appending to an array.
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayAppend(N: Int) {
|
||||
for _ in 0..<N {
|
||||
for _ in 0..<10 {
|
||||
var nums = [Int]()
|
||||
for _ in 0..<40000 {
|
||||
nums.append(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayAppendReserved(N: Int) {
|
||||
for _ in 0..<N {
|
||||
for _ in 0..<10 {
|
||||
var nums = [Int]()
|
||||
nums.reserveCapacity(40000)
|
||||
for _ in 0..<40000 {
|
||||
nums.append(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
benchmark/single-source/ArrayInClass.swift
Normal file
38
benchmark/single-source/ArrayInClass.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//===--- ArrayInClass.swift -----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class ArrayContainer {
|
||||
final var arr : [Int]
|
||||
|
||||
init() {
|
||||
arr = [Int] (repeating: 0, count: 100_000)
|
||||
}
|
||||
|
||||
func runLoop(N: Int) {
|
||||
for _ in 0 ..< N {
|
||||
for i in 0 ..< arr.count {
|
||||
arr[i] = arr[i] + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func getArrayContainer() -> ArrayContainer {
|
||||
return ArrayContainer()
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayInClass(N: Int) {
|
||||
let a = getArrayContainer()
|
||||
a.runLoop(N)
|
||||
}
|
||||
105
benchmark/single-source/ArrayLiteral.swift
Normal file
105
benchmark/single-source/ArrayLiteral.swift
Normal file
@@ -0,0 +1,105 @@
|
||||
//===--- ArrayLiteral.swift -----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of creating array from literal and array value
|
||||
// propagation.
|
||||
// It is reported to be slow: <rdar://problem/17297449>
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
func makeArray() -> [Int] {
|
||||
return [1,2,3]
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayLiteral(N: Int) {
|
||||
for _ in 1...10000*N {
|
||||
makeArray()
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func addLiteralArray() -> Int {
|
||||
let Arr = [1, 2, 3]
|
||||
return Arr[0] + Arr[1] + Arr[2]
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayValueProp(N: Int) {
|
||||
var res = 123
|
||||
for _ in 1...10000*N {
|
||||
res += addLiteralArray()
|
||||
res -= addLiteralArray()
|
||||
}
|
||||
CheckResults(res == 123, "Wrong result in ArrayValueProp 123 != \(res)")
|
||||
}
|
||||
|
||||
|
||||
@inline(never)
|
||||
func addLiteralArray2() -> Int {
|
||||
let Arr = [1, 2, 3]
|
||||
var r = 0
|
||||
for elt in Arr {
|
||||
r += elt
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func addLiteralArray3() -> Int {
|
||||
let Arr = [1, 2, 3]
|
||||
var r = 0
|
||||
for i in 0..<Arr.count {
|
||||
r += Arr[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func addLiteralArray4() -> Int {
|
||||
let Arr = [1, 2, 3]
|
||||
var r = 0
|
||||
for i in 0..<3 {
|
||||
r += Arr[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayValueProp2(N: Int) {
|
||||
var res = 123
|
||||
for _ in 1...10000*N {
|
||||
res += addLiteralArray2()
|
||||
res -= addLiteralArray2()
|
||||
}
|
||||
CheckResults(res == 123, "Wrong result in ArrayValueProp 123 != \(res)")
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayValueProp3(N: Int) {
|
||||
var res = 123
|
||||
for _ in 1...10000*N {
|
||||
res += addLiteralArray3()
|
||||
res -= addLiteralArray3()
|
||||
}
|
||||
CheckResults(res == 123, "Wrong result in ArrayValueProp 123 != \(res)")
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayValueProp4(N: Int) {
|
||||
var res = 123
|
||||
for _ in 1...10000*N {
|
||||
res += addLiteralArray4()
|
||||
res -= addLiteralArray4()
|
||||
}
|
||||
CheckResults(res == 123, "Wrong result in ArrayValueProp 123 != \(res)")
|
||||
}
|
||||
67
benchmark/single-source/ArrayOfGenericPOD.swift
Normal file
67
benchmark/single-source/ArrayOfGenericPOD.swift
Normal file
@@ -0,0 +1,67 @@
|
||||
//===--- ArrayOfGenericPOD.swift ------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This benchmark tests creation and destruction of arrays of enum and
|
||||
// generic type bound to trivial types. It should take the same time as
|
||||
// ArrayOfPOD. (In practice, it takes a little longer to construct
|
||||
// the optional arrays).
|
||||
//
|
||||
// For comparison, we always create three arrays of 200,000 words.
|
||||
// An integer enum takes two words.
|
||||
|
||||
class RefArray<T> {
|
||||
var array : [T]
|
||||
|
||||
init(_ i:T) {
|
||||
array = [T](repeating: i, count: 100000)
|
||||
}
|
||||
}
|
||||
|
||||
// Check the performance of destroying an array of enums (optional) where the
|
||||
// enum has a single payload of trivial type. Destroying the
|
||||
// elements should be a nop.
|
||||
@inline(never)
|
||||
func genEnumArray() {
|
||||
_ = RefArray<Int?>(3)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
// Check the performance of destroying an array of implicit unwrapped
|
||||
// optional where the optional has a single payload of trivial
|
||||
// type. Destroying the elements should be a nop.
|
||||
@inline(never)
|
||||
func genIOUArray() {
|
||||
_ = RefArray<Int!>(3)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
// Check the performance of destroying an array of structs where the
|
||||
// struct has multiple fields of trivial type. Destroying the
|
||||
// elements should be a nop.
|
||||
struct S<T> {
|
||||
var x : T
|
||||
var y : T
|
||||
}
|
||||
@inline(never)
|
||||
func genStructArray() {
|
||||
_ = RefArray<S<Int>>(S(x:3,y:4))
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayOfGenericPOD(N: Int) {
|
||||
for _ in 0...N {
|
||||
genEnumArray()
|
||||
genIOUArray()
|
||||
genStructArray()
|
||||
}
|
||||
}
|
||||
96
benchmark/single-source/ArrayOfGenericRef.swift
Normal file
96
benchmark/single-source/ArrayOfGenericRef.swift
Normal file
@@ -0,0 +1,96 @@
|
||||
//===--- ArrayOfGenericRef.swift ------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This benchmark tests creation and destruction of an array of enum
|
||||
// and generic type bound to nontrivial types.
|
||||
//
|
||||
// For comparison, we always create three arrays of 10,000 words.
|
||||
|
||||
protocol Constructible {
|
||||
associatedtype Element
|
||||
init(e:Element)
|
||||
}
|
||||
class ConstructibleArray<T:Constructible> {
|
||||
var array : [T]
|
||||
|
||||
init(_ e:T.Element) {
|
||||
array = [T]()
|
||||
array.reserveCapacity(10_000)
|
||||
for _ in 0...10_000 {
|
||||
array.append(T(e:e) as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GenericRef<T> : Constructible {
|
||||
typealias Element=T
|
||||
var x : T
|
||||
required init(e:T) { self.x = e }
|
||||
}
|
||||
|
||||
// Reference to a POD class.
|
||||
@inline(never)
|
||||
func genPODRefArray() {
|
||||
_ = ConstructibleArray<GenericRef<Int>>(3)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
class Dummy {}
|
||||
|
||||
// Reference to a reference. The nested reference is shared across elements.
|
||||
@inline(never)
|
||||
func genCommonRefArray() {
|
||||
let d = Dummy()
|
||||
_ = ConstructibleArray<GenericRef<Dummy>>(d)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
// Reuse the same enum value for each element.
|
||||
class RefArray<T> {
|
||||
var array : [T]
|
||||
|
||||
init(_ i:T, count:Int = 10_000) {
|
||||
array = [T](repeating: i, count: count)
|
||||
}
|
||||
}
|
||||
|
||||
// enum holding a reference.
|
||||
@inline(never)
|
||||
func genRefEnumArray() {
|
||||
let d = Dummy()
|
||||
_ = RefArray<Dummy?>(d)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
struct GenericVal<T> : Constructible {
|
||||
typealias Element=T
|
||||
var x : T
|
||||
init(e:T) { self.x = e }
|
||||
}
|
||||
|
||||
// Struct holding a reference.
|
||||
@inline(never)
|
||||
func genRefStructArray() {
|
||||
let d = Dummy()
|
||||
_ = ConstructibleArray<GenericVal<Dummy>>(d)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayOfGenericRef(N: Int) {
|
||||
for _ in 0...N {
|
||||
genPODRefArray()
|
||||
genCommonRefArray()
|
||||
genRefEnumArray()
|
||||
genRefStructArray()
|
||||
}
|
||||
}
|
||||
62
benchmark/single-source/ArrayOfPOD.swift
Normal file
62
benchmark/single-source/ArrayOfPOD.swift
Normal file
@@ -0,0 +1,62 @@
|
||||
//===--- ArrayOfPOD.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This benchmark tests creation and destruction of an array of
|
||||
// trivial static type. It is meant to be a baseline for comparison against
|
||||
// ArrayOfGenericPOD.
|
||||
//
|
||||
// For comparison, we always create three arrays of 200,000 words.
|
||||
|
||||
class RefArray<T> {
|
||||
var array : [T]
|
||||
|
||||
init(_ i:T, count:Int = 100_000) {
|
||||
array = [T](repeating: i, count: count)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genIntArray() {
|
||||
_ = RefArray<Int>(3, count:200_000)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
enum PODEnum {
|
||||
case Some(Int)
|
||||
|
||||
init(i:Int) { self = .Some(i) }
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genEnumArray() {
|
||||
_ = RefArray<PODEnum>(PODEnum.Some(3))
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
struct S {
|
||||
var x : Int
|
||||
var y : Int
|
||||
}
|
||||
@inline(never)
|
||||
func genStructArray() {
|
||||
_ = RefArray<S>(S(x:3, y:4))
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayOfPOD(N: Int) {
|
||||
for _ in 0...N {
|
||||
genIntArray()
|
||||
genEnumArray()
|
||||
genStructArray()
|
||||
}
|
||||
}
|
||||
107
benchmark/single-source/ArrayOfRef.swift
Normal file
107
benchmark/single-source/ArrayOfRef.swift
Normal file
@@ -0,0 +1,107 @@
|
||||
//===--- ArrayOfRef.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This benchmark tests creation and destruction of an array of
|
||||
// references. It is meant to be a baseline for comparison against
|
||||
// ArrayOfGenericRef.
|
||||
//
|
||||
// For comparison, we always create four arrays of 10,000 words.
|
||||
|
||||
protocol Constructible {
|
||||
associatedtype Element
|
||||
init(e:Element)
|
||||
}
|
||||
class ConstructibleArray<T:Constructible> {
|
||||
var array : [T]
|
||||
|
||||
init(_ e:T.Element) {
|
||||
array = [T]()
|
||||
array.reserveCapacity(10_000)
|
||||
for _ in 0...10_000 {
|
||||
array.append(T(e:e) as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reference to a POD class.
|
||||
class POD : Constructible {
|
||||
typealias Element=Int
|
||||
var x : Int
|
||||
required init(e:Int) { self.x = e }
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genPODRefArray() {
|
||||
_ = ConstructibleArray<POD>(3)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
class Dummy {}
|
||||
|
||||
// Reference to a reference. The nested reference is shared across elements.
|
||||
class CommonRef : Constructible {
|
||||
typealias Element=Dummy
|
||||
var d : Dummy
|
||||
required init(e:Dummy) { self.d = e }
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genCommonRefArray() {
|
||||
let d = Dummy()
|
||||
_ = ConstructibleArray<CommonRef>(d)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
enum RefEnum {
|
||||
case None
|
||||
case Some(Dummy)
|
||||
}
|
||||
|
||||
// Reuse the same enum value for each element.
|
||||
class RefArray<T> {
|
||||
var array : [T]
|
||||
|
||||
init(_ i:T, count:Int = 10_000) {
|
||||
array = [T](repeating: i, count: count)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genRefEnumArray() {
|
||||
let e = RefEnum.Some(Dummy())
|
||||
_ = RefArray<RefEnum>(e)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
// Struct holding a reference.
|
||||
struct S : Constructible {
|
||||
typealias Element=Dummy
|
||||
var d : Dummy
|
||||
init(e:Dummy) { self.d = e }
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func genRefStructArray() {
|
||||
let d = Dummy()
|
||||
_ = ConstructibleArray<S>(d)
|
||||
// should be a nop
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ArrayOfRef(N: Int) {
|
||||
for _ in 0...N {
|
||||
genPODRefArray()
|
||||
genCommonRefArray()
|
||||
genRefEnumArray()
|
||||
genRefStructArray()
|
||||
}
|
||||
}
|
||||
39
benchmark/single-source/ArraySubscript.swift
Normal file
39
benchmark/single-source/ArraySubscript.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
//===--- ArraySubscript.swift ---------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks the performance of modifying an array element.
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_ArraySubscript(N: Int) {
|
||||
SRand()
|
||||
|
||||
let numArrays = 200*N
|
||||
let numArrayElements = 100
|
||||
|
||||
func bound(x: Int) -> Int { return min(x, numArrayElements-1) }
|
||||
|
||||
var arrays = [[Int]](repeating: [], count: numArrays)
|
||||
for i in 0..<numArrays {
|
||||
for _ in 0..<numArrayElements {
|
||||
arrays[i].append(Int(truncatingBitPattern: Random()))
|
||||
}
|
||||
}
|
||||
|
||||
// Do a max up the diagonal.
|
||||
for i in 1..<numArrays {
|
||||
arrays[i][bound(i)] =
|
||||
max(arrays[i-1][bound(i-1)], arrays[i][bound(i)])
|
||||
}
|
||||
CheckResults(arrays[0][0] <= arrays[numArrays-1][bound(numArrays-1)],
|
||||
"Incorrect results in QuickSort.")
|
||||
}
|
||||
40
benchmark/single-source/BitCount.swift
Normal file
40
benchmark/single-source/BitCount.swift
Normal file
@@ -0,0 +1,40 @@
|
||||
//===--- BitCount.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of Swift bit count.
|
||||
// and mask operator.
|
||||
// rdar://problem/22151678
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
func countBitSet(num: Int) -> Int {
|
||||
let bits = sizeof(Int) * 8
|
||||
var cnt : Int = 0
|
||||
var mask: Int = 1
|
||||
for _ in 0...bits {
|
||||
if num & mask != 0 {
|
||||
cnt += 1
|
||||
}
|
||||
mask <<= 1
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_BitCount(N: Int) {
|
||||
for _ in 1...100*N {
|
||||
// Check some results.
|
||||
CheckResults(countBitSet(1) == 1, "Incorrect results in BitCount.")
|
||||
CheckResults(countBitSet(2) == 1, "Incorrect results in BitCount.")
|
||||
CheckResults(countBitSet(2457) == 6, "Incorrect results in BitCount.")
|
||||
}
|
||||
}
|
||||
48
benchmark/single-source/ByteSwap.swift
Normal file
48
benchmark/single-source/ByteSwap.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//===--- ByteSwap.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of Swift byte swap.
|
||||
// rdar://problem/22151907
|
||||
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
// a naive O(n) implementation of byteswap.
|
||||
func byteswap_n(a: UInt64) -> UInt64 {
|
||||
return ((a & 0x00000000000000FF) << 56) |
|
||||
((a & 0x000000000000FF00) << 40) |
|
||||
((a & 0x0000000000FF0000) << 24) |
|
||||
((a & 0x00000000FF000000) << 8) |
|
||||
((a & 0x000000FF00000000) >> 8) |
|
||||
((a & 0x0000FF0000000000) >> 24) |
|
||||
((a & 0x00FF000000000000) >> 40) |
|
||||
((a & 0xFF00000000000000) >> 56)
|
||||
}
|
||||
|
||||
// a O(logn) implementation of byteswap.
|
||||
func byteswap_logn(a: UInt64) -> UInt64 {
|
||||
var a = a
|
||||
a = (a & 0x00000000FFFFFFFF) << 32 | (a & 0xFFFFFFFF00000000) >> 32
|
||||
a = (a & 0x0000FFFF0000FFFF) << 16 | (a & 0xFFFF0000FFFF0000) >> 16
|
||||
a = (a & 0x00FF00FF00FF00FF) << 8 | (a & 0xFF00FF00FF00FF00) >> 8
|
||||
return a
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ByteSwap(N: Int) {
|
||||
for _ in 1...100*N {
|
||||
// Check some results.
|
||||
CheckResults(byteswap_logn(byteswap_n(2457)) == 2457, "Incorrect results in ByteSwap.")
|
||||
CheckResults(byteswap_logn(byteswap_n(9129)) == 9129, "Incorrect results in ByteSwap.")
|
||||
CheckResults(byteswap_logn(byteswap_n(3333)) == 3333, "Incorrect results in ByteSwap.")
|
||||
}
|
||||
}
|
||||
41
benchmark/single-source/Calculator.swift
Normal file
41
benchmark/single-source/Calculator.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//===--- Calculator.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
@inline(never)
|
||||
func my_atoi_impl(input : String) -> Int {
|
||||
switch input {
|
||||
case "0": return 0
|
||||
case "1": return 1
|
||||
case "2": return 2
|
||||
case "3": return 3
|
||||
case "4": return 4
|
||||
case "5": return 5
|
||||
case "6": return 6
|
||||
case "7": return 7
|
||||
case "8": return 8
|
||||
case "9": return 9
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Calculator(N: Int) {
|
||||
var c = 0
|
||||
for _ in 1...N*5000 {
|
||||
c += my_atoi_impl("10")
|
||||
}
|
||||
CheckResults(c == 0, "IncorrectResults in run_Calculator")
|
||||
}
|
||||
|
||||
32
benchmark/single-source/CaptureProp.swift
Normal file
32
benchmark/single-source/CaptureProp.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
//===--- CaptureProp.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
func sum(x:Int, y:Int) -> Int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func benchCaptureProp<S : Sequence
|
||||
>(
|
||||
s:S, _ f:(S.Iterator.Element, S.Iterator.Element)->S.Iterator.Element) -> S.Iterator.Element {
|
||||
|
||||
var it = s.iterator()
|
||||
let initial = it.next()!
|
||||
return IteratorSequence(it).reduce(initial, combine: f)
|
||||
}
|
||||
|
||||
public func run_CaptureProp(N: Int) {
|
||||
let a = 1...10_000
|
||||
for _ in 1...100*N {
|
||||
benchCaptureProp(a, sum)
|
||||
}
|
||||
}
|
||||
37
benchmark/single-source/Chars.swift
Normal file
37
benchmark/single-source/Chars.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//===--- Chars.swift ------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test tests the performance of ASCII Character comparison.
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_Chars(N: Int) {
|
||||
// Permute some characters.
|
||||
let alphabet: [Character] = [
|
||||
"A", "B", "C", "D", "E", "F", "G",
|
||||
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
|
||||
"S", "T", "U",
|
||||
"V", "W", "X", "Y", "Z", "/", "f", "Z", "z", "6", "7", "C", "j", "f", "9",
|
||||
"g", "g", "I", "J", "K", "c", "x", "i", ".",
|
||||
"2", "a", "t", "i", "o", "e", "q", "n", "X", "Y", "Z", "?", "m", "Z", ","
|
||||
]
|
||||
|
||||
for _ in 0...N {
|
||||
for firstChar in alphabet {
|
||||
for middleChar in alphabet {
|
||||
for lastChar in alphabet {
|
||||
_ = ((firstChar == middleChar) != (middleChar < lastChar))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
benchmark/single-source/ClassArrayGetter.swift
Normal file
37
benchmark/single-source/ClassArrayGetter.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//===--- ClassArrayGetter.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class Box {
|
||||
var v: Int
|
||||
init(v: Int) { self.v = v }
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func sumArray(a: [Box]) -> Int {
|
||||
var s = 0
|
||||
for i in 0..<a.count {
|
||||
s += a[i].v
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
public func run_ClassArrayGetter(N: Int) {
|
||||
let aSize = 10_000
|
||||
var a: [Box] = []
|
||||
a.reserveCapacity(aSize)
|
||||
for i in 1...aSize {
|
||||
a.append(Box(v:i))
|
||||
}
|
||||
for _ in 1...N {
|
||||
sumArray(a)
|
||||
}
|
||||
}
|
||||
39
benchmark/single-source/DeadArray.swift
Normal file
39
benchmark/single-source/DeadArray.swift
Normal file
@@ -0,0 +1,39 @@
|
||||
//===--- DeadArray.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// rdar://problem/20980377
|
||||
import TestsUtils
|
||||
|
||||
@inline(__always)
|
||||
func debug(m:String) {}
|
||||
|
||||
private var Count = 0
|
||||
|
||||
@inline(never)
|
||||
func bar() { Count += 1 }
|
||||
|
||||
@inline(never)
|
||||
func runLoop(var1: Int, var2: Int) {
|
||||
for _ in 0..<100_000 {
|
||||
debug("Var1: \(var1) Var2: \(var2)")
|
||||
bar()
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_DeadArray(N: Int) {
|
||||
for _ in 1...N {
|
||||
Count = 0
|
||||
runLoop(0, var2: 0)
|
||||
}
|
||||
CheckResults(Count == 100_000, "Incorrect number of calls in loop")
|
||||
}
|
||||
147
benchmark/single-source/DictTest.swift
Normal file
147
benchmark/single-source/DictTest.swift
Normal file
@@ -0,0 +1,147 @@
|
||||
//===--- DictTest.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_Dictionary(scale: Int) {
|
||||
let Input = [
|
||||
// Text from http://en.wikipedia.org/wiki/Hash_table
|
||||
"hash", "table",
|
||||
"in", "computing", "a", "hash", "table", "also", "hash", "map", "is",
|
||||
"a", "data", "structure", "used", "to", "implement", "an", "associative",
|
||||
"array", "a", "structure", "that", "can", "map", "keys", "to", "values",
|
||||
"a", "hash", "table", "uses", "a", "hash", "function", "to", "compute",
|
||||
"an", "index", "into", "an", "array", "of", "buckets", "or", "slots",
|
||||
"from", "which", "the", "correct", "value", "can", "be", "found",
|
||||
"ideally", "the", "hash", "function", "will", "assign", "each", "key",
|
||||
"to", "a", "unique", "bucket", "but", "this", "situation", "is",
|
||||
"rarely", "achievable", "in", "practice", "usually", "some", "keys",
|
||||
"will", "hash", "to", "the", "same", "bucket", "instead", "most", "hash",
|
||||
"table", "designs", "assume", "that", "hash", "collisions", "different",
|
||||
"keys", "that", "are", "assigned", "by", "the", "hash", "function", "to",
|
||||
"the", "same", "bucket", "will", "occur", "and", "must", "be",
|
||||
"accommodated", "in", "some", "way", "in", "a", "well", "dimensioned",
|
||||
"hash", "table", "the", "average", "cost", "number", "of",
|
||||
"instructions", "for", "each", "lookup", "is", "independent", "of",
|
||||
"the", "number", "of", "elements", "stored", "in", "the", "table",
|
||||
"many", "hash", "table", "designs", "also", "allow", "arbitrary",
|
||||
"insertions", "and", "deletions", "of", "key", "value", "pairs", "at",
|
||||
"amortized", "constant", "average", "cost", "per", "operation", "in",
|
||||
"many", "situations", "hash", "tables", "turn", "out", "to", "be",
|
||||
"more", "efficient", "than", "search", "trees", "or", "any", "other",
|
||||
"table", "lookup", "structure", "for", "this", "reason", "they", "are",
|
||||
"widely", "used", "in", "many", "kinds", "of", "computer", "software",
|
||||
"particularly", "for", "associative", "arrays", "database", "indexing",
|
||||
"caches", "and", "sets",
|
||||
|
||||
"hashing",
|
||||
"the", "idea", "of", "hashing", "is", "to", "distribute", "the",
|
||||
"entries", "key", "value", "pairs", "across", "an", "array", "of",
|
||||
"buckets", "given", "a", "key", "the", "algorithm", "computes", "an",
|
||||
"index", "that", "suggests", "where", "the", "entry", "can", "be",
|
||||
"found", "index", "f", "key", "array", "size", "often", "this", "is",
|
||||
"done", "in", "two", "steps", "hash", "hashfunc", "key", "index", "hash",
|
||||
"array", "size", "in", "this", "method", "the", "hash", "is",
|
||||
"independent", "of", "the", "array", "size", "and", "it", "is", "then",
|
||||
"reduced", "to", "an", "index", "a", "number", "between", "and", "array",
|
||||
"size", "using", "the", "modulus", "operator", "in", "the", "case",
|
||||
"that", "the", "array", "size", "is", "a", "power", "of", "two", "the",
|
||||
"remainder", "operation", "is", "reduced", "to", "masking", "which",
|
||||
"improves", "speed", "but", "can", "increase", "problems", "with", "a",
|
||||
"poor", "hash", "function",
|
||||
|
||||
"choosing", "a", "good", "hash", "function",
|
||||
"a", "good", "hash", "function", "and", "implementation", "algorithm",
|
||||
"are", "essential", "for", "good", "hash", "table", "performance", "but",
|
||||
"may", "be", "difficult", "to", "achieve", "a", "basic", "requirement",
|
||||
"is", "that", "the", "function", "should", "provide", "a", "uniform",
|
||||
"distribution", "of", "hash", "values", "a", "non", "uniform",
|
||||
"distribution", "increases", "the", "number", "of", "collisions", "and",
|
||||
"the", "cost", "of", "resolving", "them", "uniformity", "is",
|
||||
"sometimes", "difficult", "to", "ensure", "by", "design", "but", "may",
|
||||
"be", "evaluated", "empirically", "using", "statistical", "tests", "e",
|
||||
"g", "a", "pearson", "s", "chi", "squared", "test", "for", "discrete",
|
||||
"uniform", "distributions", "the", "distribution", "needs", "to", "be",
|
||||
"uniform", "only", "for", "table", "sizes", "that", "occur", "in", "the",
|
||||
"application", "in", "particular", "if", "one", "uses", "dynamic",
|
||||
"resizing", "with", "exact", "doubling", "and", "halving", "of", "the",
|
||||
"table", "size", "s", "then", "the", "hash", "function", "needs", "to",
|
||||
"be", "uniform", "only", "when", "s", "is", "a", "power", "of", "two",
|
||||
"on", "the", "other", "hand", "some", "hashing", "algorithms", "provide",
|
||||
"uniform", "hashes", "only", "when", "s", "is", "a", "prime", "number",
|
||||
"for", "open", "addressing", "schemes", "the", "hash", "function",
|
||||
"should", "also", "avoid", "clustering", "the", "mapping", "of", "two",
|
||||
"or", "more", "keys", "to", "consecutive", "slots", "such", "clustering",
|
||||
"may", "cause", "the", "lookup", "cost", "to", "skyrocket", "even", "if",
|
||||
"the", "load", "factor", "is", "low", "and", "collisions", "are",
|
||||
"infrequent", "the", "popular", "multiplicative", "hash", "3", "is",
|
||||
"claimed", "to", "have", "particularly", "poor", "clustering",
|
||||
"behavior", "cryptographic", "hash", "functions", "are", "believed",
|
||||
"to", "provide", "good", "hash", "functions", "for", "any", "table",
|
||||
"size", "s", "either", "by", "modulo", "reduction", "or", "by", "bit",
|
||||
"masking", "they", "may", "also", "be", "appropriate", "if", "there",
|
||||
"is", "a", "risk", "of", "malicious", "users", "trying", "to",
|
||||
"sabotage", "a", "network", "service", "by", "submitting", "requests",
|
||||
"designed", "to", "generate", "a", "large", "number", "of", "collisions",
|
||||
"in", "the", "server", "s", "hash", "tables", "however", "the", "risk",
|
||||
"of", "sabotage", "can", "also", "be", "avoided", "by", "cheaper",
|
||||
"methods", "such", "as", "applying", "a", "secret", "salt", "to", "the",
|
||||
"data", "or", "using", "a", "universal", "hash", "function",
|
||||
|
||||
"perfect", "hash", "function",
|
||||
"if", "all", "keys", "are", "known", "ahead", "of", "time", "a",
|
||||
"perfect", "hash", "function", "can", "be", "used", "to", "create", "a",
|
||||
"perfect", "hash", "table", "that", "has", "no", "collisions", "if",
|
||||
"minimal", "perfect", "hashing", "is", "used", "every", "location", "in",
|
||||
"the", "hash", "table", "can", "be", "used", "as", "well", "perfect",
|
||||
"hashing", "allows", "for", "constant", "time", "lookups", "in", "the",
|
||||
"worst", "case", "this", "is", "in", "contrast", "to", "most",
|
||||
"chaining", "and", "open", "addressing", "methods", "where", "the",
|
||||
"time", "for", "lookup", "is", "low", "on", "average", "but", "may",
|
||||
"be", "very", "large", "proportional", "to", "the", "number", "of",
|
||||
"entries", "for", "some", "sets", "of", "keys"
|
||||
]
|
||||
|
||||
var Dict: Dictionary<String, Bool> = [:]
|
||||
let N = 5*scale
|
||||
|
||||
// Check performance of filling the dictionary:
|
||||
for _ in 1...N {
|
||||
Dict = [:]
|
||||
for word in Input {
|
||||
Dict[word] = true;
|
||||
}
|
||||
}
|
||||
CheckResults(Dict.count == 270,
|
||||
"IncorrectResults in DictTest: \(Dict.count) != 270.")
|
||||
|
||||
// Check performance of searching in the dictionary:
|
||||
// Fill the dictionary with words from the first half of the text
|
||||
Dict = [:]
|
||||
for i in 0 ..< Input.count/2 {
|
||||
let word = Input[i]
|
||||
Dict[word] = true
|
||||
}
|
||||
|
||||
// Count number of words from the first half in the entire text
|
||||
var count = 0
|
||||
for _ in 1...N {
|
||||
for word in Input {
|
||||
if Dict[word] != nil {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckResults(count == N*541,
|
||||
"IncorrectResults in DictTest: \(count) != \(N*541).")
|
||||
}
|
||||
38
benchmark/single-source/DictTest2.swift
Normal file
38
benchmark/single-source/DictTest2.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//===--- DictTest2.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_Dictionary2(N: Int) {
|
||||
let size = 500
|
||||
let ref_result = 199
|
||||
var res = 0
|
||||
for _ in 1...5*N {
|
||||
var x: [String:Int] = [:]
|
||||
for i in 1...size {
|
||||
x[String(i, radix:16)] = i
|
||||
}
|
||||
|
||||
res = 0
|
||||
for i in 0..<size {
|
||||
let i2 = size-i
|
||||
if x[String(i2)] != nil {
|
||||
res += 1
|
||||
}
|
||||
}
|
||||
if res != ref_result {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(res == ref_result, "Incorrect results in Dictionary2: \(res) != \(ref_result)")
|
||||
}
|
||||
45
benchmark/single-source/DictTest3.swift
Normal file
45
benchmark/single-source/DictTest3.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
//===--- DictTest3.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_Dictionary3(N: Int) {
|
||||
let size1 = 100
|
||||
let reps = 20
|
||||
let ref_result = "1 99 20 1980"
|
||||
var hash1 = [String:Int]()
|
||||
var hash2 = [String:Int]()
|
||||
var res = ""
|
||||
|
||||
for _ in 1...N {
|
||||
hash1 = [:]
|
||||
for i in 0..<size1 {
|
||||
hash1["foo_" + String(i)] = i
|
||||
}
|
||||
|
||||
hash2 = hash1
|
||||
|
||||
for _ in 1..<reps {
|
||||
for (k, v) in hash1 {
|
||||
hash2[k] = hash2[k]! + v
|
||||
}
|
||||
}
|
||||
|
||||
res = (String(hash1["foo_1"]!) + " " + String(hash1["foo_99"]!) + " " +
|
||||
String(hash2["foo_1"]!) + " " + String(hash2["foo_99"]!))
|
||||
if res != ref_result {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(res == ref_result, "Incorrect results in Dictionary3: \(res) != \(ref_result)")
|
||||
}
|
||||
59
benchmark/single-source/DictionaryBridge.swift
Normal file
59
benchmark/single-source/DictionaryBridge.swift
Normal file
@@ -0,0 +1,59 @@
|
||||
//===--- DictionaryBridge.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// benchmark to test the performance of bridging an NSDictionary to a
|
||||
// Swift.Dictionary.
|
||||
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
class Thing : NSObject {
|
||||
|
||||
required override init() {
|
||||
let c = self.dynamicType.col()
|
||||
CheckResults(c!.count == 10, "The rules of the universe apply")
|
||||
}
|
||||
|
||||
private class func col() -> [String : AnyObject]? {
|
||||
let dict = NSMutableDictionary()
|
||||
dict.setValue(1, forKey: "one")
|
||||
dict.setValue(2, forKey: "two")
|
||||
dict.setValue(3, forKey: "three")
|
||||
dict.setValue(4, forKey: "four")
|
||||
dict.setValue(5, forKey: "five")
|
||||
dict.setValue(6, forKey: "six")
|
||||
dict.setValue(7, forKey: "seven")
|
||||
dict.setValue(8, forKey: "eight")
|
||||
dict.setValue(9, forKey: "nine")
|
||||
dict.setValue(10, forKey: "ten")
|
||||
|
||||
return NSDictionary(dictionary: dict) as? [String: AnyObject]
|
||||
}
|
||||
|
||||
class func mk() -> Thing {
|
||||
return self.init()
|
||||
}
|
||||
}
|
||||
|
||||
class Stuff {
|
||||
var c : Thing = Thing.mk()
|
||||
init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_DictionaryBridge(N: Int) {
|
||||
for _ in 1...100*N {
|
||||
_ = Stuff()
|
||||
}
|
||||
}
|
||||
27
benchmark/single-source/DictionaryLiteral.swift
Normal file
27
benchmark/single-source/DictionaryLiteral.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//===--- DictionaryLiteral.swift ------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Dictionary creation from literals benchmark
|
||||
// rdar://problem/19804127
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
func makeDictionary() -> [Int: Int] {
|
||||
return [1: 3, 2: 2, 3: 1]
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_DictionaryLiteral(N: Int) {
|
||||
for _ in 1...10000*N {
|
||||
makeDictionary()
|
||||
}
|
||||
}
|
||||
43
benchmark/single-source/DictionaryRemove.swift
Normal file
43
benchmark/single-source/DictionaryRemove.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//===--- DictionaryRemove.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Dictionary element removal benchmark
|
||||
// rdar://problem/19804127
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_DictionaryRemove(N: Int) {
|
||||
let size = 100
|
||||
var dict = [Int: Int](minimumCapacity: size)
|
||||
|
||||
// Fill dictionary
|
||||
for i in 1...size {
|
||||
dict[i] = i
|
||||
}
|
||||
CheckResults(dict.count == size,
|
||||
"Incorrect dict count: \(dict.count) != \(size).")
|
||||
|
||||
var tmpDict = dict
|
||||
for _ in 1...1000*N {
|
||||
tmpDict = dict
|
||||
// Empty dictionary
|
||||
for i in 1...size {
|
||||
tmpDict.removeValueForKey(i)
|
||||
}
|
||||
if !tmpDict.isEmpty {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
CheckResults(tmpDict.isEmpty,
|
||||
"tmpDict should be empty: \(tmpDict.count) != 0.")
|
||||
}
|
||||
46
benchmark/single-source/DictionarySwap.swift
Normal file
46
benchmark/single-source/DictionarySwap.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//===--- DictionarySwap.swift ---------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Dictionary element swapping benchmark
|
||||
// rdar://problem/19804127
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_DictionarySwap(N: Int) {
|
||||
let size = 100
|
||||
var dict = [Int: Int](minimumCapacity: size)
|
||||
|
||||
// Fill dictionary
|
||||
for i in 1...size {
|
||||
dict[i] = i
|
||||
}
|
||||
CheckResults(dict.count == size,
|
||||
"Incorrect dict count: \(dict.count) != \(size).")
|
||||
|
||||
var swapped = false
|
||||
for _ in 1...10000*N {
|
||||
swap(&dict[25]!, &dict[75]!)
|
||||
swapped = !swapped
|
||||
if !swappedCorrectly(swapped, dict[25]!, dict[75]!) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
CheckResults(swappedCorrectly(swapped, dict[25]!, dict[75]!),
|
||||
"Dictionary value swap failed")
|
||||
}
|
||||
|
||||
// Return true if correctly swapped, false otherwise
|
||||
func swappedCorrectly(swapped: Bool, _ p25: Int, _ p75: Int) -> Bool {
|
||||
return swapped && (p25 == 75 && p75 == 25) ||
|
||||
!swapped && (p25 == 25 && p75 == 75)
|
||||
}
|
||||
41
benchmark/single-source/ErrorHandling.swift
Normal file
41
benchmark/single-source/ErrorHandling.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//===--- ErrorHandling.swift ----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
enum PizzaError : ErrorProtocol {
|
||||
case Pepperoni, Olives, Anchovy
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func doSomething() throws -> String {
|
||||
var sb = "pi"
|
||||
for str in ["z","z","a","?","?","?"] {
|
||||
sb += str
|
||||
if sb == "pizza" {
|
||||
throw PizzaError.Anchovy
|
||||
}
|
||||
}
|
||||
return sb
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ErrorHandling(N: Int) {
|
||||
for _ in 1...5000*N {
|
||||
do {
|
||||
try doSomething()
|
||||
} catch _ {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
43
benchmark/single-source/Fibonacci.swift
Normal file
43
benchmark/single-source/Fibonacci.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
//===--- Fibonacci.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
func fibonacci(n: Int) -> Int {
|
||||
if (n < 2) { return 1 }
|
||||
return fibonacci(n - 2) + fibonacci(n - 1)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func Fibonacci(n: Int) -> Int {
|
||||
// This if prevents optimizer from computing return value of Fibonacci(32)
|
||||
// at compile time.
|
||||
if False() { return 0 }
|
||||
|
||||
if (n < 2) { return 1 }
|
||||
return fibonacci(n - 2) + fibonacci(n - 1)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Fibonacci(N: Int) {
|
||||
let n = 32
|
||||
let ref_result = 3524578
|
||||
var result = 0
|
||||
for _ in 1...N {
|
||||
result = Fibonacci(n)
|
||||
if result != ref_result {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(result == ref_result,
|
||||
"Incorrect results in Fibonacci: \(result) != \(ref_result)")
|
||||
}
|
||||
33
benchmark/single-source/GlobalClass.swift
Normal file
33
benchmark/single-source/GlobalClass.swift
Normal file
@@ -0,0 +1,33 @@
|
||||
//===--- GlobalClass.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Test inline cache with a global class. Make sure the retain|release pair
|
||||
// for the fast path is removed in the loop.
|
||||
import TestsUtils
|
||||
|
||||
class A
|
||||
{
|
||||
func f(a : Int) -> Int
|
||||
{
|
||||
return a + 1
|
||||
}
|
||||
}
|
||||
|
||||
var x = 0
|
||||
var a = A()
|
||||
@inline(never)
|
||||
public func run_GlobalClass(N: Int) {
|
||||
for _ in 0..<N
|
||||
{
|
||||
x = a.f(x)
|
||||
}
|
||||
}
|
||||
48
benchmark/single-source/Hanoi.swift
Normal file
48
benchmark/single-source/Hanoi.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//===--- Hanoi.swift ------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of Swift hanoi tower.
|
||||
// <rdar://problem/22151932>
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
struct Move {
|
||||
var from: String
|
||||
var to : String
|
||||
init(from:String, to:String) {
|
||||
self.from = from
|
||||
self.to = to
|
||||
}
|
||||
}
|
||||
|
||||
class TowersOfHanoi {
|
||||
// Record all moves made.
|
||||
var moves : [Move] = [Move]()
|
||||
|
||||
func solve(n: Int, start: String, auxiliary: String, end: String) {
|
||||
if (n == 1) {
|
||||
moves.append(Move(from:start, to:end))
|
||||
} else {
|
||||
solve(n - 1, start: start, auxiliary: end, end: auxiliary)
|
||||
moves.append(Move(from:start, to:end))
|
||||
solve(n - 1, start: auxiliary, auxiliary: start, end: end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Hanoi(N: Int) {
|
||||
for _ in 1...100*N {
|
||||
let hanoi: TowersOfHanoi = TowersOfHanoi()
|
||||
hanoi.solve(10, start: "A", auxiliary: "B", end: "C")
|
||||
}
|
||||
}
|
||||
682
benchmark/single-source/Hash.swift
Normal file
682
benchmark/single-source/Hash.swift
Normal file
@@ -0,0 +1,682 @@
|
||||
//===--- Hash.swift -------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Derived from the C samples in:
|
||||
// Source: http://en.wikipedia.org/wiki/MD5 and
|
||||
// http://en.wikipedia.org/wiki/SHA-1
|
||||
import TestsUtils
|
||||
|
||||
class Hash {
|
||||
/// \brief C'tor.
|
||||
init(_ bs: Int) {
|
||||
blocksize = bs
|
||||
messageLength = 0
|
||||
dataLength = 0
|
||||
assert(blocksize <= 64, "Invalid block size")
|
||||
}
|
||||
|
||||
/// \brief Add the bytes in \p Msg to the hash.
|
||||
func update(Msg: String) {
|
||||
for c in Msg.unicodeScalars {
|
||||
data[dataLength] = UInt8(ascii: c)
|
||||
dataLength += 1
|
||||
messageLength += 1
|
||||
if dataLength == blocksize { hash() }
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Add the bytes in \p Msg to the hash.
|
||||
func update(Msg: [UInt8]) {
|
||||
for c in Msg {
|
||||
data[dataLength] = c
|
||||
dataLength += 1
|
||||
messageLength += 1
|
||||
if dataLength == blocksize { hash() }
|
||||
}
|
||||
}
|
||||
|
||||
/// \returns the hash of the data that was updated.
|
||||
func digest() -> String {
|
||||
fillBlock()
|
||||
hash()
|
||||
let x = hashState()
|
||||
return x
|
||||
}
|
||||
|
||||
func digestFast(inout Res : [UInt8]) {
|
||||
fillBlock()
|
||||
hash()
|
||||
// We use [UInt8] to avoid using String::apend.
|
||||
hashStateFast(&Res)
|
||||
}
|
||||
|
||||
// private:
|
||||
|
||||
// Hash state:
|
||||
final var messageLength : Int = 0
|
||||
final var dataLength : Int = 0
|
||||
final var data = [UInt8](repeating: 0, count: 64)
|
||||
final var blocksize : Int
|
||||
|
||||
/// \brief Hash the internal data.
|
||||
func hash() {
|
||||
fatalError("Pure virtual")
|
||||
}
|
||||
|
||||
/// \returns a string representation of the state.
|
||||
func hashState() -> String {
|
||||
fatalError("Pure virtual")
|
||||
}
|
||||
func hashStateFast(inout Res : [UInt8]) {
|
||||
fatalError("Pure virtual")
|
||||
}
|
||||
|
||||
/// \brief Blow the data to fill the block.
|
||||
func fillBlock() {
|
||||
fatalError("Pure virtual")
|
||||
}
|
||||
|
||||
var HexTbl = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"]
|
||||
final
|
||||
var HexTblFast : [UInt8] = [48,49,50,51,52,53,54,55,56,57,97,98,99,100,101,102]
|
||||
|
||||
/// \brief Convert a 4-byte integer to a hex string.
|
||||
final
|
||||
func toHex(In: UInt32) -> String {
|
||||
var In = In
|
||||
var Res = ""
|
||||
for _ in 0..<8 {
|
||||
Res = HexTbl[Int(In & 0xF)] + Res
|
||||
In = In >> 4
|
||||
}
|
||||
return Res
|
||||
}
|
||||
|
||||
final
|
||||
func toHexFast(In: UInt32, inout _ Res: Array<UInt8>, _ Index : Int) {
|
||||
var In = In
|
||||
for i in 0..<4 {
|
||||
// Convert one byte each iteration.
|
||||
Res[Index + 2*i] = HexTblFast[Int(In >> 4) & 0xF]
|
||||
Res[Index + 2*i + 1] = HexTblFast[Int(In & 0xF)]
|
||||
In = In >> 8
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Left-rotate \p x by \p c.
|
||||
final
|
||||
func rol(x: UInt32, _ c: UInt32) -> UInt32 {
|
||||
// TODO: use the &>> operator.
|
||||
let a = UInt32(truncatingBitPattern: Int64(x) << Int64(c))
|
||||
let b = UInt32(truncatingBitPattern: Int64(x) >> (32 - Int64(c)))
|
||||
return a|b
|
||||
}
|
||||
|
||||
/// \brief Right-rotate \p x by \p c.
|
||||
final
|
||||
func ror(x: UInt32, _ c: UInt32) -> UInt32 {
|
||||
// TODO: use the &>> operator.
|
||||
let a = UInt32(truncatingBitPattern: Int64(x) >> Int64(c))
|
||||
let b = UInt32(truncatingBitPattern: Int64(x) << (32 - Int64(c)))
|
||||
return a|b
|
||||
}
|
||||
}
|
||||
|
||||
final
|
||||
class MD5 : Hash {
|
||||
// Integer part of the sines of integers (in radians) * 2^32.
|
||||
var k : [UInt32] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 ]
|
||||
|
||||
// Per-round shift amounts
|
||||
var r : [UInt32] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
|
||||
|
||||
// State
|
||||
var h0 : UInt32 = 0
|
||||
var h1 : UInt32 = 0
|
||||
var h2 : UInt32 = 0
|
||||
var h3 : UInt32 = 0
|
||||
|
||||
init() {
|
||||
super.init(64)
|
||||
reset()
|
||||
}
|
||||
|
||||
func reset() {
|
||||
// Set the initial values.
|
||||
h0 = 0x67452301
|
||||
h1 = 0xefcdab89
|
||||
h2 = 0x98badcfe
|
||||
h3 = 0x10325476
|
||||
messageLength = 0
|
||||
dataLength = 0
|
||||
}
|
||||
|
||||
func appendBytes(Val: Int, inout _ Message: Array<UInt8>, _ Offset : Int) {
|
||||
Message[Offset] = UInt8(truncatingBitPattern: Val)
|
||||
Message[Offset + 1] = UInt8(truncatingBitPattern: Val >> 8)
|
||||
Message[Offset + 2] = UInt8(truncatingBitPattern: Val >> 16)
|
||||
Message[Offset + 3] = UInt8(truncatingBitPattern: Val >> 24)
|
||||
}
|
||||
|
||||
override
|
||||
func fillBlock() {
|
||||
// Pre-processing:
|
||||
// Append "1" bit to message
|
||||
// Append "0" bits until message length in bits -> 448 (mod 512)
|
||||
// Append length mod (2^64) to message
|
||||
|
||||
var new_len = messageLength + 1
|
||||
while (new_len % (512/8) != 448/8) {
|
||||
new_len += 1
|
||||
}
|
||||
|
||||
// Append the "1" bit - most significant bit is "first"
|
||||
data[dataLength] = UInt8(0x80)
|
||||
dataLength += 1
|
||||
|
||||
// Append "0" bits
|
||||
for _ in 0..<(new_len - (messageLength + 1)) {
|
||||
if dataLength == blocksize { hash() }
|
||||
data[dataLength] = UInt8(0)
|
||||
dataLength += 1
|
||||
}
|
||||
|
||||
// Append the len in bits at the end of the buffer.
|
||||
// initial_len>>29 == initial_len*8>>32, but avoids overflow.
|
||||
appendBytes(messageLength * 8, &data, dataLength)
|
||||
appendBytes(messageLength>>29 * 8, &data, dataLength+4)
|
||||
dataLength += 8
|
||||
}
|
||||
|
||||
func toUInt32(Message: Array<UInt8>, _ Offset: Int) -> UInt32 {
|
||||
let first = UInt32(Message[Offset + 0])
|
||||
let second = UInt32(Message[Offset + 1]) << 8
|
||||
let third = UInt32(Message[Offset + 2]) << 16
|
||||
let fourth = UInt32(Message[Offset + 3]) << 24
|
||||
return first | second | third | fourth
|
||||
}
|
||||
|
||||
var w = [UInt32](repeating: 0, count: 16)
|
||||
override
|
||||
func hash() {
|
||||
assert(dataLength == blocksize, "Invalid block size")
|
||||
|
||||
// Break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
|
||||
for i in 0..<16 {
|
||||
w[i] = toUInt32(data, i*4)
|
||||
}
|
||||
|
||||
// We don't need the original data anymore.
|
||||
dataLength = 0
|
||||
|
||||
var a = h0
|
||||
var b = h1
|
||||
var c = h2
|
||||
var d = h3
|
||||
var f, g : UInt32
|
||||
|
||||
// Main loop:
|
||||
for i in 0..<64 {
|
||||
if i < 16 {
|
||||
f = (b & c) | ((~b) & d)
|
||||
g = UInt32(i)
|
||||
} else if i < 32 {
|
||||
f = (d & b) | ((~d) & c)
|
||||
g = UInt32(5*i + 1) % 16
|
||||
} else if i < 48 {
|
||||
f = b ^ c ^ d
|
||||
g = UInt32(3*i + 5) % 16
|
||||
} else {
|
||||
f = c ^ (b | (~d))
|
||||
g = UInt32(7*i) % 16
|
||||
}
|
||||
|
||||
let temp = d
|
||||
d = c
|
||||
c = b
|
||||
b = b &+ rol(a &+ f &+ k[i] &+ w[Int(g)], r[i])
|
||||
a = temp
|
||||
}
|
||||
|
||||
// Add this chunk's hash to result so far:
|
||||
h0 = a &+ h0
|
||||
h1 = b &+ h1
|
||||
h2 = c &+ h2
|
||||
h3 = d &+ h3
|
||||
}
|
||||
|
||||
func reverseBytes(In: UInt32) -> UInt32 {
|
||||
let B0 = (In >> 0 ) & 0xFF
|
||||
let B1 = (In >> 8 ) & 0xFF
|
||||
let B2 = (In >> 16) & 0xFF
|
||||
let B3 = (In >> 24) & 0xFF
|
||||
return (B0 << 24) | (B1 << 16) | (B2 << 8) | B3
|
||||
}
|
||||
|
||||
override
|
||||
func hashState() -> String {
|
||||
var S = ""
|
||||
for h in [h0, h1, h2, h3] {
|
||||
S += toHex(reverseBytes(h))
|
||||
}
|
||||
return S
|
||||
}
|
||||
|
||||
override
|
||||
func hashStateFast(inout Res : [UInt8]) {
|
||||
#if !NO_RANGE
|
||||
var Idx : Int = 0
|
||||
for h in [h0, h1, h2, h3] {
|
||||
toHexFast(h, &Res, Idx)
|
||||
Idx += 8
|
||||
}
|
||||
#else
|
||||
toHexFast(h0, &Res, 0)
|
||||
toHexFast(h1, &Res, 8)
|
||||
toHexFast(h2, &Res, 16)
|
||||
toHexFast(h3, &Res, 24)
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SHA1 : Hash {
|
||||
// State
|
||||
var h0 : UInt32 = 0
|
||||
var h1 : UInt32 = 0
|
||||
var h2 : UInt32 = 0
|
||||
var h3 : UInt32 = 0
|
||||
var h4 : UInt32 = 0
|
||||
|
||||
init() {
|
||||
super.init(64)
|
||||
reset()
|
||||
}
|
||||
|
||||
func reset() {
|
||||
// Set the initial values.
|
||||
h0 = 0x67452301
|
||||
h1 = 0xEFCDAB89
|
||||
h2 = 0x98BADCFE
|
||||
h3 = 0x10325476
|
||||
h4 = 0xC3D2E1F0
|
||||
messageLength = 0
|
||||
dataLength = 0
|
||||
}
|
||||
|
||||
override
|
||||
func fillBlock() {
|
||||
// Append a 1 to the message.
|
||||
data[dataLength] = UInt8(0x80)
|
||||
dataLength += 1
|
||||
|
||||
var new_len = messageLength + 1
|
||||
while ((new_len % 64) != 56) {
|
||||
new_len += 1
|
||||
}
|
||||
|
||||
for _ in 0..<new_len - (messageLength + 1) {
|
||||
if dataLength == blocksize { hash() }
|
||||
data[dataLength] = UInt8(0x0)
|
||||
dataLength += 1
|
||||
}
|
||||
|
||||
// Append the original message length as 64bit big endian:
|
||||
let len_in_bits = Int64(messageLength)*8
|
||||
for i in 0..<8 {
|
||||
let val = (len_in_bits >> ((7-i)*8)) & 0xFF
|
||||
data[dataLength] = UInt8(val)
|
||||
dataLength += 1
|
||||
}
|
||||
}
|
||||
|
||||
override
|
||||
func hash() {
|
||||
assert(dataLength == blocksize, "Invalid block size")
|
||||
|
||||
// Init the "W" buffer.
|
||||
var w = [UInt32](repeating: 0, count: 80)
|
||||
|
||||
// Convert the Byte array to UInt32 array.
|
||||
var word : UInt32 = 0
|
||||
for i in 0..<64 {
|
||||
word = word << 8
|
||||
word = word &+ UInt32(data[i])
|
||||
if i%4 == 3 { w[i/4] = word; word = 0 }
|
||||
}
|
||||
|
||||
// Init the rest of the "W" buffer.
|
||||
for t in 16..<80 {
|
||||
w[t] = rol((w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]) ,1)
|
||||
}
|
||||
|
||||
dataLength = 0
|
||||
|
||||
var A = h0
|
||||
var B = h1
|
||||
var C = h2
|
||||
var D = h3
|
||||
var E = h4
|
||||
var K : UInt32, F : UInt32
|
||||
|
||||
for t in 0..<80 {
|
||||
if t < 20 {
|
||||
K = 0x5a827999
|
||||
F = (B & C) | ((B ^ 0xFFFFFFFF) & D)
|
||||
} else if t < 40 {
|
||||
K = 0x6ed9eba1
|
||||
F = B ^ C ^ D
|
||||
} else if t < 60 {
|
||||
K = 0x8f1bbcdc
|
||||
F = (B & C) | (B & D) | (C & D)
|
||||
} else {
|
||||
K = 0xca62c1d6
|
||||
F = B ^ C ^ D
|
||||
}
|
||||
let Temp : UInt32 = rol(A,5) &+ F &+ E &+ w[t] &+ K
|
||||
|
||||
E = D
|
||||
D = C
|
||||
C = rol(B,30)
|
||||
B = A
|
||||
A = Temp
|
||||
}
|
||||
|
||||
h0 = h0 &+ A
|
||||
h1 = h1 &+ B
|
||||
h2 = h2 &+ C
|
||||
h3 = h3 &+ D
|
||||
h4 = h4 &+ E
|
||||
}
|
||||
|
||||
override
|
||||
func hashState() -> String {
|
||||
var Res : String = ""
|
||||
for state in [h0, h1, h2, h3, h4] {
|
||||
Res += toHex(state)
|
||||
}
|
||||
return Res
|
||||
}
|
||||
}
|
||||
|
||||
class SHA256 : Hash {
|
||||
// State
|
||||
var h0 : UInt32 = 0
|
||||
var h1 : UInt32 = 0
|
||||
var h2 : UInt32 = 0
|
||||
var h3 : UInt32 = 0
|
||||
var h4 : UInt32 = 0
|
||||
var h5 : UInt32 = 0
|
||||
var h6 : UInt32 = 0
|
||||
var h7 : UInt32 = 0
|
||||
|
||||
var k : [UInt32] = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2]
|
||||
|
||||
init() {
|
||||
super.init(64)
|
||||
reset()
|
||||
}
|
||||
|
||||
func reset() {
|
||||
// Set the initial values.
|
||||
h0 = 0x6a09e667
|
||||
h1 = 0xbb67ae85
|
||||
h2 = 0x3c6ef372
|
||||
h3 = 0xa54ff53a
|
||||
h4 = 0x510e527f
|
||||
h5 = 0x9b05688c
|
||||
h6 = 0x1f83d9ab
|
||||
h7 = 0x5be0cd19
|
||||
messageLength = 0
|
||||
dataLength = 0
|
||||
}
|
||||
|
||||
override
|
||||
func fillBlock() {
|
||||
// Append a 1 to the message.
|
||||
data[dataLength] = UInt8(0x80)
|
||||
dataLength += 1
|
||||
|
||||
var new_len = messageLength + 1
|
||||
while ((new_len % 64) != 56) {
|
||||
new_len += 1
|
||||
}
|
||||
|
||||
for _ in 0..<new_len - (messageLength+1) {
|
||||
if dataLength == blocksize { hash() }
|
||||
data[dataLength] = UInt8(0)
|
||||
dataLength += 1
|
||||
}
|
||||
|
||||
// Append the original message length as 64bit big endian:
|
||||
let len_in_bits = Int64(messageLength)*8
|
||||
for i in 0..<8 {
|
||||
let val = (len_in_bits >> ((7-i)*8)) & 0xFF
|
||||
data[dataLength] = UInt8(val)
|
||||
dataLength += 1
|
||||
}
|
||||
}
|
||||
|
||||
override
|
||||
func hash() {
|
||||
assert(dataLength == blocksize, "Invalid block size")
|
||||
|
||||
// Init the "W" buffer.
|
||||
var w = [UInt32](repeating: 0, count: 64)
|
||||
|
||||
// Convert the Byte array to UInt32 array.
|
||||
var word : UInt32 = 0
|
||||
for i in 0..<64 {
|
||||
word = word << 8
|
||||
word = word &+ UInt32(data[i])
|
||||
if i%4 == 3 { w[i/4] = word; word = 0 }
|
||||
}
|
||||
|
||||
// Init the rest of the "W" buffer.
|
||||
for i in 16..<64 {
|
||||
let s0 = ror(w[i-15], 7) ^ ror(w[i-15], 18) ^ (w[i-15] >> 3)
|
||||
let s1 = ror(w[i-2], 17) ^ ror(w[i-2], 19) ^ (w[i-2] >> 10)
|
||||
w[i] = w[i-16] &+ s0 &+ w[i-7] &+ s1
|
||||
}
|
||||
|
||||
dataLength = 0
|
||||
|
||||
var a = h0
|
||||
var b = h1
|
||||
var c = h2
|
||||
var d = h3
|
||||
var e = h4
|
||||
var f = h5
|
||||
var g = h6
|
||||
var h = h7
|
||||
|
||||
for i in 0..<64 {
|
||||
let S1 = ror(e, 6) ^ ror(e, 11) ^ ror(e, 25)
|
||||
let ch = (e & f) ^ ((~e) & g)
|
||||
let temp1 = h &+ S1 &+ ch &+ k[i] &+ w[i]
|
||||
let S0 = ror(a, 2) ^ ror(a, 13) ^ ror(a, 22)
|
||||
let maj = (a & b) ^ (a & c) ^ (b & c)
|
||||
let temp2 = S0 &+ maj
|
||||
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
e = d &+ temp1
|
||||
d = c
|
||||
c = b
|
||||
b = a
|
||||
a = temp1 &+ temp2
|
||||
}
|
||||
|
||||
h0 = h0 &+ a
|
||||
h1 = h1 &+ b
|
||||
h2 = h2 &+ c
|
||||
h3 = h3 &+ d
|
||||
h4 = h4 &+ e
|
||||
h5 = h5 &+ f
|
||||
h6 = h6 &+ g
|
||||
h7 = h7 &+ h
|
||||
}
|
||||
|
||||
override
|
||||
func hashState() -> String {
|
||||
var Res : String = ""
|
||||
for state in [h0, h1, h2, h3, h4, h5, h6, h7] {
|
||||
Res += toHex(state)
|
||||
}
|
||||
return Res
|
||||
}
|
||||
}
|
||||
|
||||
func == (lhs: [UInt8], rhs: [UInt8]) -> Bool {
|
||||
if lhs.count != rhs.count { return false }
|
||||
for idx in 0..<lhs.count {
|
||||
if lhs[idx] != rhs[idx] { return false }
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_HashTest(N: Int) {
|
||||
let TestMD5 = ["" : "d41d8cd98f00b204e9800998ecf8427e",
|
||||
"The quick brown fox jumps over the lazy dog." : "e4d909c290d0fb1ca068ffaddf22cbd0",
|
||||
"The quick brown fox jumps over the lazy cog." : "68aa5deab43e4df2b5e1f80190477fb0"]
|
||||
|
||||
let TestSHA1 = ["" : "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
"The quick brown fox jumps over the lazy dog" : "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
||||
"The quick brown fox jumps over the lazy cog" : "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3"]
|
||||
|
||||
let TestSHA256 = ["" : "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"The quick brown fox jumps over the lazy dog" : "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
|
||||
"The quick brown fox jumps over the lazy dog." : "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c"]
|
||||
let size = 50
|
||||
|
||||
for _ in 1...10*N {
|
||||
// Check for precomputed values.
|
||||
let MD = MD5()
|
||||
for (K, V) in TestMD5 {
|
||||
MD.update(K)
|
||||
CheckResults(MD.digest() == V,
|
||||
"Incorrect result in Hash: check 1 failed.")
|
||||
MD.reset()
|
||||
}
|
||||
|
||||
// Check that we don't crash on large strings.
|
||||
var S : String = ""
|
||||
for _ in 1...size {
|
||||
S += "a"
|
||||
MD.reset()
|
||||
MD.update(S)
|
||||
}
|
||||
|
||||
// Check that the order in which we push values does not change the result.
|
||||
MD.reset()
|
||||
var L : String = ""
|
||||
for _ in 1...size {
|
||||
L += "a"
|
||||
MD.update("a")
|
||||
}
|
||||
let MD2 = MD5()
|
||||
MD2.update(L)
|
||||
CheckResults(MD.digest() == MD2.digest(),
|
||||
"Incorrect result in Hash: check 2 failed.")
|
||||
|
||||
// Test the famous MD5 collision from 2009: http://www.mscs.dal.ca/~selinger/md5collision/
|
||||
let Src1 : [UInt8] =
|
||||
[0xd1, 0x31, 0xdd, 0x02, 0xc5, 0xe6, 0xee, 0xc4, 0x69, 0x3d, 0x9a, 0x06, 0x98, 0xaf, 0xf9, 0x5c, 0x2f, 0xca, 0xb5, 0x87, 0x12, 0x46, 0x7e, 0xab, 0x40, 0x04, 0x58, 0x3e, 0xb8, 0xfb, 0x7f, 0x89,
|
||||
0x55, 0xad, 0x34, 0x06, 0x09, 0xf4, 0xb3, 0x02, 0x83, 0xe4, 0x88, 0x83, 0x25, 0x71, 0x41, 0x5a, 0x08, 0x51, 0x25, 0xe8, 0xf7, 0xcd, 0xc9, 0x9f, 0xd9, 0x1d, 0xbd, 0xf2, 0x80, 0x37, 0x3c, 0x5b,
|
||||
0xd8, 0x82, 0x3e, 0x31, 0x56, 0x34, 0x8f, 0x5b, 0xae, 0x6d, 0xac, 0xd4, 0x36, 0xc9, 0x19, 0xc6, 0xdd, 0x53, 0xe2, 0xb4, 0x87, 0xda, 0x03, 0xfd, 0x02, 0x39, 0x63, 0x06, 0xd2, 0x48, 0xcd, 0xa0,
|
||||
0xe9, 0x9f, 0x33, 0x42, 0x0f, 0x57, 0x7e, 0xe8, 0xce, 0x54, 0xb6, 0x70, 0x80, 0xa8, 0x0d, 0x1e, 0xc6, 0x98, 0x21, 0xbc, 0xb6, 0xa8, 0x83, 0x93, 0x96, 0xf9, 0x65, 0x2b, 0x6f, 0xf7, 0x2a, 0x70]
|
||||
|
||||
let Src2 : [UInt8] =
|
||||
[0xd1, 0x31, 0xdd, 0x02, 0xc5, 0xe6, 0xee, 0xc4, 0x69, 0x3d, 0x9a, 0x06, 0x98, 0xaf, 0xf9, 0x5c, 0x2f, 0xca, 0xb5, 0x07, 0x12, 0x46, 0x7e, 0xab, 0x40, 0x04, 0x58, 0x3e, 0xb8, 0xfb, 0x7f, 0x89,
|
||||
0x55, 0xad, 0x34, 0x06, 0x09, 0xf4, 0xb3, 0x02, 0x83, 0xe4, 0x88, 0x83, 0x25, 0xf1, 0x41, 0x5a, 0x08, 0x51, 0x25, 0xe8, 0xf7, 0xcd, 0xc9, 0x9f, 0xd9, 0x1d, 0xbd, 0x72, 0x80, 0x37, 0x3c, 0x5b,
|
||||
0xd8, 0x82, 0x3e, 0x31, 0x56, 0x34, 0x8f, 0x5b, 0xae, 0x6d, 0xac, 0xd4, 0x36, 0xc9, 0x19, 0xc6, 0xdd, 0x53, 0xe2, 0x34, 0x87, 0xda, 0x03, 0xfd, 0x02, 0x39, 0x63, 0x06, 0xd2, 0x48, 0xcd, 0xa0,
|
||||
0xe9, 0x9f, 0x33, 0x42, 0x0f, 0x57, 0x7e, 0xe8, 0xce, 0x54, 0xb6, 0x70, 0x80, 0x28, 0x0d, 0x1e, 0xc6, 0x98, 0x21, 0xbc, 0xb6, 0xa8, 0x83, 0x93, 0x96, 0xf9, 0x65, 0xab, 0x6f, 0xf7, 0x2a, 0x70]
|
||||
|
||||
let H1 = MD5()
|
||||
let H2 = MD5()
|
||||
|
||||
H1.update(Src1)
|
||||
H2.update(Src2)
|
||||
let A1 = H1.digest()
|
||||
let A2 = H2.digest()
|
||||
CheckResults(A1 == A2,
|
||||
"Incorrect result in Hash: check 3 failed.")
|
||||
CheckResults(A1 == "79054025255fb1a26e4bc422aef54eb4",
|
||||
"Incorrect result in Hash: check 4 failed.")
|
||||
H1.reset()
|
||||
H2.reset()
|
||||
|
||||
let SH = SHA1()
|
||||
let SH256 = SHA256()
|
||||
for (K, V) in TestSHA1 {
|
||||
SH.update(K)
|
||||
CheckResults(SH.digest() == V,
|
||||
"Incorrect result in Hash: check 5 failed.")
|
||||
SH.reset()
|
||||
}
|
||||
|
||||
for (K, V) in TestSHA256 {
|
||||
SH256.update(K)
|
||||
CheckResults(SH256.digest() == V,
|
||||
"Incorrect result in Hash: check 5 failed.")
|
||||
SH256.reset()
|
||||
}
|
||||
|
||||
// Check that we don't crash on large strings.
|
||||
S = ""
|
||||
for _ in 1...size {
|
||||
S += "a"
|
||||
SH.reset()
|
||||
SH.update(S)
|
||||
}
|
||||
|
||||
// Check that the order in which we push values does not change the result.
|
||||
SH.reset()
|
||||
L = ""
|
||||
for _ in 1...size {
|
||||
L += "a"
|
||||
SH.update("a")
|
||||
}
|
||||
let SH2 = SHA1()
|
||||
SH2.update(L)
|
||||
CheckResults(SH.digest() == SH2.digest(),
|
||||
"Incorrect result in Hash: check 5 failed.")
|
||||
}
|
||||
}
|
||||
114
benchmark/single-source/Histogram.swift
Normal file
114
benchmark/single-source/Histogram.swift
Normal file
@@ -0,0 +1,114 @@
|
||||
//===--- Histogram.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test measures performance of histogram generating.
|
||||
// <rdar://problem/17384894>
|
||||
import TestsUtils
|
||||
|
||||
typealias rrggbb_t = UInt32
|
||||
|
||||
func output_sorted_sparse_rgb_histogram<S: Sequence where S.Iterator.Element == rrggbb_t>(samples: S, _ N: Int) {
|
||||
var histogram = Dictionary<rrggbb_t, Int>()
|
||||
for _ in 1...50*N {
|
||||
for sample in samples { // This part is really awful, I agree
|
||||
let i = histogram.indexForKey(sample)
|
||||
histogram[sample] = (i != nil ? histogram[i!].1 : 0) + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Packed-RGB test data: four gray samples, two red, two blue, and a 4 pixel gradient from black to white
|
||||
let samples: [rrggbb_t] = [
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF
|
||||
]
|
||||
|
||||
@inline(never)
|
||||
public func run_Histogram(N: Int) {
|
||||
output_sorted_sparse_rgb_histogram(samples, N);
|
||||
}
|
||||
24
benchmark/single-source/Join.swift
Normal file
24
benchmark/single-source/Join.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
//===--- Join.swift -------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test tests the performance of ASCII Character comparison.
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_Join(N: Int) {
|
||||
var array: [String] = []
|
||||
for x in 0..<1000 * N {
|
||||
array.append(String(x))
|
||||
}
|
||||
_ = array.joinWithSeparator("")
|
||||
_ = array.joinWithSeparator(" ")
|
||||
}
|
||||
51
benchmark/single-source/LinkedList.swift
Normal file
51
benchmark/single-source/LinkedList.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//===--- LinkedList.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of linked lists. It is based on LinkedList from
|
||||
// utils/benchmark, with modifications for performance measuring.
|
||||
import TestsUtils
|
||||
|
||||
final class Node {
|
||||
var next: Node?
|
||||
var data: Int
|
||||
|
||||
init(n: Node?, d: Int) {
|
||||
next = n
|
||||
data = d
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_LinkedList(N: Int) {
|
||||
let size = 100
|
||||
var head = Node(n:nil, d:0)
|
||||
for i in 0..<size {
|
||||
head = Node(n:head, d:i)
|
||||
}
|
||||
|
||||
var sum = 0
|
||||
let ref_result = size*(size-1)/2
|
||||
var ptr = head
|
||||
for _ in 1...5000*N {
|
||||
ptr = head
|
||||
sum = 0
|
||||
while let nxt = ptr.next {
|
||||
sum += ptr.data
|
||||
ptr = nxt
|
||||
}
|
||||
if sum != ref_result {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(sum == ref_result,
|
||||
"Incorrect results in LinkedList: \(sum) != \(ref_result)")
|
||||
}
|
||||
27
benchmark/single-source/MapReduce.swift
Normal file
27
benchmark/single-source/MapReduce.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//===--- MapReduce.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
@inline(never)
|
||||
public func run_MapReduce(N: Int) {
|
||||
var numbers = [Int](0..<1000)
|
||||
|
||||
var c = 0
|
||||
for _ in 1...N*100 {
|
||||
numbers = numbers.map({$0 &+ 5})
|
||||
c += numbers.reduce(0, combine: &+)
|
||||
}
|
||||
CheckResults(c != 0, "IncorrectResults in MapReduce")
|
||||
}
|
||||
|
||||
30
benchmark/single-source/Memset.swift
Normal file
30
benchmark/single-source/Memset.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//===--- Memset.swift -----------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
func memset(inout a: [Int], _ c: Int) {
|
||||
for i in 0..<a.count {
|
||||
a[i] = c
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Memset(N: Int) {
|
||||
var a = [Int](repeating: 0, count: 10_000)
|
||||
for _ in 1...50*N {
|
||||
memset(&a, 1)
|
||||
memset(&a, 0)
|
||||
}
|
||||
CheckResults(a[87] == 0, "Incorrect result in Memset.")
|
||||
}
|
||||
38
benchmark/single-source/MonteCarloE.swift
Normal file
38
benchmark/single-source/MonteCarloE.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//===--- MonteCarloE.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test measures performance of Monte Carlo estimation of the e constant.
|
||||
//
|
||||
// We use 'dart' method: we split an interval into N pieces and drop N darts
|
||||
// to this interval.
|
||||
// After that we count number of empty intervals. The probability of being
|
||||
// empty is (1 - 1/N)^N which estimates to e^-1 for large N.
|
||||
// Thus, e = N / Nempty.
|
||||
import TestsUtils
|
||||
|
||||
public func run_MonteCarloE(scale: Int) {
|
||||
let N = 200000*scale
|
||||
var intervals = [Bool](repeating: false, count: N)
|
||||
for _ in 1...N {
|
||||
let pos = Int(UInt(truncatingBitPattern: Random())%UInt(N))
|
||||
intervals[pos] = true
|
||||
}
|
||||
let numEmptyIntervals = intervals.filter{!$0}.count
|
||||
// If there are no empty intervals, then obviously the random generator is
|
||||
// not 'random' enough.
|
||||
CheckResults(numEmptyIntervals != N,
|
||||
"Incorrect results in MonteCarloE: no empty intervals.")
|
||||
let e_estimate = Double(N)/Double(numEmptyIntervals)
|
||||
let e = 2.71828
|
||||
CheckResults(Double.abs(e_estimate - e) < 0.1,
|
||||
"Incorrect results in MonteCarloE: e_estimate == \(e_estimate)")
|
||||
}
|
||||
30
benchmark/single-source/MonteCarloPi.swift
Normal file
30
benchmark/single-source/MonteCarloPi.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//===--- MonteCarloPi.swift -----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
public func run_MonteCarloPi(scale: Int) {
|
||||
var pointsInside = 0
|
||||
let r = 10000
|
||||
let N = 500000*scale
|
||||
for _ in 1...N {
|
||||
let x = Int(truncatingBitPattern: Random())%r
|
||||
let y = Int(truncatingBitPattern: Random())%r
|
||||
if x*x + y*y < r*r {
|
||||
pointsInside += 1
|
||||
}
|
||||
}
|
||||
let pi_estimate: Double = Double(pointsInside)*4.0/Double(N)
|
||||
let pi = 3.1415
|
||||
CheckResults(Double.abs(pi_estimate - pi) < 0.1,
|
||||
"Incorrect results in MonteCarloPi: pi_estimate == \(pi_estimate)")
|
||||
}
|
||||
34
benchmark/single-source/NSDictionaryCastToSwift.swift
Normal file
34
benchmark/single-source/NSDictionaryCastToSwift.swift
Normal file
@@ -0,0 +1,34 @@
|
||||
//===--- NSDictionaryCastToSwift.swift ------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Performance benchmark for casting NSDictionary to Swift Dictionary
|
||||
// rdar://problem/18539730
|
||||
//
|
||||
// Description:
|
||||
// Create a NSDictionary instance and cast it to [String: NSObject].
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_NSDictionaryCastToSwift(N: Int) {
|
||||
let NSDict = NSDictionary()
|
||||
var swiftDict = [String: NSObject]()
|
||||
for _ in 1...10000*N {
|
||||
swiftDict = NSDict as! [String: NSObject]
|
||||
if !swiftDict.isEmpty {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(swiftDict.isEmpty,
|
||||
"Incorrect result in swiftDict.isEmpty: " +
|
||||
"\(swiftDict.isEmpty) != true\n")
|
||||
}
|
||||
48
benchmark/single-source/NSError.swift
Normal file
48
benchmark/single-source/NSError.swift
Normal file
@@ -0,0 +1,48 @@
|
||||
//===--- NSError.swift ----------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
protocol P {
|
||||
func buzz() throws -> Int
|
||||
}
|
||||
|
||||
class K : P {
|
||||
init() {}
|
||||
func buzz() throws -> Int {
|
||||
throw NSError(domain: "AnDomain", code: 42, userInfo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
class G : K {
|
||||
override init() {}
|
||||
override func buzz() throws -> Int { return 0 }
|
||||
}
|
||||
|
||||
func caller(x : P) throws {
|
||||
try x.buzz()
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_NSError(N: Int) {
|
||||
for _ in 1...N*1000 {
|
||||
let k = K()
|
||||
let g = G()
|
||||
do {
|
||||
try caller(g)
|
||||
try caller(k)
|
||||
} catch _ {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
22
benchmark/single-source/NSStringConversion.swift
Normal file
22
benchmark/single-source/NSStringConversion.swift
Normal file
@@ -0,0 +1,22 @@
|
||||
//===--- NSStringConversion.swift -----------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <rdar://problem/19003201>
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
public func run_NSStringConversion(N: Int) {
|
||||
let test:NSString = NSString(cString: "test", encoding: NSASCIIStringEncoding)!
|
||||
for _ in 1...N * 10000 {
|
||||
test as String
|
||||
}
|
||||
}
|
||||
36
benchmark/single-source/NopDeinit.swift
Normal file
36
benchmark/single-source/NopDeinit.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
//===--- NopDeinit.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// <rdar://problem/17838787>
|
||||
import TestsUtils
|
||||
|
||||
class X<T : Comparable> {
|
||||
let deinitIters = 10000
|
||||
var elem : T
|
||||
init(_ x : T) {elem = x}
|
||||
deinit {
|
||||
for _ in 1...deinitIters {
|
||||
if (elem > elem) { };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func run_NopDeinit(N: Int) {
|
||||
for _ in 1...N {
|
||||
var arr :[X<Int>] = []
|
||||
let size = 500
|
||||
for i in 1...size { arr.append(X(i)) }
|
||||
arr.removeAll()
|
||||
CheckResults(arr.count == 0,
|
||||
"Incorrect results in NopDeinit: \(arr.count) != 0.")
|
||||
}
|
||||
}
|
||||
135
benchmark/single-source/ObjectAllocation.swift
Normal file
135
benchmark/single-source/ObjectAllocation.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
//===--- ObjectAllocation.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks the performance of allocations.
|
||||
import TestsUtils
|
||||
|
||||
final class XX {
|
||||
var xx: Int
|
||||
|
||||
init(_ x: Int) {
|
||||
xx = x
|
||||
}
|
||||
}
|
||||
|
||||
final class TreeNode {
|
||||
let left: XX
|
||||
let right: XX
|
||||
|
||||
init(_ l: XX, _ r: XX) {
|
||||
left = l
|
||||
right = r
|
||||
}
|
||||
}
|
||||
|
||||
final class LinkedNode {
|
||||
var next: LinkedNode?
|
||||
var xx: Int
|
||||
|
||||
init(_ x: Int, _ n: LinkedNode?) {
|
||||
xx = x
|
||||
next = n
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func getInt(x: XX) -> Int {
|
||||
return x.xx
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testSingleObject() -> Int {
|
||||
var s = 0
|
||||
for i in 0..<1000 {
|
||||
let x = XX(i)
|
||||
s += getInt(x)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func addInts(t: TreeNode) -> Int {
|
||||
return t.left.xx + t.right.xx
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testTree() -> Int {
|
||||
var s = 0
|
||||
for i in 0..<300 {
|
||||
let t = TreeNode(XX(i), XX(i + 1))
|
||||
s += addInts(t)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func addAllInts(n: LinkedNode) -> Int {
|
||||
var s = 0
|
||||
var iter: LinkedNode? = n
|
||||
while let iter2 = iter {
|
||||
s += iter2.xx
|
||||
iter = iter2.next
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testList() -> Int {
|
||||
var s = 0
|
||||
for i in 0..<250 {
|
||||
let l = LinkedNode(i, LinkedNode(27, LinkedNode(42, nil)))
|
||||
s += addAllInts(l)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func identity(x: Int) -> Int {
|
||||
return x
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func testArray() -> Int {
|
||||
var s = 0
|
||||
for _ in 0..<1000 {
|
||||
for i in [0, 1, 2] {
|
||||
s += identity(i)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_ObjectAllocation(N: Int) {
|
||||
|
||||
var SingleObjectResult = 0
|
||||
var TreeResult = 0
|
||||
var ListResult = 0
|
||||
var ArrayResult = 0
|
||||
|
||||
for _ in 0..<N {
|
||||
SingleObjectResult = testSingleObject()
|
||||
TreeResult = testTree()
|
||||
ListResult = testList()
|
||||
ArrayResult = testArray()
|
||||
}
|
||||
|
||||
CheckResults(SingleObjectResult == 499500,
|
||||
"Incorrect results in testSingleObject")
|
||||
CheckResults(TreeResult == 90000,
|
||||
"Incorrect results in testTree")
|
||||
CheckResults(ListResult == 48375,
|
||||
"Incorrect results in testList")
|
||||
CheckResults(ArrayResult == 3000,
|
||||
"Incorrect results in testArray")
|
||||
}
|
||||
|
||||
37
benchmark/single-source/OpenClose.swift
Normal file
37
benchmark/single-source/OpenClose.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//===--- OpenClose.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
|
||||
// A micro benchmark for checking the speed of string-based enums.
|
||||
|
||||
enum MyState : String {
|
||||
case Closed = "Closed"
|
||||
case Opened = "Opened"
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func check_state(state : MyState) -> Int {
|
||||
return state == .Opened ? 1 : 0
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_OpenClose(N: Int) {
|
||||
var c = 0
|
||||
for _ in 1...N*10000 {
|
||||
c += check_state(MyState.Closed)
|
||||
}
|
||||
CheckResults(c == 0, "IncorrectResults in run_OpenClose")
|
||||
}
|
||||
|
||||
74
benchmark/single-source/Phonebook.swift
Normal file
74
benchmark/single-source/Phonebook.swift
Normal file
@@ -0,0 +1,74 @@
|
||||
//===--- Phonebook.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test is based on util/benchmarks/Phonebook, with modifications
|
||||
// for performance measuring.
|
||||
import TestsUtils
|
||||
|
||||
var words=[
|
||||
"James", "John", "Robert", "Michael", "William", "David", "Richard", "Joseph",
|
||||
"Charles", "Thomas", "Christopher", "Daniel", "Matthew", "Donald", "Anthony",
|
||||
"Paul", "Mark", "George", "Steven", "Kenneth", "Andrew", "Edward", "Brian",
|
||||
"Joshua", "Kevin", "Ronald", "Timothy", "Jason", "Jeffrey", "Gary", "Ryan",
|
||||
"Nicholas", "Eric", "Stephen", "Jacob", "Larry", "Frank", "Jonathan", "Scott",
|
||||
"Justin", "Raymond", "Brandon", "Gregory", "Samuel", "Patrick", "Benjamin",
|
||||
"Jack", "Dennis", "Jerry", "Alexander", "Tyler", "Douglas", "Henry", "Peter",
|
||||
"Walter", "Aaron", "Jose", "Adam", "Harold", "Zachary", "Nathan", "Carl",
|
||||
"Kyle", "Arthur", "Gerald", "Lawrence", "Roger", "Albert", "Keith", "Jeremy",
|
||||
"Terry", "Joe", "Sean", "Willie", "Jesse", "Ralph", "Billy", "Austin", "Bruce",
|
||||
"Christian", "Roy", "Bryan", "Eugene", "Louis", "Harry", "Wayne", "Ethan",
|
||||
"Jordan", "Russell", "Alan", "Philip", "Randy", "Juan", "Howard", "Vincent",
|
||||
"Bobby", "Dylan", "Johnny", "Phillip", "Craig"]
|
||||
|
||||
// This is a phone book record.
|
||||
struct Record : Comparable {
|
||||
var first : String
|
||||
var last : String
|
||||
|
||||
init(_ first_ : String,_ last_ : String) {
|
||||
first = first_
|
||||
last = last_
|
||||
}
|
||||
}
|
||||
func ==(lhs: Record, rhs: Record) -> Bool {
|
||||
return lhs.last == rhs.last && lhs.first == rhs.first
|
||||
}
|
||||
|
||||
func <(lhs: Record, rhs: Record) -> Bool {
|
||||
if lhs.last < rhs.last {
|
||||
return true
|
||||
}
|
||||
if lhs.last > rhs.last {
|
||||
return false
|
||||
}
|
||||
|
||||
if lhs.first < rhs.first {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Phonebook(N: Int) {
|
||||
// The list of names in the phonebook.
|
||||
var Names : [Record] = []
|
||||
for first in words {
|
||||
for last in words {
|
||||
Names.append(Record(first, last))
|
||||
}
|
||||
}
|
||||
for _ in 1...N {
|
||||
var t = Names;
|
||||
t.sort()
|
||||
}
|
||||
}
|
||||
333
benchmark/single-source/PolymorphicCalls.swift
Normal file
333
benchmark/single-source/PolymorphicCalls.swift
Normal file
@@ -0,0 +1,333 @@
|
||||
//===--- PolymorphicCalls.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://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 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 += 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 += 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 += 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 += a2_c2.run2()
|
||||
cnt += 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 += a3_c3.run2()
|
||||
cnt += a3_d3.run2()
|
||||
cnt += a3_e3.run2()
|
||||
cnt += a3_f3.run2()
|
||||
}
|
||||
return cnt
|
||||
}
|
||||
|
||||
|
||||
|
||||
@inline(never)
|
||||
public func run_PolymorphicCalls(N:Int) {
|
||||
let UPTO = 10000 * N
|
||||
|
||||
let a = A(b:B(x:1))
|
||||
test(a, UPTO)
|
||||
|
||||
let a1 = A1(b:C1(x:1))
|
||||
|
||||
test(a1, UPTO)
|
||||
|
||||
let a2 = A2(b:C2(x:1))
|
||||
|
||||
test(a2, UPTO)
|
||||
|
||||
let a2_c2 = A2(b:C2(x:1))
|
||||
let a2_d2 = A2(b:D2(x:1))
|
||||
|
||||
test(a2_c2, a2_d2, UPTO)
|
||||
|
||||
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))
|
||||
|
||||
test(a3_c3, a3_d3, a3_e3, a3_f3, UPTO)
|
||||
}
|
||||
56
benchmark/single-source/PopFront.swift
Normal file
56
benchmark/single-source/PopFront.swift
Normal file
@@ -0,0 +1,56 @@
|
||||
//===--- PopFront.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
let reps = 1
|
||||
let arrayCount = 1024
|
||||
|
||||
@inline(never)
|
||||
public func run_PopFrontArray(N: Int) {
|
||||
let orig = Array(repeating: 1, count: arrayCount)
|
||||
var a = [Int]()
|
||||
for _ in 1...20*N {
|
||||
for _ in 1...reps {
|
||||
var result = 0
|
||||
a.appendContentsOf(orig)
|
||||
while a.count != 0 {
|
||||
result += a[0]
|
||||
a.removeAt(0)
|
||||
}
|
||||
CheckResults(result == arrayCount, "IncorrectResults in StringInterpolation: \(result) != \(arrayCount)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_PopFrontUnsafePointer(N: Int) {
|
||||
var orig = Array(repeating: 1, count: arrayCount)
|
||||
let a = UnsafeMutablePointer<Int>(allocatingCapacity: arrayCount)
|
||||
for _ in 1...100*N {
|
||||
for _ in 1...reps {
|
||||
for i in 0..<arrayCount {
|
||||
a[i] = orig[i]
|
||||
}
|
||||
var result = 0
|
||||
var count = arrayCount
|
||||
while count != 0 {
|
||||
result += a[0]
|
||||
a.assignFrom(a + 1, count: count - 1)
|
||||
count -= 1
|
||||
}
|
||||
CheckResults(result == arrayCount, "IncorrectResults in StringInterpolation: \(result) != \(arrayCount)")
|
||||
}
|
||||
}
|
||||
a.deallocateCapacity(arrayCount)
|
||||
}
|
||||
|
||||
63
benchmark/single-source/PopFrontGeneric.swift
Normal file
63
benchmark/single-source/PopFrontGeneric.swift
Normal file
@@ -0,0 +1,63 @@
|
||||
//===--- PopFrontGeneric.swift --------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
let reps = 1
|
||||
let arrayCount = 1024
|
||||
|
||||
// This test case exposes rdar://17440222 which caused rdar://17974483 (popFront
|
||||
// being really slow).
|
||||
|
||||
func _arrayReplace<B: _ArrayBufferProtocol, C: Collection
|
||||
where C.Iterator.Element == B.Element, B.Index == Int
|
||||
>(
|
||||
inout target: B, _ subRange: Range<Int>, _ newValues: C
|
||||
) {
|
||||
_require(
|
||||
subRange.startIndex >= 0,
|
||||
"Array replace: subRange start is negative")
|
||||
|
||||
_require(
|
||||
subRange.endIndex <= target.endIndex,
|
||||
"Array replace: subRange extends past the end")
|
||||
|
||||
let oldCount = target.count
|
||||
let eraseCount = subRange.count
|
||||
let insertCount = numericCast(newValues.count) as Int
|
||||
let growth = insertCount - eraseCount
|
||||
|
||||
if target.requestUniqueMutableBackingBuffer(oldCount + growth) != nil {
|
||||
target.replace(subRange: subRange, with: insertCount, elementsOf: newValues)
|
||||
}
|
||||
else {
|
||||
_requirementFailure("Should not get here?")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@inline(never)
|
||||
public func run_PopFrontArrayGeneric(N: Int) {
|
||||
let orig = Array(repeating: 1, count: arrayCount)
|
||||
var a = [Int]()
|
||||
for _ in 1...20*N {
|
||||
for _ in 1...reps {
|
||||
var result = 0
|
||||
a.appendContentsOf(orig)
|
||||
while a.count != 0 {
|
||||
result += a[0]
|
||||
_arrayReplace(&a._buffer, 0..<1, EmptyCollection())
|
||||
}
|
||||
CheckResults(result == arrayCount, "IncorrectResults in StringInterpolation: \(result) != \(arrayCount)")
|
||||
}
|
||||
}
|
||||
}
|
||||
757
benchmark/single-source/Prims.swift
Normal file
757
benchmark/single-source/Prims.swift
Normal file
@@ -0,0 +1,757 @@
|
||||
//===--- Prims.swift ------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The test implements Prim's algorithm for minimum spanning tree building.
|
||||
// http://en.wikipedia.org/wiki/Prim%27s_algorithm
|
||||
|
||||
// This class implements array-based heap (priority queue).
|
||||
// It is used to store edges from nodes in spanning tree to nodes outside of it.
|
||||
// We are interested only in the edges with the smallest costs, so if there are
|
||||
// several edges pointing to the same node, we keep only one from them. Thus,
|
||||
// it is enough to record this node instead.
|
||||
// We maintain a map (node index in graph)->(node index in heap) to be able to
|
||||
// update the heap fast when we add a new node to the tree.
|
||||
import TestsUtils
|
||||
|
||||
class PriorityQueue {
|
||||
final var heap : Array<EdgeCost>
|
||||
final var graphIndexToHeapIndexMap : Array<Int?>
|
||||
|
||||
// Create heap for graph with NUM nodes.
|
||||
init(Num: Int) {
|
||||
heap = Array<EdgeCost>()
|
||||
graphIndexToHeapIndexMap = Array<Int?>(repeating:nil, count: Num)
|
||||
}
|
||||
|
||||
func isEmpty() -> Bool {
|
||||
return heap.isEmpty
|
||||
}
|
||||
|
||||
// Insert element N to heap, maintaining the heap property.
|
||||
func insert(n : EdgeCost) {
|
||||
let ind: Int = heap.count
|
||||
heap.append(n)
|
||||
graphIndexToHeapIndexMap[n.to] = heap.count - 1
|
||||
bubbleUp(ind)
|
||||
}
|
||||
|
||||
// Insert element N if in's not in the heap, or update its cost if the new
|
||||
// value is less than the existing one.
|
||||
func insertOrUpdate(n : EdgeCost) {
|
||||
let id = n.to
|
||||
let c = n.cost
|
||||
if let ind = graphIndexToHeapIndexMap[id] {
|
||||
if heap[ind].cost <= c {
|
||||
// We don't need an edge with a bigger cost
|
||||
return
|
||||
}
|
||||
heap[ind].cost = c
|
||||
heap[ind].from = n.from
|
||||
bubbleUp(ind)
|
||||
} else {
|
||||
insert(n)
|
||||
}
|
||||
}
|
||||
|
||||
// Restore heap property by moving element at index IND up.
|
||||
// This is needed after insertion, and after decreasing an element's cost.
|
||||
func bubbleUp(ind: Int) {
|
||||
var ind = ind
|
||||
let c = heap[ind].cost
|
||||
while (ind != 0) {
|
||||
let p = getParentIndex(ind)
|
||||
if heap[p].cost > c {
|
||||
Swap(p, with: ind)
|
||||
ind = p
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pop minimum element from heap and restore the heap property after that.
|
||||
func pop() -> EdgeCost? {
|
||||
if (heap.isEmpty) {
|
||||
return nil
|
||||
}
|
||||
Swap(0, with:heap.count-1)
|
||||
let r = heap.removeLast()
|
||||
graphIndexToHeapIndexMap[r.to] = nil
|
||||
bubbleDown(0)
|
||||
return r
|
||||
}
|
||||
|
||||
// Restore heap property by moving element at index IND down.
|
||||
// This is needed after removing an element, and after increasing an
|
||||
// element's cost.
|
||||
func bubbleDown(ind: Int) {
|
||||
var ind = ind
|
||||
let n = heap.count
|
||||
while (ind < n) {
|
||||
let l = getLeftChildIndex(ind)
|
||||
let r = getRightChildIndex(ind)
|
||||
if (l >= n) {
|
||||
break
|
||||
}
|
||||
var min: Int
|
||||
if (r < n && heap[r].cost < heap[l].cost) {
|
||||
min = r
|
||||
} else {
|
||||
min = l
|
||||
}
|
||||
if (heap[ind].cost <= heap[min].cost) {
|
||||
break
|
||||
}
|
||||
Swap(ind, with: min)
|
||||
ind = min
|
||||
}
|
||||
}
|
||||
|
||||
// Swaps elements I and J in the heap and correspondingly updates
|
||||
// graphIndexToHeapIndexMap.
|
||||
func Swap(i: Int, with j : Int) {
|
||||
if (i == j) {
|
||||
return
|
||||
}
|
||||
(heap[i], heap[j]) = (heap[j], heap[i])
|
||||
let (I, J) = (heap[i].to, heap[j].to)
|
||||
(graphIndexToHeapIndexMap[I], graphIndexToHeapIndexMap[J]) =
|
||||
(graphIndexToHeapIndexMap[J], graphIndexToHeapIndexMap[I])
|
||||
}
|
||||
|
||||
// Dumps the heap.
|
||||
func dump() {
|
||||
print("QUEUE")
|
||||
for nodeCost in heap {
|
||||
let to : Int = nodeCost.to
|
||||
let from : Int = nodeCost.from
|
||||
let cost : Double = nodeCost.cost
|
||||
print("(\(from)->\(to), \(cost))")
|
||||
}
|
||||
}
|
||||
|
||||
func getLeftChildIndex(index : Int) -> Int {
|
||||
return index*2 + 1
|
||||
}
|
||||
func getRightChildIndex(index : Int) -> Int {
|
||||
return (index + 1)*2
|
||||
}
|
||||
func getParentIndex(childIndex : Int) -> Int {
|
||||
return (childIndex - 1)/2
|
||||
}
|
||||
}
|
||||
|
||||
struct GraphNode {
|
||||
var id : Int
|
||||
var adjList : Array<Int>
|
||||
|
||||
init(i : Int) {
|
||||
id = i
|
||||
adjList = Array<Int>()
|
||||
}
|
||||
}
|
||||
|
||||
struct EdgeCost {
|
||||
var to : Int
|
||||
var cost : Double
|
||||
var from: Int
|
||||
}
|
||||
|
||||
struct Edge : Equatable {
|
||||
var start : Int
|
||||
var end : Int
|
||||
}
|
||||
|
||||
func ==(lhs: Edge, rhs: Edge) -> Bool {
|
||||
return lhs.start == rhs.start && lhs.end == rhs.end
|
||||
}
|
||||
|
||||
extension Edge : Hashable {
|
||||
var hashValue: Int {
|
||||
get {
|
||||
return start.hashValue ^ end.hashValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Prims(graph : Array<GraphNode>, _ fun : (Int,Int)->Double) -> Array<Int?> {
|
||||
var treeEdges = Array<Int?>(repeating:nil, count:graph.count)
|
||||
|
||||
let queue = PriorityQueue(Num:graph.count)
|
||||
// Make the minimum spanning tree root its own parent for simplicity.
|
||||
queue.insert(EdgeCost(to: 0, cost: 0.0, from: 0))
|
||||
|
||||
// Take an element with the smallest cost from the queue and add its
|
||||
// neighbours to the queue if their cost was updated
|
||||
while !queue.isEmpty() {
|
||||
// Add an edge with minimum cost to the spanning tree
|
||||
let e = queue.pop()!
|
||||
let newnode = e.to
|
||||
// Add record about the edge newnode->e.from to treeEdges
|
||||
treeEdges[newnode] = e.from
|
||||
|
||||
// Check all adjacent nodes and add edges, ending outside the tree, to the
|
||||
// queue. If the queue already contains an edge to an adjacent node, we
|
||||
// replace existing one with the new one in case the new one costs less.
|
||||
for adjNodeIndex in graph[newnode].adjList {
|
||||
if treeEdges[adjNodeIndex] != nil {
|
||||
continue
|
||||
}
|
||||
let newcost = fun(newnode, graph[adjNodeIndex].id)
|
||||
queue.insertOrUpdate(EdgeCost(to: adjNodeIndex, cost: newcost, from: newnode))
|
||||
}
|
||||
}
|
||||
return treeEdges
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Prims(N: Int) {
|
||||
for _ in 1...5*N {
|
||||
let nodes : [Int] = [ 0, 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 ]
|
||||
|
||||
// Prim's algorithm is designed for undirected graphs.
|
||||
// Due to that, in our set all the edges are paired, i.e. for any
|
||||
// edge (start,end,C) there is also an edge (end,start,C).
|
||||
let edges : [(Int, Int, Double)] = [
|
||||
(26, 47, 921),
|
||||
(20, 25, 971),
|
||||
(92, 59, 250),
|
||||
(33, 55, 1391),
|
||||
(78, 39, 313),
|
||||
(7, 25, 637),
|
||||
(18, 19, 1817),
|
||||
(33, 41, 993),
|
||||
(64, 41, 926),
|
||||
(88, 86, 574),
|
||||
(93, 15, 1462),
|
||||
(86, 33, 1649),
|
||||
(37, 35, 841),
|
||||
(98, 51, 1160),
|
||||
(15, 30, 1125),
|
||||
(65, 78, 1052),
|
||||
(58, 12, 1273),
|
||||
(12, 17, 285),
|
||||
(45, 61, 1608),
|
||||
(75, 53, 545),
|
||||
(99, 48, 410),
|
||||
(97, 0, 1303),
|
||||
(48, 17, 1807),
|
||||
(1, 54, 1491),
|
||||
(15, 34, 807),
|
||||
(94, 98, 646),
|
||||
(12, 69, 136),
|
||||
(65, 11, 983),
|
||||
(63, 83, 1604),
|
||||
(78, 89, 1828),
|
||||
(61, 63, 845),
|
||||
(18, 36, 1626),
|
||||
(68, 52, 1324),
|
||||
(14, 50, 690),
|
||||
(3, 11, 943),
|
||||
(21, 68, 914),
|
||||
(19, 44, 1762),
|
||||
(85, 80, 270),
|
||||
(59, 92, 250),
|
||||
(86, 84, 1431),
|
||||
(19, 18, 1817),
|
||||
(52, 68, 1324),
|
||||
(16, 29, 1108),
|
||||
(36, 80, 395),
|
||||
(67, 18, 803),
|
||||
(63, 88, 1717),
|
||||
(68, 21, 914),
|
||||
(75, 82, 306),
|
||||
(49, 82, 1292),
|
||||
(73, 45, 1876),
|
||||
(89, 82, 409),
|
||||
(45, 47, 272),
|
||||
(22, 83, 597),
|
||||
(61, 12, 1791),
|
||||
(44, 68, 1229),
|
||||
(50, 51, 917),
|
||||
(14, 53, 355),
|
||||
(77, 41, 138),
|
||||
(54, 21, 1870),
|
||||
(93, 70, 1582),
|
||||
(76, 2, 1658),
|
||||
(83, 73, 1162),
|
||||
(6, 1, 482),
|
||||
(11, 65, 983),
|
||||
(81, 90, 1024),
|
||||
(19, 1, 970),
|
||||
(8, 58, 1131),
|
||||
(60, 42, 477),
|
||||
(86, 29, 258),
|
||||
(69, 59, 903),
|
||||
(34, 15, 807),
|
||||
(37, 2, 1451),
|
||||
(7, 73, 754),
|
||||
(47, 86, 184),
|
||||
(67, 17, 449),
|
||||
(18, 67, 803),
|
||||
(25, 4, 595),
|
||||
(3, 31, 1337),
|
||||
(64, 31, 1928),
|
||||
(9, 43, 237),
|
||||
(83, 63, 1604),
|
||||
(47, 45, 272),
|
||||
(86, 88, 574),
|
||||
(87, 74, 934),
|
||||
(98, 94, 646),
|
||||
(20, 1, 642),
|
||||
(26, 92, 1344),
|
||||
(18, 17, 565),
|
||||
(47, 11, 595),
|
||||
(10, 59, 1558),
|
||||
(2, 76, 1658),
|
||||
(77, 74, 1277),
|
||||
(42, 60, 477),
|
||||
(80, 36, 395),
|
||||
(35, 23, 589),
|
||||
(50, 37, 203),
|
||||
(6, 96, 481),
|
||||
(78, 65, 1052),
|
||||
(1, 52, 127),
|
||||
(65, 23, 1932),
|
||||
(46, 51, 213),
|
||||
(59, 89, 89),
|
||||
(15, 93, 1462),
|
||||
(69, 3, 1305),
|
||||
(17, 37, 1177),
|
||||
(30, 3, 193),
|
||||
(9, 15, 818),
|
||||
(75, 95, 977),
|
||||
(86, 47, 184),
|
||||
(10, 12, 1736),
|
||||
(80, 27, 1010),
|
||||
(12, 10, 1736),
|
||||
(86, 1, 1958),
|
||||
(60, 12, 1240),
|
||||
(43, 71, 683),
|
||||
(91, 65, 1519),
|
||||
(33, 86, 1649),
|
||||
(62, 26, 1773),
|
||||
(1, 13, 1187),
|
||||
(2, 10, 1018),
|
||||
(91, 29, 351),
|
||||
(69, 12, 136),
|
||||
(43, 9, 237),
|
||||
(29, 86, 258),
|
||||
(17, 48, 1807),
|
||||
(31, 64, 1928),
|
||||
(68, 61, 1936),
|
||||
(76, 38, 1724),
|
||||
(1, 6, 482),
|
||||
(53, 14, 355),
|
||||
(51, 50, 917),
|
||||
(54, 13, 815),
|
||||
(19, 29, 883),
|
||||
(35, 87, 974),
|
||||
(70, 96, 511),
|
||||
(23, 35, 589),
|
||||
(39, 69, 1588),
|
||||
(93, 73, 1093),
|
||||
(13, 73, 435),
|
||||
(5, 60, 1619),
|
||||
(42, 41, 1523),
|
||||
(66, 58, 1596),
|
||||
(1, 67, 431),
|
||||
(17, 67, 449),
|
||||
(30, 95, 906),
|
||||
(71, 43, 683),
|
||||
(5, 87, 190),
|
||||
(12, 78, 891),
|
||||
(30, 97, 402),
|
||||
(28, 17, 1131),
|
||||
(7, 97, 1356),
|
||||
(58, 66, 1596),
|
||||
(20, 37, 1294),
|
||||
(73, 76, 514),
|
||||
(54, 8, 613),
|
||||
(68, 35, 1252),
|
||||
(92, 32, 701),
|
||||
(3, 90, 652),
|
||||
(99, 46, 1576),
|
||||
(13, 54, 815),
|
||||
(20, 87, 1390),
|
||||
(36, 18, 1626),
|
||||
(51, 26, 1146),
|
||||
(2, 23, 581),
|
||||
(29, 7, 1558),
|
||||
(88, 59, 173),
|
||||
(17, 1, 1071),
|
||||
(37, 49, 1011),
|
||||
(18, 6, 696),
|
||||
(88, 33, 225),
|
||||
(58, 38, 802),
|
||||
(87, 50, 1744),
|
||||
(29, 91, 351),
|
||||
(6, 71, 1053),
|
||||
(45, 24, 1720),
|
||||
(65, 91, 1519),
|
||||
(37, 50, 203),
|
||||
(11, 3, 943),
|
||||
(72, 65, 1330),
|
||||
(45, 50, 339),
|
||||
(25, 20, 971),
|
||||
(15, 9, 818),
|
||||
(14, 54, 1353),
|
||||
(69, 95, 393),
|
||||
(8, 66, 1213),
|
||||
(52, 2, 1608),
|
||||
(50, 14, 690),
|
||||
(50, 45, 339),
|
||||
(1, 37, 1273),
|
||||
(45, 93, 1650),
|
||||
(39, 78, 313),
|
||||
(1, 86, 1958),
|
||||
(17, 28, 1131),
|
||||
(35, 33, 1667),
|
||||
(23, 2, 581),
|
||||
(51, 66, 245),
|
||||
(17, 54, 924),
|
||||
(41, 49, 1629),
|
||||
(60, 5, 1619),
|
||||
(56, 93, 1110),
|
||||
(96, 13, 461),
|
||||
(25, 7, 637),
|
||||
(11, 69, 370),
|
||||
(90, 3, 652),
|
||||
(39, 71, 1485),
|
||||
(65, 51, 1529),
|
||||
(20, 6, 1414),
|
||||
(80, 85, 270),
|
||||
(73, 83, 1162),
|
||||
(0, 97, 1303),
|
||||
(13, 33, 826),
|
||||
(29, 71, 1788),
|
||||
(33, 12, 461),
|
||||
(12, 58, 1273),
|
||||
(69, 39, 1588),
|
||||
(67, 75, 1504),
|
||||
(87, 20, 1390),
|
||||
(88, 97, 526),
|
||||
(33, 88, 225),
|
||||
(95, 69, 393),
|
||||
(2, 52, 1608),
|
||||
(5, 25, 719),
|
||||
(34, 78, 510),
|
||||
(53, 99, 1074),
|
||||
(33, 35, 1667),
|
||||
(57, 30, 361),
|
||||
(87, 58, 1574),
|
||||
(13, 90, 1030),
|
||||
(79, 74, 91),
|
||||
(4, 86, 1107),
|
||||
(64, 94, 1609),
|
||||
(11, 12, 167),
|
||||
(30, 45, 272),
|
||||
(47, 91, 561),
|
||||
(37, 17, 1177),
|
||||
(77, 49, 883),
|
||||
(88, 23, 1747),
|
||||
(70, 80, 995),
|
||||
(62, 77, 907),
|
||||
(18, 4, 371),
|
||||
(73, 93, 1093),
|
||||
(11, 47, 595),
|
||||
(44, 23, 1990),
|
||||
(20, 0, 512),
|
||||
(3, 69, 1305),
|
||||
(82, 3, 1815),
|
||||
(20, 88, 368),
|
||||
(44, 45, 364),
|
||||
(26, 51, 1146),
|
||||
(7, 65, 349),
|
||||
(71, 39, 1485),
|
||||
(56, 88, 1954),
|
||||
(94, 69, 1397),
|
||||
(12, 28, 544),
|
||||
(95, 75, 977),
|
||||
(32, 90, 789),
|
||||
(53, 1, 772),
|
||||
(54, 14, 1353),
|
||||
(49, 77, 883),
|
||||
(92, 26, 1344),
|
||||
(17, 18, 565),
|
||||
(97, 88, 526),
|
||||
(48, 80, 1203),
|
||||
(90, 32, 789),
|
||||
(71, 6, 1053),
|
||||
(87, 35, 974),
|
||||
(55, 90, 1808),
|
||||
(12, 61, 1791),
|
||||
(1, 96, 328),
|
||||
(63, 10, 1681),
|
||||
(76, 34, 871),
|
||||
(41, 64, 926),
|
||||
(42, 97, 482),
|
||||
(25, 5, 719),
|
||||
(23, 65, 1932),
|
||||
(54, 1, 1491),
|
||||
(28, 12, 544),
|
||||
(89, 10, 108),
|
||||
(27, 33, 143),
|
||||
(67, 1, 431),
|
||||
(32, 45, 52),
|
||||
(79, 33, 1871),
|
||||
(6, 55, 717),
|
||||
(10, 58, 459),
|
||||
(67, 39, 393),
|
||||
(10, 4, 1808),
|
||||
(96, 6, 481),
|
||||
(1, 19, 970),
|
||||
(97, 7, 1356),
|
||||
(29, 16, 1108),
|
||||
(1, 53, 772),
|
||||
(30, 15, 1125),
|
||||
(4, 6, 634),
|
||||
(6, 20, 1414),
|
||||
(88, 56, 1954),
|
||||
(87, 64, 1950),
|
||||
(34, 76, 871),
|
||||
(17, 12, 285),
|
||||
(55, 59, 321),
|
||||
(61, 68, 1936),
|
||||
(50, 87, 1744),
|
||||
(84, 44, 952),
|
||||
(41, 33, 993),
|
||||
(59, 18, 1352),
|
||||
(33, 27, 143),
|
||||
(38, 32, 1210),
|
||||
(55, 70, 1264),
|
||||
(38, 58, 802),
|
||||
(1, 20, 642),
|
||||
(73, 13, 435),
|
||||
(80, 48, 1203),
|
||||
(94, 64, 1609),
|
||||
(38, 28, 414),
|
||||
(73, 23, 1113),
|
||||
(78, 12, 891),
|
||||
(26, 62, 1773),
|
||||
(87, 43, 579),
|
||||
(53, 6, 95),
|
||||
(59, 95, 285),
|
||||
(88, 63, 1717),
|
||||
(17, 5, 633),
|
||||
(66, 8, 1213),
|
||||
(41, 42, 1523),
|
||||
(83, 22, 597),
|
||||
(95, 30, 906),
|
||||
(51, 65, 1529),
|
||||
(17, 49, 1727),
|
||||
(64, 87, 1950),
|
||||
(86, 4, 1107),
|
||||
(37, 98, 1102),
|
||||
(32, 92, 701),
|
||||
(60, 94, 198),
|
||||
(73, 98, 1749),
|
||||
(4, 18, 371),
|
||||
(96, 70, 511),
|
||||
(7, 29, 1558),
|
||||
(35, 37, 841),
|
||||
(27, 64, 384),
|
||||
(12, 33, 461),
|
||||
(36, 38, 529),
|
||||
(69, 16, 1183),
|
||||
(91, 47, 561),
|
||||
(85, 29, 1676),
|
||||
(3, 82, 1815),
|
||||
(69, 58, 1579),
|
||||
(93, 45, 1650),
|
||||
(97, 42, 482),
|
||||
(37, 1, 1273),
|
||||
(61, 4, 543),
|
||||
(96, 1, 328),
|
||||
(26, 0, 1993),
|
||||
(70, 64, 878),
|
||||
(3, 30, 193),
|
||||
(58, 69, 1579),
|
||||
(4, 25, 595),
|
||||
(31, 3, 1337),
|
||||
(55, 6, 717),
|
||||
(39, 67, 393),
|
||||
(78, 34, 510),
|
||||
(75, 67, 1504),
|
||||
(6, 53, 95),
|
||||
(51, 79, 175),
|
||||
(28, 91, 1040),
|
||||
(89, 78, 1828),
|
||||
(74, 93, 1587),
|
||||
(45, 32, 52),
|
||||
(10, 2, 1018),
|
||||
(49, 37, 1011),
|
||||
(63, 61, 845),
|
||||
(0, 20, 512),
|
||||
(1, 17, 1071),
|
||||
(99, 53, 1074),
|
||||
(37, 20, 1294),
|
||||
(10, 89, 108),
|
||||
(33, 92, 946),
|
||||
(23, 73, 1113),
|
||||
(23, 88, 1747),
|
||||
(49, 17, 1727),
|
||||
(88, 20, 368),
|
||||
(21, 54, 1870),
|
||||
(70, 93, 1582),
|
||||
(59, 88, 173),
|
||||
(32, 38, 1210),
|
||||
(89, 59, 89),
|
||||
(23, 44, 1990),
|
||||
(38, 76, 1724),
|
||||
(30, 57, 361),
|
||||
(94, 60, 198),
|
||||
(59, 10, 1558),
|
||||
(55, 64, 1996),
|
||||
(12, 11, 167),
|
||||
(36, 24, 1801),
|
||||
(97, 30, 402),
|
||||
(52, 1, 127),
|
||||
(58, 87, 1574),
|
||||
(54, 17, 924),
|
||||
(93, 74, 1587),
|
||||
(24, 36, 1801),
|
||||
(2, 37, 1451),
|
||||
(91, 28, 1040),
|
||||
(59, 55, 321),
|
||||
(69, 11, 370),
|
||||
(8, 54, 613),
|
||||
(29, 85, 1676),
|
||||
(44, 19, 1762),
|
||||
(74, 79, 91),
|
||||
(93, 56, 1110),
|
||||
(58, 10, 459),
|
||||
(41, 50, 1559),
|
||||
(66, 51, 245),
|
||||
(80, 19, 1838),
|
||||
(33, 79, 1871),
|
||||
(76, 73, 514),
|
||||
(98, 37, 1102),
|
||||
(45, 44, 364),
|
||||
(16, 69, 1183),
|
||||
(49, 41, 1629),
|
||||
(19, 80, 1838),
|
||||
(71, 57, 500),
|
||||
(6, 4, 634),
|
||||
(64, 27, 384),
|
||||
(84, 86, 1431),
|
||||
(5, 17, 633),
|
||||
(96, 88, 334),
|
||||
(87, 5, 190),
|
||||
(70, 21, 1619),
|
||||
(55, 33, 1391),
|
||||
(10, 63, 1681),
|
||||
(11, 62, 1339),
|
||||
(33, 13, 826),
|
||||
(64, 70, 878),
|
||||
(65, 72, 1330),
|
||||
(70, 55, 1264),
|
||||
(64, 55, 1996),
|
||||
(50, 41, 1559),
|
||||
(46, 99, 1576),
|
||||
(88, 96, 334),
|
||||
(51, 20, 868),
|
||||
(73, 7, 754),
|
||||
(80, 70, 995),
|
||||
(44, 84, 952),
|
||||
(29, 19, 883),
|
||||
(59, 69, 903),
|
||||
(57, 53, 1575),
|
||||
(90, 13, 1030),
|
||||
(28, 38, 414),
|
||||
(12, 60, 1240),
|
||||
(85, 58, 573),
|
||||
(90, 55, 1808),
|
||||
(4, 10, 1808),
|
||||
(68, 44, 1229),
|
||||
(92, 33, 946),
|
||||
(90, 81, 1024),
|
||||
(53, 75, 545),
|
||||
(45, 30, 272),
|
||||
(41, 77, 138),
|
||||
(21, 70, 1619),
|
||||
(45, 73, 1876),
|
||||
(35, 68, 1252),
|
||||
(13, 96, 461),
|
||||
(53, 57, 1575),
|
||||
(82, 89, 409),
|
||||
(28, 61, 449),
|
||||
(58, 61, 78),
|
||||
(27, 80, 1010),
|
||||
(61, 58, 78),
|
||||
(38, 36, 529),
|
||||
(80, 30, 397),
|
||||
(18, 59, 1352),
|
||||
(62, 11, 1339),
|
||||
(95, 59, 285),
|
||||
(51, 98, 1160),
|
||||
(6, 18, 696),
|
||||
(30, 80, 397),
|
||||
(69, 94, 1397),
|
||||
(58, 85, 573),
|
||||
(48, 99, 410),
|
||||
(51, 46, 213),
|
||||
(57, 71, 500),
|
||||
(91, 30, 104),
|
||||
(65, 7, 349),
|
||||
(79, 51, 175),
|
||||
(47, 26, 921),
|
||||
(4, 61, 543),
|
||||
(98, 73, 1749),
|
||||
(74, 77, 1277),
|
||||
(61, 28, 449),
|
||||
(58, 8, 1131),
|
||||
(61, 45, 1608),
|
||||
(74, 87, 934),
|
||||
(71, 29, 1788),
|
||||
(30, 91, 104),
|
||||
(13, 1, 1187),
|
||||
(0, 26, 1993),
|
||||
(82, 49, 1292),
|
||||
(43, 87, 579),
|
||||
(24, 45, 1720),
|
||||
(20, 51, 868),
|
||||
(77, 62, 907),
|
||||
(82, 75, 306),
|
||||
]
|
||||
|
||||
// Prepare graph and edge->cost map
|
||||
var graph = Array<GraphNode>()
|
||||
for n in nodes {
|
||||
graph.append(GraphNode(i: n))
|
||||
}
|
||||
var map = Dictionary<Edge, Double>()
|
||||
for tup in edges {
|
||||
map[Edge(start: tup.0, end: tup.1)] = tup.2
|
||||
graph[tup.0].adjList.append(tup.1)
|
||||
}
|
||||
|
||||
// Find spanning tree
|
||||
let treeEdges = Prims(graph, { (start: Int, end: Int) in
|
||||
return map[Edge(start: start, end: end)]!
|
||||
})
|
||||
|
||||
// Compute its cost in order to check results
|
||||
var cost = 0.0
|
||||
for i in 1..<treeEdges.count {
|
||||
if let n = treeEdges[i] { cost += map[Edge(start: n, end: i)]! }
|
||||
}
|
||||
CheckResults(Int(cost) == 49324,
|
||||
"Incorrect results in Prims: \(Int(cost)) != 49324.")
|
||||
}
|
||||
}
|
||||
24
benchmark/single-source/ProtocolDispatch.swift
Normal file
24
benchmark/single-source/ProtocolDispatch.swift
Normal file
@@ -0,0 +1,24 @@
|
||||
//===--- ProtocolDispatch.swift -------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_ProtocolDispatch(N: Int) {
|
||||
|
||||
let x = someProtocolFactory()
|
||||
|
||||
for _ in 0...1000000 * N {
|
||||
x.getValue()
|
||||
}
|
||||
}
|
||||
|
||||
104
benchmark/single-source/RC4.swift
Normal file
104
benchmark/single-source/RC4.swift
Normal file
@@ -0,0 +1,104 @@
|
||||
//===--- RC4.swift --------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test is based on util/benchmarks/RC4, with modifications
|
||||
// for performance measuring.
|
||||
import TestsUtils
|
||||
|
||||
struct RC4 {
|
||||
var State : [UInt8]
|
||||
var I : UInt8 = 0
|
||||
var J : UInt8 = 0
|
||||
|
||||
init() {
|
||||
State = [UInt8](repeating: 0, count: 256)
|
||||
}
|
||||
|
||||
mutating
|
||||
func initialize(Key: [UInt8]) {
|
||||
for i in 0..<256 {
|
||||
State[i] = UInt8(i)
|
||||
}
|
||||
|
||||
var j : UInt8 = 0
|
||||
for i in 0..<256 {
|
||||
let K : UInt8 = Key[i % Key.count]
|
||||
let S : UInt8 = State[i]
|
||||
j = j &+ S &+ K
|
||||
swapByIndex(i, y: Int(j))
|
||||
}
|
||||
}
|
||||
|
||||
mutating
|
||||
func swapByIndex(x: Int, y: Int) {
|
||||
let T1 : UInt8 = State[x]
|
||||
let T2 : UInt8 = State[y]
|
||||
State[x] = T2
|
||||
State[y] = T1
|
||||
}
|
||||
|
||||
mutating
|
||||
func next() -> UInt8 {
|
||||
I = I &+ 1
|
||||
J = J &+ State[Int(I)]
|
||||
swapByIndex(Int(I), y: Int(J))
|
||||
return State[Int(State[Int(I)] &+ State[Int(J)]) & 0xFF]
|
||||
}
|
||||
|
||||
mutating
|
||||
func encrypt(inout Data: [UInt8]) {
|
||||
let cnt = Data.count
|
||||
for i in 0..<cnt {
|
||||
Data[i] = Data[i] ^ next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let RefResults : [UInt8] = [245, 62, 245, 202, 138, 120, 186, 107, 255, 189,
|
||||
184, 223, 65, 77, 112, 201, 238, 161, 74, 192, 145,
|
||||
21, 43, 41, 91, 136, 182, 176, 237, 155, 208, 16,
|
||||
17, 139, 33, 195, 24, 136, 79, 183, 211, 21, 56,
|
||||
202, 235, 65, 201, 184, 68, 29, 110, 218, 112, 122,
|
||||
194, 77, 41, 230, 147, 84, 0, 233, 168, 6, 55, 131,
|
||||
70, 119, 41, 119, 234, 131, 87, 24, 51, 130, 28,
|
||||
66, 172, 105, 33, 97, 179, 48, 81, 229, 114, 216,
|
||||
208, 119, 39, 31, 47, 109, 172, 215, 246, 210, 48,
|
||||
203]
|
||||
|
||||
|
||||
@inline(never)
|
||||
public func run_RC4(N: Int) {
|
||||
let messageLen = 100
|
||||
let iterations = 500
|
||||
let Secret = "This is my secret message"
|
||||
let Key = "This is my key"
|
||||
let SecretData : [UInt8] = Array(Secret.utf8)
|
||||
let KeyData : [UInt8] = Array(Key.utf8)
|
||||
|
||||
var LongData : [UInt8] = [UInt8](repeating: 0, count: messageLen)
|
||||
|
||||
for _ in 1...N {
|
||||
// Generate a long message.
|
||||
for i in 0..<messageLen {
|
||||
LongData[i] = SecretData[i % SecretData.count]
|
||||
}
|
||||
|
||||
var Enc = RC4()
|
||||
Enc.initialize(KeyData)
|
||||
|
||||
for _ in 1...iterations {
|
||||
Enc.encrypt(&LongData)
|
||||
}
|
||||
|
||||
CheckResults(LongData == RefResults, "Incorrect result in RC4")
|
||||
}
|
||||
}
|
||||
112
benchmark/single-source/RGBHistogram.swift
Normal file
112
benchmark/single-source/RGBHistogram.swift
Normal file
@@ -0,0 +1,112 @@
|
||||
//===--- RGBHistogram.swift -----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Performance benchmark for creating RGB histograms
|
||||
// rdar://problem/18539486
|
||||
//
|
||||
// Description:
|
||||
// Create a sorted sparse RGB histogram from an array of 300 RGB values.
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_RGBHistogram(N: Int) {
|
||||
var histogram = [(key: rrggbb_t, value: Int)]()
|
||||
for _ in 1...100*N {
|
||||
histogram = createSortedSparseRGBHistogram(samples)
|
||||
if !isCorrectHistogram(histogram) {
|
||||
break
|
||||
}
|
||||
}
|
||||
CheckResults(isCorrectHistogram(histogram),
|
||||
"Incorrect results in histogram")
|
||||
}
|
||||
|
||||
typealias rrggbb_t = UInt32
|
||||
|
||||
let samples: [rrggbb_t] = [
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0x00FF0000, 0x00FF0000, 0x000000FF, 0x000000FF, 0x000000FF, 0x000000FF,
|
||||
0x00000000, 0x00555555, 0x00AAAAAA, 0x00FFFFFF, 0x00AAAAAA, 0x00FFFFFF,
|
||||
0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080, 0x00808080,
|
||||
0xCCD45FBC, 0xA56F39E4, 0x8C08DBA7, 0xDA4413D7, 0x43926C6B, 0x592975FE,
|
||||
0xC77E47ED, 0xB28F427D, 0x90D7C464, 0x805A003A, 0xAB79B390, 0x49D859B3,
|
||||
0x2419213A, 0x69E8C61D, 0xC4BE948F, 0x896CC6D0, 0xE4F3DFF1, 0x466B68FA,
|
||||
0xC8084E2A, 0x3FC1F2C4, 0x0E0D47F4, 0xB268BFE6, 0x9F990E6A, 0x7389F2F8,
|
||||
0x0720FD81, 0x65388005, 0xD8307612, 0xEC75B9B0, 0xB0C51360, 0x29647EB4,
|
||||
0x6E8B02E6, 0xEFE9F0F4, 0xFEF0EB89, 0x41BBD587, 0xCD19E510, 0x6A710BBD,
|
||||
0xFF146228, 0xFB34AD0C, 0x2AEB5588, 0x71993821, 0x9FC8CA5C, 0xF99E969B,
|
||||
0x8DF78241, 0x21ADFB7C, 0x4DE5E465, 0x0C171D2F, 0x2C08CECF, 0x3318440A,
|
||||
0xEC8F8D1C, 0x6CAFD68E, 0xCA35F571, 0x68A37E1A, 0x3047F87F, 0x50CC39DE,
|
||||
0x776CF5CB, 0x75DC4595, 0x77E32288, 0x14899C0D, 0x14835CF6, 0x0A732F76,
|
||||
0xA4B05790, 0x34CBED42, 0x5A6964CE, 0xEA4CA5F7, 0x3DECB0F1, 0x5015D419,
|
||||
0x84EBC299, 0xC656B381, 0xFA2840C5, 0x618D754E, 0x003B8D96, 0xCE91AA8E,
|
||||
0xBD9784DB, 0x9372E919, 0xC138BEA6, 0xF0B3E3AD, 0x4E4F60BF, 0xC1598ABE,
|
||||
0x930873DB, 0x0F029E3A, 0xBEFC0125, 0x10645D6D, 0x1FF93547, 0xA7069CB5,
|
||||
0xCF0B7E06, 0xE33EDC17, 0x8C5E1F48, 0x2FB345E1, 0x3B0070E0, 0x0421E568,
|
||||
0xB39A42A0, 0xB935DA8B, 0x281C30F0, 0xB2E48677, 0x277A9A45, 0x52AF9FC6,
|
||||
0xBBDF4048, 0xC668137A, 0xF39020D1, 0x71BEE810, 0x5F2B3825, 0x25C863FB,
|
||||
0x876144E8, 0x9B4108C3, 0xF735CB08, 0x8B77DEEC, 0x0185A067, 0xB964F42B,
|
||||
0xA2EC236B, 0x3C08646F, 0xB514C4BE, 0x37EE9689, 0xACF97317, 0x1EA4F7C6,
|
||||
0x453A6F13, 0x01C25E42, 0xA052BB3B, 0x71A699CB, 0xC728AE88, 0x128A656F,
|
||||
0x78F64E55, 0x045967E0, 0xC5DC4125, 0xDA39F6FE, 0x873785B9, 0xB6BB446A,
|
||||
0xF4F5093F, 0xAF05A4EC, 0xB5DB854B, 0x7ADA6A37, 0x9EA218E3, 0xCCCC9316,
|
||||
0x86A133F8, 0x8AF47795, 0xCBA235D4, 0xBB9101CC, 0xBCC8C8A3, 0x02BAC911,
|
||||
0x45C17A8C, 0x896C81FC, 0x4974FA22, 0xEA7CD629, 0x103ED364, 0x4C644503,
|
||||
0x607F4D9F, 0x9733E55E, 0xA360439D, 0x1DB568FD, 0xB7A5C3A1, 0xBE84492D
|
||||
]
|
||||
|
||||
func isCorrectHistogram(histogram: [(key: rrggbb_t, value: Int)]) -> Bool {
|
||||
return histogram.count == 157 &&
|
||||
histogram[0].0 == 0x00808080 && histogram[0].1 == 54 &&
|
||||
histogram[156].0 == 0x003B8D96 && histogram[156].1 == 1
|
||||
}
|
||||
|
||||
func createSortedSparseRGBHistogram
|
||||
<S: Sequence where S.Iterator.Element == rrggbb_t>
|
||||
(samples: S) -> [(key: rrggbb_t, value: Int)] {
|
||||
var histogram = Dictionary<rrggbb_t, Int>()
|
||||
|
||||
for sample in samples {
|
||||
let i = histogram.indexForKey(sample)
|
||||
histogram[sample] = ((i != nil) ? histogram[i!].1 : 0) + 1
|
||||
}
|
||||
|
||||
return histogram.sorted() {
|
||||
if $0.1 == $1.1 {
|
||||
return $0.0 > $1.0
|
||||
} else {
|
||||
return $0.1 > $1.1
|
||||
}
|
||||
}
|
||||
}
|
||||
27
benchmark/single-source/RangeAssignment.swift
Normal file
27
benchmark/single-source/RangeAssignment.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//===--- RangeAssignment.swift --------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_RangeAssignment(scale: Int) {
|
||||
let range = 100..<200
|
||||
var vector = [Double](repeating: 0.0 , count: 5000)
|
||||
let alfa = 1.0
|
||||
let N = 500*scale
|
||||
for _ in 1...N {
|
||||
vector[range] = ArraySlice(vector[range].map { $0 + alfa })
|
||||
}
|
||||
|
||||
CheckResults(vector[100] == Double(N),
|
||||
"IncorrectResults in RangeAssignment: \(vector[100]) != \(N).")
|
||||
}
|
||||
57
benchmark/single-source/RecursiveOwnedParameter.swift
Normal file
57
benchmark/single-source/RecursiveOwnedParameter.swift
Normal file
@@ -0,0 +1,57 @@
|
||||
//===--- RecursiveOwnedParameter.swift ------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
// This test recursively visits each element of an array in a class and compares
|
||||
// it with every value in a different array stored in a different class. The
|
||||
// idea is to make sure that we can get rid of the overhead from guaranteed
|
||||
// parameters.
|
||||
|
||||
// We use final since we are not interesting in devirtualization for the
|
||||
// purposes of this test.
|
||||
final
|
||||
class ArrayWrapper {
|
||||
var data: [Int]
|
||||
|
||||
init(_ count: Int, _ initialValue: Int) {
|
||||
data = [Int](repeating: initialValue, count: count)
|
||||
}
|
||||
|
||||
func compare(b: ArrayWrapper, _ iteration: Int, _ stopIteration: Int) -> Bool {
|
||||
// We will never return true here by design. We want to test the full effect
|
||||
// every time of retaining, releasing.
|
||||
if iteration == stopIteration || data[iteration] == b.data[iteration] {
|
||||
return true
|
||||
}
|
||||
|
||||
return compare(b, iteration &+ 1, stopIteration)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_RecursiveOwnedParameter(N: Int) {
|
||||
let numElts = 1_000
|
||||
|
||||
let a = ArrayWrapper(numElts, 0)
|
||||
let b = ArrayWrapper(numElts, 1)
|
||||
|
||||
var result = 0
|
||||
for _ in 0..<100*N {
|
||||
if a.compare(b, 0, numElts) {
|
||||
result += 1
|
||||
}
|
||||
}
|
||||
let refResult = 100*N
|
||||
CheckResults(result == refResult,
|
||||
"IncorrectResults in RecursiveOwnedParameter: \(result) != \(refResult)")
|
||||
}
|
||||
105
benchmark/single-source/SetTests.swift
Normal file
105
benchmark/single-source/SetTests.swift
Normal file
@@ -0,0 +1,105 @@
|
||||
//===--- SetTests.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_SetIsSubsetOf(N: Int) {
|
||||
let size = 200
|
||||
|
||||
SRand()
|
||||
|
||||
var set = Set<Int>(minimumCapacity: size)
|
||||
var otherSet = Set<Int>(minimumCapacity: size)
|
||||
|
||||
for _ in 0 ..< size {
|
||||
set.insert(Int(truncatingBitPattern: Random()))
|
||||
otherSet.insert(Int(truncatingBitPattern: Random()))
|
||||
}
|
||||
|
||||
var isSubset = false;
|
||||
for _ in 0 ..< N * 5000 {
|
||||
isSubset = set.isSubsetOf(otherSet)
|
||||
if isSubset {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
CheckResults(!isSubset, "Incorrect results in SetIsSubsetOf")
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func sink(inout s: Set<Int>) {
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_SetExclusiveOr(N: Int) {
|
||||
let size = 400
|
||||
|
||||
SRand()
|
||||
|
||||
var set = Set<Int>(minimumCapacity: size)
|
||||
var otherSet = Set<Int>(minimumCapacity: size)
|
||||
|
||||
for _ in 0 ..< size {
|
||||
set.insert(Int(truncatingBitPattern: Random()))
|
||||
otherSet.insert(Int(truncatingBitPattern: Random()))
|
||||
}
|
||||
|
||||
var xor = Set<Int>()
|
||||
for _ in 0 ..< N * 100 {
|
||||
xor = set.exclusiveOr(otherSet)
|
||||
}
|
||||
sink(&xor)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_SetUnion(N: Int) {
|
||||
let size = 400
|
||||
|
||||
SRand()
|
||||
|
||||
var set = Set<Int>(minimumCapacity: size)
|
||||
var otherSet = Set<Int>(minimumCapacity: size)
|
||||
|
||||
for _ in 0 ..< size {
|
||||
set.insert(Int(truncatingBitPattern: Random()))
|
||||
otherSet.insert(Int(truncatingBitPattern: Random()))
|
||||
}
|
||||
|
||||
var or = Set<Int>()
|
||||
for _ in 0 ..< N * 100 {
|
||||
or = set.union(otherSet)
|
||||
}
|
||||
sink(&or)
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_SetIntersect(N: Int) {
|
||||
let size = 400
|
||||
|
||||
SRand()
|
||||
|
||||
var set = Set<Int>(minimumCapacity: size)
|
||||
var otherSet = Set<Int>(minimumCapacity: size)
|
||||
|
||||
for _ in 0 ..< size {
|
||||
set.insert(Int(truncatingBitPattern: Random()))
|
||||
otherSet.insert(Int(truncatingBitPattern: Random()))
|
||||
}
|
||||
|
||||
var and = Set<Int>()
|
||||
for _ in 0 ..< N * 100 {
|
||||
and = set.intersect(otherSet)
|
||||
}
|
||||
sink(&and)
|
||||
}
|
||||
36
benchmark/single-source/SevenBoom.swift
Normal file
36
benchmark/single-source/SevenBoom.swift
Normal file
@@ -0,0 +1,36 @@
|
||||
//===--- SevenBoom.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Foundation
|
||||
|
||||
@inline(never)
|
||||
func filter_seven(input : Int) throws {
|
||||
guard case 7 = input else {
|
||||
throw NSError(domain: "AnDomain", code: 42, userInfo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_SevenBoom(N: Int) {
|
||||
var c = 0
|
||||
for i in 1...N*5000 {
|
||||
do {
|
||||
try filter_seven(i)
|
||||
c += 1
|
||||
}
|
||||
catch _ {
|
||||
}
|
||||
}
|
||||
CheckResults(c == 1, "IncorrectResults in SevenBoom")
|
||||
}
|
||||
|
||||
42
benchmark/single-source/Sim2DArray.swift
Normal file
42
benchmark/single-source/Sim2DArray.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
//===--- Sim2DArray.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
struct Array2D {
|
||||
var storage : [Int]
|
||||
let rows : Int
|
||||
let cols: Int
|
||||
|
||||
init(numRows: Int, numCols: Int) {
|
||||
storage = [Int](repeating: 0, count: numRows * numCols)
|
||||
rows = numRows
|
||||
cols = numCols
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func workload_2DArrayTest(inout A: Array2D) {
|
||||
for _ in 0 ..< 10 {
|
||||
for r in 0 ..< A.rows {
|
||||
for c in 0 ..< A.cols {
|
||||
A.storage[r*A.cols+c] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Sim2DArray(N : Int) {
|
||||
for _ in 0 ..< N {
|
||||
var A = Array2D(numRows:2048, numCols:32)
|
||||
workload_2DArrayTest(&A)
|
||||
}
|
||||
}
|
||||
46
benchmark/single-source/SortLettersInPlace.swift
Normal file
46
benchmark/single-source/SortLettersInPlace.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
//===--- SortLettersInPlace.swift -----------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance and correctness of Swift sortInPlace on an
|
||||
// array of letters.
|
||||
import Foundation
|
||||
import TestsUtils
|
||||
|
||||
class Letter {
|
||||
let value: String
|
||||
init(_ value: String) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_SortLettersInPlace(N: Int) {
|
||||
for _ in 1...100*N {
|
||||
var letters = [
|
||||
Letter("k"), Letter("a"), Letter("x"), Letter("i"), Letter("f"), Letter("l"),
|
||||
Letter("o"), Letter("w"), Letter("h"), Letter("p"), Letter("b"), Letter("u"),
|
||||
Letter("n"), Letter("c"), Letter("j"), Letter("t"), Letter("y"), Letter("s"),
|
||||
Letter("d"), Letter("v"), Letter("r"), Letter("e"), Letter("q"), Letter("m"),
|
||||
Letter("z"), Letter("g")
|
||||
]
|
||||
|
||||
// Sort the letters in place.
|
||||
letters.sort {
|
||||
return $0.value < $1.value
|
||||
}
|
||||
|
||||
// Check whether letters are sorted.
|
||||
CheckResults(letters[0].value <= letters[letters.count/2].value,
|
||||
"Incorrect results in SortLetterInPlace.")
|
||||
}
|
||||
}
|
||||
|
||||
1031
benchmark/single-source/SortStrings.swift
Normal file
1031
benchmark/single-source/SortStrings.swift
Normal file
File diff suppressed because it is too large
Load Diff
90
benchmark/single-source/StaticArray.swift
Normal file
90
benchmark/single-source/StaticArray.swift
Normal file
@@ -0,0 +1,90 @@
|
||||
//===--- StaticArray.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// We use this test to benchmark the compile time and analyze the code
|
||||
// generation of struct initializers.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
protocol StaticArrayProtocol {
|
||||
associatedtype ElemTy
|
||||
init(_ defaultValue : ElemTy)
|
||||
func get(idx : Int) -> ElemTy
|
||||
mutating func set(idx : Int,_ val : ElemTy)
|
||||
func count() -> Int
|
||||
}
|
||||
|
||||
struct A0<ElemTy> : StaticArrayProtocol {
|
||||
init(_ defaultValue : ElemTy) { x = defaultValue }
|
||||
var x : ElemTy
|
||||
func get(idx : Int) -> ElemTy { if idx == 0 { return x } else { fatalError("oob"); } }
|
||||
mutating func set(idx : Int,_ val : ElemTy) { if idx == 0 { x = val }}
|
||||
func count() -> Int { return 1}
|
||||
}
|
||||
|
||||
struct A2X<T : StaticArrayProtocol> : StaticArrayProtocol {
|
||||
init(_ defaultValue : T.ElemTy) { lower = T(defaultValue); upper = T(defaultValue) }
|
||||
var lower : T
|
||||
var upper : T
|
||||
func get(idx : Int) -> T.ElemTy { let size = lower.count(); if idx < size { return lower.get(idx) } else { return upper.get(idx - size) }}
|
||||
mutating func set(idx : Int,_ val : T.ElemTy) {let size = lower.count(); if idx < size { return lower.set(idx, val) } else { return upper.set(idx - size, val) }}
|
||||
func count() -> Int { return upper.count() + lower.count() }
|
||||
}
|
||||
|
||||
struct StaticArray<T : StaticArrayProtocol> : StaticArrayProtocol, MutableCollection {
|
||||
init(_ defaultValue : T.ElemTy) { values = T(defaultValue) }
|
||||
var values : T
|
||||
func get(idx : Int) -> T.ElemTy { return values.get(idx) }
|
||||
mutating func set(idx : Int,_ val : T.ElemTy) { return values.set(idx, val) }
|
||||
func count() -> Int { return values.count() }
|
||||
|
||||
typealias Index = Int
|
||||
let startIndex: Int = 0
|
||||
var endIndex: Int { return count()}
|
||||
|
||||
subscript(idx: Int) -> T.ElemTy {
|
||||
get {
|
||||
return get(idx)
|
||||
}
|
||||
set(val) {
|
||||
set(idx, val)
|
||||
}
|
||||
}
|
||||
|
||||
typealias Iterator = IndexingIterator<StaticArray>
|
||||
func iterator() -> Iterator { return Iterator(self) }
|
||||
}
|
||||
|
||||
typealias SA2Int = StaticArray<A0<Int>>
|
||||
typealias SA4Int = StaticArray<A2X<A0<Int>>>
|
||||
typealias SA8Int = StaticArray<A2X<A2X<A0<Int>>>>
|
||||
typealias SA16Int = StaticArray<A2X<A2X<A2X<A0<Int>>>>>
|
||||
typealias SA32Int = StaticArray<A2X<A2X<A2X<A2X<A0<Int>>>>>>
|
||||
typealias SA64Int = StaticArray<A2X<A2X<A2X<A2X<A2X<A0<Int>>>>>>>
|
||||
typealias SA128Int = StaticArray<A2X<A2X<A2X<A2X<A2X<A2X<A0<Int>>>>>>>>
|
||||
|
||||
// Make sure the optimizer does not optimize the compute away.
|
||||
@inline(never)
|
||||
public func sink(value: Int) { if False() { print(value) }}
|
||||
|
||||
|
||||
@inline(never)
|
||||
public func run_StaticArray(N: Int) {
|
||||
|
||||
for _ in 1...N {
|
||||
var staticArray = SA128Int(0)
|
||||
for i in 0..<staticArray.count() { staticArray[i] = i ^ 123 }
|
||||
staticArray.sort()
|
||||
sink(staticArray[0])
|
||||
}
|
||||
}
|
||||
27
benchmark/single-source/StrComplexWalk.swift
Normal file
27
benchmark/single-source/StrComplexWalk.swift
Normal file
@@ -0,0 +1,27 @@
|
||||
//===--- StrComplexWalk.swift ---------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_StrComplexWalk(N: Int) {
|
||||
var s = "निरन्तरान्धकारिता-दिगन्तर-कन्दलदमन्द-सुधारस-बिन्दु-सान्द्रतर-घनाघन-वृन्द-सन्देहकर-स्यन्दमान-मकरन्द-बिन्दु-बन्धुरतर-माकन्द-तरु-कुल-तल्प-कल्प-मृदुल-सिकता-जाल-जटिल-मूल-तल-मरुवक-मिलदलघु-लघु-लय-कलित-रमणीय-पानीय-शालिका-बालिका-करार-विन्द-गलन्तिका-गलदेला-लवङ्ग-पाटल-घनसार-कस्तूरिकातिसौरभ-मेदुर-लघुतर-मधुर-शीतलतर-सलिलधारा-निराकरिष्णु-तदीय-विमल-विलोचन-मयूख-रेखापसारित-पिपासायास-पथिक-लोकान्"
|
||||
let ref_result = 379
|
||||
for _ in 1...2000*N {
|
||||
var count = 0
|
||||
for _ in s.unicodeScalars {
|
||||
count += 1
|
||||
}
|
||||
CheckResults(count == ref_result, "Incorrect results in StrComplexWalk: \(count) != \(ref_result)")
|
||||
}
|
||||
}
|
||||
|
||||
47
benchmark/single-source/StrToInt.swift
Normal file
47
benchmark/single-source/StrToInt.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
//===--- StrToInt.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test checks performance of String to Int conversion.
|
||||
// It is reported to be very slow: <rdar://problem/17255477>
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_StrToInt(N: Int) {
|
||||
// 64 numbers from -500_000 to 500_000 generated randomly
|
||||
let input = ["-237392", "293715", "126809", "333779", "-362824", "144198",
|
||||
"-394973", "-163669", "-7236", "376965", "-400783", "-118670",
|
||||
"454728", "-38915", "136285", "-448481", "-499684", "68298",
|
||||
"382671", "105432", "-38385", "39422", "-267849", "-439886",
|
||||
"292690", "87017", "404692", "27692", "486408", "336482",
|
||||
"-67850", "56414", "-340902", "-391782", "414778", "-494338",
|
||||
"-413017", "-377452", "-300681", "170194", "428941", "-291665",
|
||||
"89331", "329496", "-364449", "272843", "-10688", "142542",
|
||||
"-417439", "167337", "96598", "-264104", "-186029", "98480",
|
||||
"-316727", "483808", "300149", "-405877", "-98938", "283685",
|
||||
"-247856", "-46975", "346060", "160085",]
|
||||
let ref_result = 517492
|
||||
func DoOneIter(arr: [String]) -> Int {
|
||||
var r = 0
|
||||
for n in arr {
|
||||
r += Int(n)!
|
||||
}
|
||||
if r < 0 {
|
||||
r = -r
|
||||
}
|
||||
return r
|
||||
}
|
||||
var res = Int.max
|
||||
for _ in 1...1000*N {
|
||||
res = res & DoOneIter(input)
|
||||
}
|
||||
CheckResults(res == ref_result, "IncorrectResults in StrToInt: \(res) != \(ref_result)")
|
||||
}
|
||||
30
benchmark/single-source/StringBuilder.swift
Normal file
30
benchmark/single-source/StringBuilder.swift
Normal file
@@ -0,0 +1,30 @@
|
||||
//===--- StringBuilder.swift ----------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
func buildString() -> String {
|
||||
var sb = "a"
|
||||
for str in ["b","c","d","pizza"] {
|
||||
sb += str
|
||||
}
|
||||
return sb
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_StringBuilder(N: Int) {
|
||||
for _ in 1...5000*N {
|
||||
buildString()
|
||||
}
|
||||
}
|
||||
|
||||
41
benchmark/single-source/StringInterpolation.swift
Normal file
41
benchmark/single-source/StringInterpolation.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//===--- StringInterpolation.swift ----------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
class RefTypePrintable : CustomStringConvertible {
|
||||
var description: String {
|
||||
return "01234567890123456789012345678901234567890123456789"
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_StringInterpolation(N: Int) {
|
||||
let reps = 100
|
||||
let refResult = reps
|
||||
let anInt: Int64 = 0x1234567812345678
|
||||
let aRefCountedObject = RefTypePrintable()
|
||||
|
||||
for _ in 1...100*N {
|
||||
var result = 0
|
||||
for _ in 1...reps {
|
||||
let s = "\(anInt) abcdefdhijklmn \(aRefCountedObject) abcdefdhijklmn \u{01}"
|
||||
|
||||
// FIXME: if String is not stored as UTF-16 on this platform, then the
|
||||
// following operation has a non-trivial cost and needs to be replaced
|
||||
// with an operation on the native storage type.
|
||||
result = result &+ Int(s.utf16[s.utf16.endIndex.predecessor()])
|
||||
}
|
||||
CheckResults(result == refResult, "IncorrectResults in StringInterpolation: \(result) != \(refResult)")
|
||||
}
|
||||
}
|
||||
|
||||
18
benchmark/single-source/StringTests.swift
Normal file
18
benchmark/single-source/StringTests.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
//===--- StringTests.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
public func run_StringWithCString(N: Int) {
|
||||
let str = String(repeating: "x" as UnicodeScalar, count: 100 * (1 << 16))
|
||||
for _ in 0 ..< N {
|
||||
str.withCString { _ in }
|
||||
}
|
||||
}
|
||||
38
benchmark/single-source/StringWalk.swift
Normal file
38
benchmark/single-source/StringWalk.swift
Normal file
@@ -0,0 +1,38 @@
|
||||
//===--- StringWalk.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Test String subscript performance.
|
||||
//
|
||||
// Subscript has a slow path that initializes a global variable:
|
||||
// Swift._cocoaStringSubscript.addressor. Global optimization would
|
||||
// normally hoist the initializer outside the inner loop (over
|
||||
// unicodeScalars), forcing the initializer to be called on each
|
||||
// lap. However, no that the cocoa code is properly marked "slowPath",
|
||||
// no hoisting should occur.
|
||||
import TestsUtils
|
||||
|
||||
var count: Int = 0
|
||||
|
||||
@inline(never) func countChars(s: String) {
|
||||
for _ in s.unicodeScalars {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_StringWalk(N: Int) {
|
||||
let s = "siebenhundertsiebenundsiebzigtausendsiebenhundertsiebenundsiebzig"
|
||||
|
||||
for _ in 1...50000*N {
|
||||
countChars(s)
|
||||
}
|
||||
}
|
||||
42
benchmark/single-source/SuperChars.swift
Normal file
42
benchmark/single-source/SuperChars.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
//===--- SuperChars.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test tests the performance of ASCII Character comparison.
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_SuperChars(N: Int) {
|
||||
// Permute some characters.
|
||||
let alphabet: [Character] = [
|
||||
"A", "B", "C", "D", "E", "F", "G",
|
||||
"«", // throw in some unicode to make it slower
|
||||
"H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
|
||||
"á", "お",
|
||||
"S", "T", "U",
|
||||
"🇯🇵",
|
||||
"V", "W", "X", "Y", "Z", "/", "f", "Z", "z", "6", "7", "C", "j", "f", "9",
|
||||
"🇯🇵🇺🇸", "🇯🇵🇺🇸🇨🇳", "🇯🇵🇺🇸🇨🇳🇩🇪",
|
||||
"g", "g", "I", "J", "K", "c", "x", "i", ".",
|
||||
"🇯🇵🇺🇸🇨🇳🇩🇪", "🇯🇵🇺🇸", "🇯🇵🇺🇸🇨🇳",
|
||||
"2", "a", "t", "i", "o", "e", "q", "n", "X", "Y", "Z", "?", "m", "Z", ","
|
||||
]
|
||||
|
||||
for _ in 0...N {
|
||||
for firstChar in alphabet {
|
||||
for middleChar in alphabet {
|
||||
for lastChar in alphabet {
|
||||
_ = ((firstChar == middleChar) != (middleChar < lastChar))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
benchmark/single-source/TwoSum.swift
Normal file
79
benchmark/single-source/TwoSum.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//===--- TwoSum.swift -----------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This test is solves 2SUM problem:
|
||||
// Given an array and a number C, find elements A and B such that A+B = C
|
||||
import TestsUtils
|
||||
|
||||
let array = [
|
||||
959, 81, 670, 727, 416, 171, 401, 398, 707, 596, 200, 9, 414, 98, 43,
|
||||
352, 752, 158, 593, 418, 240, 912, 542, 445, 429, 456, 993, 618, 52, 649,
|
||||
759, 190, 126, 306, 966, 37, 787, 981, 606, 372, 597, 901, 158, 284, 809,
|
||||
820, 173, 538, 644, 428, 932, 967, 962, 959, 233, 467, 220, 8, 729, 889,
|
||||
277, 494, 554, 670, 91, 657, 606, 248, 644, 8, 366, 815, 567, 993, 696,
|
||||
763, 800, 531, 301, 863, 680, 703, 279, 388, 871, 124, 302, 617, 410, 366,
|
||||
813, 599, 543, 508, 336, 312, 212, 86, 524, 64, 641, 533, 207, 893, 146,
|
||||
534, 104, 888, 534, 464, 423, 583, 365, 420, 642, 514, 336, 974, 846, 437,
|
||||
604, 121, 180, 794, 278, 467, 818, 603, 537, 167, 169, 704, 9, 843, 555,
|
||||
154, 598, 566, 676, 682, 828, 128, 875, 445, 918, 505, 393, 571, 3, 406,
|
||||
719, 165, 505, 750, 396, 726, 404, 391, 532, 403, 728, 240, 89, 917, 665,
|
||||
561, 282, 302, 438, 714, 6, 290, 939, 200, 788, 128, 773, 900, 934, 772,
|
||||
130, 884, 60, 870, 812, 750, 349, 35, 155, 905, 595, 806, 771, 443, 304,
|
||||
283, 404, 905, 861, 820, 338, 380, 709, 927, 42, 478, 789, 656, 106, 218,
|
||||
412, 453, 262, 864, 701, 686, 770, 34, 624, 597, 843, 913, 966, 230, 942,
|
||||
112, 991, 299, 669, 399, 630, 943, 934, 448, 62, 745, 917, 397, 440, 286,
|
||||
875, 22, 989, 235, 732, 906, 923, 643, 853, 68, 48, 524, 86, 89, 688,
|
||||
224, 546, 73, 963, 755, 413, 524, 680, 472, 19, 996, 81, 100, 338, 626,
|
||||
911, 358, 887, 242, 159, 731, 494, 985, 83, 597, 98, 270, 909, 828, 988,
|
||||
684, 622, 499, 932, 299, 449, 888, 533, 801, 844, 940, 642, 501, 513, 735,
|
||||
674, 211, 394, 635, 372, 213, 618, 280, 792, 487, 605, 755, 584, 163, 358,
|
||||
249, 784, 153, 166, 685, 264, 457, 677, 824, 391, 830, 310, 629, 591, 62,
|
||||
265, 373, 195, 803, 756, 601, 592, 843, 184, 220, 155, 396, 828, 303, 553,
|
||||
778, 477, 735, 430, 93, 464, 306, 579, 828, 759, 809, 916, 759, 336, 926,
|
||||
776, 111, 746, 217, 585, 441, 928, 236, 959, 417, 268, 200, 231, 181, 228,
|
||||
627, 675, 814, 534, 90, 665, 1, 604, 479, 598, 109, 370, 719, 786, 700,
|
||||
591, 536, 7, 147, 648, 864, 162, 404, 536, 768, 175, 517, 394, 14, 945,
|
||||
865, 490, 630, 963, 49, 904, 277, 16, 349, 301, 840, 817, 590, 738, 357,
|
||||
199, 581, 601, 33, 659, 951, 640, 126, 302, 632, 265, 894, 892, 587, 274,
|
||||
487, 499, 789, 954, 652, 825, 512, 170, 882, 269, 471, 571, 185, 364, 217,
|
||||
427, 38, 715, 950, 808, 270, 746, 830, 501, 264, 581, 211, 466, 970, 395,
|
||||
610, 930, 885, 696, 568, 920, 487, 764, 896, 903, 241, 894, 773, 896, 341,
|
||||
126, 22, 420, 959, 691, 207, 745, 126, 873, 341, 166, 127, 108, 426, 497,
|
||||
681, 796, 430, 367, 363
|
||||
]
|
||||
|
||||
@inline(never)
|
||||
public func run_TwoSum(N: Int) {
|
||||
var i1: Int?
|
||||
var i2: Int?
|
||||
var Dict: Dictionary<Int, Int> = [:]
|
||||
for _ in 1...2*N {
|
||||
for Sum in 500..<600 {
|
||||
Dict = [:]
|
||||
i1 = nil
|
||||
i2 = nil
|
||||
for n in 0..<array.count {
|
||||
if let m = Dict[Sum-array[n]] {
|
||||
i1 = m
|
||||
i2 = n
|
||||
break
|
||||
}
|
||||
Dict[array[n]] = n
|
||||
}
|
||||
CheckResults(i1 != nil && i2 != nil,
|
||||
"Incorrect results in TwoSum: i1 or i2 wasn't found.")
|
||||
CheckResults(Sum == array[i1!] + array[i2!],
|
||||
"Incorrect results in TwoSum: Sum: \(Sum), " +
|
||||
"array[i1]: \(array[i1!]), array[i2]: \(array[i2!]).")
|
||||
}
|
||||
}
|
||||
}
|
||||
110
benchmark/single-source/TypeFlood.swift
Normal file
110
benchmark/single-source/TypeFlood.swift
Normal file
@@ -0,0 +1,110 @@
|
||||
//===--- TypeFlood.swift --------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// We use this test to benchmark the runtime memory that Swift programs use.
|
||||
//
|
||||
// The Swift compiler caches the metadata that it needs to generate to support
|
||||
// code that checks for protocol conformance and other operations that require
|
||||
// use of metadata.
|
||||
// This mechanism has the potential to allocate a lot of memory. This benchmark
|
||||
// program generates 2^15 calls to swift_conformsToProtocol and fills the
|
||||
// metadata/conformance caches with data that we never free. We use this
|
||||
// program to track the runtime memory usage of swift programs. The test is
|
||||
// optimized away in Release builds but kept in Debug mode.
|
||||
|
||||
|
||||
import TestsUtils
|
||||
protocol Pingable {}
|
||||
|
||||
struct Some1<T> {
|
||||
init() {}
|
||||
func foo(x: T) {}
|
||||
}
|
||||
struct Some0<T> {
|
||||
init() {}
|
||||
func foo(x: T) {}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func flood<T>(x : T) {
|
||||
Some1<Some1<Some1<Some1<T>>>>() is Pingable
|
||||
Some1<Some1<Some1<Some0<T>>>>() is Pingable
|
||||
Some1<Some1<Some0<Some1<T>>>>() is Pingable
|
||||
Some1<Some1<Some0<Some0<T>>>>() is Pingable
|
||||
Some1<Some0<Some1<Some1<T>>>>() is Pingable
|
||||
Some1<Some0<Some1<Some0<T>>>>() is Pingable
|
||||
Some1<Some0<Some0<Some1<T>>>>() is Pingable
|
||||
Some1<Some0<Some0<Some0<T>>>>() is Pingable
|
||||
Some0<Some1<Some1<Some1<T>>>>() is Pingable
|
||||
Some0<Some1<Some1<Some0<T>>>>() is Pingable
|
||||
Some0<Some1<Some0<Some1<T>>>>() is Pingable
|
||||
Some0<Some1<Some0<Some0<T>>>>() is Pingable
|
||||
Some0<Some0<Some1<Some1<T>>>>() is Pingable
|
||||
Some0<Some0<Some1<Some0<T>>>>() is Pingable
|
||||
Some0<Some0<Some0<Some1<T>>>>() is Pingable
|
||||
Some0<Some0<Some0<Some0<T>>>>() is Pingable
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func flood3<T>(x : T) {
|
||||
flood(Some1<Some1<Some1<Some1<T>>>>())
|
||||
flood(Some1<Some1<Some1<Some0<T>>>>())
|
||||
flood(Some1<Some1<Some0<Some1<T>>>>())
|
||||
flood(Some1<Some1<Some0<Some0<T>>>>())
|
||||
flood(Some1<Some0<Some1<Some1<T>>>>())
|
||||
flood(Some1<Some0<Some1<Some0<T>>>>())
|
||||
flood(Some1<Some0<Some0<Some1<T>>>>())
|
||||
flood(Some1<Some0<Some0<Some0<T>>>>())
|
||||
flood(Some0<Some1<Some1<Some1<T>>>>())
|
||||
flood(Some0<Some1<Some1<Some0<T>>>>())
|
||||
flood(Some0<Some1<Some0<Some1<T>>>>())
|
||||
flood(Some0<Some1<Some0<Some0<T>>>>())
|
||||
flood(Some0<Some0<Some1<Some1<T>>>>())
|
||||
flood(Some0<Some0<Some1<Some0<T>>>>())
|
||||
flood(Some0<Some0<Some0<Some1<T>>>>())
|
||||
flood(Some0<Some0<Some0<Some0<T>>>>())
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
func flood2<T>(x : T) {
|
||||
flood3(Some1<Some1<Some1<Some1<T>>>>())
|
||||
flood3(Some1<Some1<Some1<Some0<T>>>>())
|
||||
flood3(Some1<Some1<Some0<Some1<T>>>>())
|
||||
flood3(Some1<Some1<Some0<Some0<T>>>>())
|
||||
flood3(Some1<Some0<Some1<Some1<T>>>>())
|
||||
flood3(Some1<Some0<Some1<Some0<T>>>>())
|
||||
flood3(Some1<Some0<Some0<Some1<T>>>>())
|
||||
flood3(Some1<Some0<Some0<Some0<T>>>>())
|
||||
flood3(Some0<Some1<Some1<Some1<T>>>>())
|
||||
flood3(Some0<Some1<Some1<Some0<T>>>>())
|
||||
flood3(Some0<Some1<Some0<Some1<T>>>>())
|
||||
flood3(Some0<Some1<Some0<Some0<T>>>>())
|
||||
flood3(Some0<Some0<Some1<Some1<T>>>>())
|
||||
flood3(Some0<Some0<Some1<Some0<T>>>>())
|
||||
flood3(Some0<Some0<Some0<Some1<T>>>>())
|
||||
flood3(Some0<Some0<Some0<Some0<T>>>>())
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_TypeFlood(N: Int) {
|
||||
|
||||
for _ in 1...N {
|
||||
flood3(Some1<Some1<Some1<Int>>>())
|
||||
flood3(Some1<Some1<Some0<Int>>>())
|
||||
flood3(Some1<Some0<Some1<Int>>>())
|
||||
flood3(Some1<Some0<Some0<Int>>>())
|
||||
flood3(Some0<Some1<Some1<Int>>>())
|
||||
flood3(Some0<Some1<Some0<Int>>>())
|
||||
flood3(Some0<Some0<Some1<Int>>>())
|
||||
flood3(Some0<Some0<Some0<Int>>>())
|
||||
}
|
||||
}
|
||||
83
benchmark/single-source/Walsh.swift
Normal file
83
benchmark/single-source/Walsh.swift
Normal file
@@ -0,0 +1,83 @@
|
||||
//===--- Walsh.swift ------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
import Darwin
|
||||
|
||||
func IsPowerOfTwo(x: Int) -> Bool { return (x & (x - 1)) == 0 }
|
||||
|
||||
//Fast Walsh Hadamard Transform
|
||||
func WalshTransform(inout data: [Double]) {
|
||||
assert(IsPowerOfTwo(data.count), "Not a power of two")
|
||||
var temp = [Double](repeating: 0, count: data.count)
|
||||
var ret = WalshImpl(&data, &temp, 0, data.count)
|
||||
for i in 0..<data.count {
|
||||
data[i] = ret[i]
|
||||
}
|
||||
}
|
||||
|
||||
func Scale(inout data : [Double], _ scalar : Double) {
|
||||
for i in 0..<data.count {
|
||||
data[i] = data[i] * scalar
|
||||
}
|
||||
}
|
||||
|
||||
func InverseWalshTransform(inout data: [Double]) {
|
||||
WalshTransform(&data)
|
||||
Scale(&data, Double(1)/Double(data.count))
|
||||
}
|
||||
|
||||
func WalshImpl(inout data: [Double], inout _ temp: [Double], _ start: Int, _ size: Int) -> [Double] {
|
||||
if (size == 1) { return data }
|
||||
|
||||
let stride = size/2
|
||||
for i in 0..<stride {
|
||||
temp[start + i] = data[start + i + stride] + data[start + i]
|
||||
temp[start + i + stride] = data[start + i] - data[start + i + stride]
|
||||
}
|
||||
|
||||
WalshImpl(&temp, &data, start, stride)
|
||||
return WalshImpl(&temp, &data, start + stride, stride)
|
||||
}
|
||||
|
||||
func checkCorrectness() {
|
||||
var In : [Double] = [1,0,1,0,0,1,1,0]
|
||||
var Out : [Double] = [4,2,0,-2,0,2,0,2]
|
||||
var data : [Double] = In
|
||||
WalshTransform(&data)
|
||||
var mid = data
|
||||
InverseWalshTransform(&data)
|
||||
for i in 0..<In.count {
|
||||
// Check encode.
|
||||
CheckResults(abs(data[i] - In[i]) < 0.0001, "Incorrect results in Walsh.")
|
||||
// Check decode.
|
||||
CheckResults(abs(mid[i] - Out[i]) < 0.0001, "Incorrect results in Walsh.")
|
||||
}
|
||||
}
|
||||
|
||||
@inline(never)
|
||||
public func run_Walsh(N : Int) {
|
||||
checkCorrectness()
|
||||
|
||||
// Generate data.
|
||||
var data2 : [Double] = []
|
||||
for i in 0..<1024 {
|
||||
data2.append(Double(sin(Float(i))))
|
||||
}
|
||||
|
||||
// Transform back and forth.
|
||||
for _ in 1...10*N {
|
||||
WalshTransform(&data2)
|
||||
InverseWalshTransform(&data2)
|
||||
}
|
||||
}
|
||||
|
||||
28
benchmark/single-source/XorLoop.swift
Normal file
28
benchmark/single-source/XorLoop.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//===--- XorLoop.swift ----------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import TestsUtils
|
||||
|
||||
@inline(never)
|
||||
public func run_XorLoop(N: Int) {
|
||||
for _ in 1...5*N {
|
||||
let size = 100000
|
||||
let ref_result = 47813324
|
||||
var x = [Int](repeating: 0xA05FD, count: size)
|
||||
for i in 0..<size {
|
||||
x[i] = x[i] ^ 12345678
|
||||
}
|
||||
let res = x[10]+x[100]+x[1000]+x[10000]
|
||||
CheckResults(res == ref_result,
|
||||
"Incorrect results in XorLoop: \(res) != \(ref_result)")
|
||||
}
|
||||
}
|
||||
78
benchmark/utils/ArgParse.swift
Normal file
78
benchmark/utils/ArgParse.swift
Normal file
@@ -0,0 +1,78 @@
|
||||
//===--- ArgParse.swift ---------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct Arguments {
|
||||
public var progName: String
|
||||
public var positionalArgs: [String]
|
||||
public var optionalArgsMap: [String : String]
|
||||
|
||||
init(_ pName: String, _ posArgs: [String], _ optArgsMap: [String : String]) {
|
||||
progName = pName
|
||||
positionalArgs = posArgs
|
||||
optionalArgsMap = optArgsMap
|
||||
}
|
||||
}
|
||||
|
||||
/// Using Process.arguments, returns an Arguments struct describing
|
||||
/// the arguments to this program. If we fail to parse arguments, we
|
||||
/// return .None.
|
||||
///
|
||||
/// We assume that optional switch args are of the form:
|
||||
///
|
||||
/// --opt-name[=opt-value]
|
||||
/// -opt-name[=opt-value]
|
||||
///
|
||||
/// with opt-name and opt-value not containing any '=' signs. Any
|
||||
/// other option passed in is assumed to be a positional argument.
|
||||
public func parseArgs(validOptions: [String]? = .None)
|
||||
-> Arguments? {
|
||||
let progName = Process.arguments[0]
|
||||
var positionalArgs = [String]()
|
||||
var optionalArgsMap = [String : String]()
|
||||
|
||||
// For each argument we are passed...
|
||||
var passThroughArgs = false
|
||||
for arg in Process.arguments[1..<Process.arguments.count] {
|
||||
// If the argument doesn't match the optional argument pattern. Add
|
||||
// it to the positional argument list and continue...
|
||||
if passThroughArgs || !arg.characters.startsWith("-".characters) {
|
||||
positionalArgs.append(arg)
|
||||
continue
|
||||
}
|
||||
if arg == "--" {
|
||||
passThroughArgs = true
|
||||
continue
|
||||
}
|
||||
// Attempt to split it into two components separated by an equals sign.
|
||||
let components = arg.componentsSeparatedBy("=")
|
||||
let optionName = components[0]
|
||||
if validOptions != nil && !validOptions!.contains(optionName) {
|
||||
print("Invalid option: \(arg)")
|
||||
return .None
|
||||
}
|
||||
var optionVal : String
|
||||
switch components.count {
|
||||
case 1: optionVal = ""
|
||||
case 2: optionVal = components[1]
|
||||
default:
|
||||
// If we do not have two components at this point, we can not have
|
||||
// an option switch. This is an invalid argument. Bail!
|
||||
print("Invalid option: \(arg)")
|
||||
return .None
|
||||
}
|
||||
optionalArgsMap[optionName] = optionVal
|
||||
}
|
||||
|
||||
return .Some(Arguments(progName, positionalArgs, optionalArgsMap))
|
||||
}
|
||||
366
benchmark/utils/DriverUtils.swift
Normal file
366
benchmark/utils/DriverUtils.swift
Normal file
@@ -0,0 +1,366 @@
|
||||
//===--- DriverUtils.swift ------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Darwin
|
||||
|
||||
struct BenchResults {
|
||||
var delim: String = ","
|
||||
var sampleCount: UInt64 = 0
|
||||
var min: UInt64 = 0
|
||||
var max: UInt64 = 0
|
||||
var mean: UInt64 = 0
|
||||
var sd: UInt64 = 0
|
||||
var median: UInt64 = 0
|
||||
init() {}
|
||||
init(delim: String, sampleCount: UInt64, min: UInt64, max: UInt64, mean: UInt64, sd: UInt64, median: UInt64) {
|
||||
self.delim = delim
|
||||
self.sampleCount = sampleCount
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.mean = mean
|
||||
self.sd = sd
|
||||
self.median = median
|
||||
}
|
||||
}
|
||||
|
||||
extension BenchResults : CustomStringConvertible {
|
||||
var description: String {
|
||||
return "\(sampleCount)\(delim)\(min)\(delim)\(max)\(delim)\(mean)\(delim)\(sd)\(delim)\(median)"
|
||||
}
|
||||
}
|
||||
|
||||
struct Test {
|
||||
let name: String
|
||||
let index: Int
|
||||
let f: (Int)->()
|
||||
var run: Bool
|
||||
init(name: String, n: Int, f: (Int)->()) {
|
||||
self.name = name
|
||||
self.index = n
|
||||
self.f = f
|
||||
run = true
|
||||
}
|
||||
}
|
||||
|
||||
public var precommitTests: [String : (Int)->()] = [:]
|
||||
public var otherTests: [String : (Int)->()] = [:]
|
||||
|
||||
enum TestAction {
|
||||
case Run
|
||||
case ListTests
|
||||
case Fail(String)
|
||||
}
|
||||
|
||||
struct TestConfig {
|
||||
/// The delimiter to use when printing output.
|
||||
var delim: String = ","
|
||||
|
||||
/// The filters applied to our test names.
|
||||
var filters = [String]()
|
||||
|
||||
/// The scalar multiple of the amount of times a test should be run. This
|
||||
/// enables one to cause tests to run for N iterations longer than they
|
||||
/// normally would. This is useful when one wishes for a test to run for a
|
||||
/// longer amount of time to perform performance analysis on the test in
|
||||
/// instruments.
|
||||
var iterationScale: Int = 1
|
||||
|
||||
/// If we are asked to have a fixed number of iterations, the number of fixed
|
||||
/// iterations.
|
||||
var fixedNumIters: UInt = 0
|
||||
|
||||
/// The number of samples we should take of each test.
|
||||
var numSamples: Int = 1
|
||||
|
||||
/// Is verbose output enabled?
|
||||
var verbose: Bool = false
|
||||
|
||||
/// Should we only run the "pre-commit" tests?
|
||||
var onlyPrecommit: Bool = true
|
||||
|
||||
/// After we run the tests, should the harness sleep to allow for utilities
|
||||
/// like leaks that require a PID to run on the test harness.
|
||||
var afterRunSleep: Int? = .None
|
||||
|
||||
/// The list of tests to run.
|
||||
var tests = [Test]()
|
||||
|
||||
mutating func processArguments() -> TestAction {
|
||||
let validOptions=["--iter-scale", "--num-samples", "--num-iters",
|
||||
"--verbose", "--delim", "--run-all", "--list", "--sleep"]
|
||||
let maybeBenchArgs: Arguments? = parseArgs(.Some(validOptions))
|
||||
if maybeBenchArgs == nil {
|
||||
return .Fail("Failed to parse arguments")
|
||||
}
|
||||
let benchArgs = maybeBenchArgs!
|
||||
|
||||
if let _ = benchArgs.optionalArgsMap["--list"] {
|
||||
return .ListTests
|
||||
}
|
||||
|
||||
if let x = benchArgs.optionalArgsMap["--iter-scale"] {
|
||||
if x.isEmpty { return .Fail("--iter-scale requires a value") }
|
||||
iterationScale = Int(x)!
|
||||
}
|
||||
|
||||
if let x = benchArgs.optionalArgsMap["--num-iters"] {
|
||||
if x.isEmpty { return .Fail("--num-iters requires a value") }
|
||||
fixedNumIters = numericCast(Int(x)!)
|
||||
}
|
||||
|
||||
if let x = benchArgs.optionalArgsMap["--num-samples"] {
|
||||
if x.isEmpty { return .Fail("--num-samples requires a value") }
|
||||
numSamples = Int(x)!
|
||||
}
|
||||
|
||||
if let _ = benchArgs.optionalArgsMap["--verbose"] {
|
||||
verbose = true
|
||||
print("Verbose")
|
||||
}
|
||||
|
||||
if let x = benchArgs.optionalArgsMap["--delim"] {
|
||||
if x.isEmpty { return .Fail("--delim requires a value") }
|
||||
delim = x
|
||||
}
|
||||
|
||||
if let _ = benchArgs.optionalArgsMap["--run-all"] {
|
||||
onlyPrecommit = false
|
||||
}
|
||||
|
||||
if let x = benchArgs.optionalArgsMap["--sleep"] {
|
||||
if x.isEmpty {
|
||||
return .Fail("--sleep requires a non-empty integer value")
|
||||
}
|
||||
let v: Int? = Int(x)
|
||||
if v == nil {
|
||||
return .Fail("--sleep requires a non-empty integer value")
|
||||
}
|
||||
afterRunSleep = v!
|
||||
}
|
||||
|
||||
filters = benchArgs.positionalArgs
|
||||
|
||||
return .Run
|
||||
}
|
||||
|
||||
mutating func findTestsToRun() {
|
||||
var i = 1
|
||||
for benchName in precommitTests.keys.sorted() {
|
||||
tests.append(Test(name: benchName, n: i, f: precommitTests[benchName]!))
|
||||
i += 1
|
||||
}
|
||||
for benchName in otherTests.keys.sorted() {
|
||||
tests.append(Test(name: benchName, n: i, f: otherTests[benchName]!))
|
||||
i += 1
|
||||
}
|
||||
for i in 0..<tests.count {
|
||||
if onlyPrecommit && precommitTests[tests[i].name] == nil {
|
||||
tests[i].run = false
|
||||
}
|
||||
if !filters.isEmpty &&
|
||||
!filters.contains(String(tests[i].index)) &&
|
||||
!filters.contains(tests[i].name) {
|
||||
tests[i].run = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func internalMeanSD(inputs: [UInt64]) -> (UInt64, UInt64) {
|
||||
// If we are empty, return 0, 0.
|
||||
if inputs.isEmpty {
|
||||
return (0, 0)
|
||||
}
|
||||
|
||||
// If we have one element, return elt, 0.
|
||||
if inputs.count == 1 {
|
||||
return (inputs[0], 0)
|
||||
}
|
||||
|
||||
// Ok, we have 2 elements.
|
||||
|
||||
var sum1: UInt64 = 0
|
||||
var sum2: UInt64 = 0
|
||||
|
||||
for i in inputs {
|
||||
sum1 += i
|
||||
}
|
||||
|
||||
let mean: UInt64 = sum1 / UInt64(inputs.count)
|
||||
|
||||
for i in inputs {
|
||||
sum2 = sum2 &+ UInt64((Int64(i) &- Int64(mean))&*(Int64(i) &- Int64(mean)))
|
||||
}
|
||||
|
||||
return (mean, UInt64(sqrt(Double(sum2)/(Double(inputs.count) - 1))))
|
||||
}
|
||||
|
||||
func internalMedian(inputs: [UInt64]) -> UInt64 {
|
||||
return inputs.sorted()[inputs.count / 2]
|
||||
}
|
||||
|
||||
#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
|
||||
|
||||
@_silgen_name("swift_leaks_startTrackingObjects")
|
||||
func startTrackingObjects(_: UnsafeMutablePointer<Void>) -> ()
|
||||
@_silgen_name("swift_leaks_stopTrackingObjects")
|
||||
func stopTrackingObjects(_: UnsafeMutablePointer<Void>) -> Int
|
||||
|
||||
#endif
|
||||
|
||||
class SampleRunner {
|
||||
var info = mach_timebase_info_data_t(numer: 0, denom: 0)
|
||||
init() {
|
||||
mach_timebase_info(&info)
|
||||
}
|
||||
func run(name: String, fn: (Int) -> Void, num_iters: UInt) -> UInt64 {
|
||||
// Start the timer.
|
||||
#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
|
||||
var str = name
|
||||
startTrackingObjects(UnsafeMutablePointer<Void>(str._core.startASCII))
|
||||
#endif
|
||||
let start_ticks = mach_absolute_time()
|
||||
fn(Int(num_iters))
|
||||
// Stop the timer.
|
||||
let end_ticks = mach_absolute_time()
|
||||
#if SWIFT_RUNTIME_ENABLE_LEAK_CHECKER
|
||||
stopTrackingObjects(UnsafeMutablePointer<Void>(str._core.startASCII))
|
||||
#endif
|
||||
|
||||
// Compute the spent time and the scaling factor.
|
||||
let elapsed_ticks = end_ticks - start_ticks
|
||||
return elapsed_ticks * UInt64(info.numer) / UInt64(info.denom)
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoke the benchmark entry point and return the run time in milliseconds.
|
||||
func runBench(name: String, _ fn: (Int) -> Void, _ c: TestConfig) -> BenchResults {
|
||||
|
||||
var samples = [UInt64](repeating: 0, count: c.numSamples)
|
||||
|
||||
if c.verbose {
|
||||
print("Running \(name) for \(c.numSamples) samples.")
|
||||
}
|
||||
|
||||
let sampler = SampleRunner()
|
||||
for s in 0..<c.numSamples {
|
||||
let time_per_sample: UInt64 = 1_000_000_000 * UInt64(c.iterationScale)
|
||||
|
||||
var scale : UInt
|
||||
var elapsed_time : UInt64 = 0
|
||||
if c.fixedNumIters == 0 {
|
||||
elapsed_time = sampler.run(name, fn: fn, num_iters: 1)
|
||||
scale = UInt(time_per_sample / elapsed_time)
|
||||
} else {
|
||||
// Compute the scaling factor if a fixed c.fixedNumIters is not specified.
|
||||
scale = c.fixedNumIters
|
||||
}
|
||||
|
||||
// Rerun the test with the computed scale factor.
|
||||
if scale > 1 {
|
||||
if c.verbose {
|
||||
print(" Measuring with scale \(scale).")
|
||||
}
|
||||
elapsed_time = sampler.run(name, fn: fn, num_iters: scale)
|
||||
} else {
|
||||
scale = 1
|
||||
}
|
||||
// save result in microseconds or k-ticks
|
||||
samples[s] = elapsed_time / UInt64(scale) / 1000
|
||||
if c.verbose {
|
||||
print(" Sample \(s),\(samples[s])")
|
||||
}
|
||||
}
|
||||
|
||||
let (mean, sd) = internalMeanSD(samples)
|
||||
|
||||
// Return our benchmark results.
|
||||
return BenchResults(delim: c.delim, sampleCount: UInt64(samples.count),
|
||||
min: samples.min()!, max: samples.max()!,
|
||||
mean: mean, sd: sd, median: internalMedian(samples))
|
||||
}
|
||||
|
||||
func printRunInfo(c: TestConfig) {
|
||||
if c.verbose {
|
||||
print("--- CONFIG ---")
|
||||
print("NumSamples: \(c.numSamples)")
|
||||
print("Verbose: \(c.verbose)")
|
||||
print("IterScale: \(c.iterationScale)")
|
||||
if c.fixedNumIters != 0 {
|
||||
print("FixedIters: \(c.fixedNumIters)")
|
||||
}
|
||||
print("Tests Filter: \(c.filters)")
|
||||
print("Tests to run: ", terminator: "")
|
||||
for t in c.tests {
|
||||
if t.run {
|
||||
print("\(t.name), ", terminator: "")
|
||||
}
|
||||
}
|
||||
print("")
|
||||
print("")
|
||||
print("--- DATA ---")
|
||||
}
|
||||
}
|
||||
|
||||
func runBenchmarks(c: TestConfig) {
|
||||
let units = "us"
|
||||
print("#\(c.delim)TEST\(c.delim)SAMPLES\(c.delim)MIN(\(units))\(c.delim)MAX(\(units))\(c.delim)MEAN(\(units))\(c.delim)SD(\(units))\(c.delim)MEDIAN(\(units))")
|
||||
var SumBenchResults = BenchResults()
|
||||
SumBenchResults.sampleCount = 0
|
||||
|
||||
for t in c.tests {
|
||||
if !t.run {
|
||||
continue
|
||||
}
|
||||
let BenchIndex = t.index
|
||||
let BenchName = t.name
|
||||
let BenchFunc = t.f
|
||||
let results = runBench(BenchName, BenchFunc, c)
|
||||
print("\(BenchIndex)\(c.delim)\(BenchName)\(c.delim)\(results.description)")
|
||||
fflush(stdout)
|
||||
|
||||
SumBenchResults.min += results.min
|
||||
SumBenchResults.max += results.max
|
||||
SumBenchResults.mean += results.mean
|
||||
SumBenchResults.sampleCount += 1
|
||||
// Don't accumulate SD and Median, as simple sum isn't valid for them.
|
||||
// TODO: Compute SD and Median for total results as well.
|
||||
// SumBenchResults.sd += results.sd
|
||||
// SumBenchResults.median += results.median
|
||||
}
|
||||
|
||||
print("")
|
||||
print("Totals\(c.delim)\(SumBenchResults.description)")
|
||||
}
|
||||
|
||||
public func main() {
|
||||
var config = TestConfig()
|
||||
|
||||
switch (config.processArguments()) {
|
||||
case let .Fail(msg):
|
||||
// We do this since we need an autoclosure...
|
||||
fatalError("\(msg)")
|
||||
case .ListTests:
|
||||
config.findTestsToRun()
|
||||
print("Enabled Tests:")
|
||||
for t in config.tests {
|
||||
print(" \(t.name)")
|
||||
}
|
||||
case .Run:
|
||||
config.findTestsToRun()
|
||||
printRunInfo(config)
|
||||
runBenchmarks(config)
|
||||
if let x = config.afterRunSleep {
|
||||
sleep(UInt32(x))
|
||||
}
|
||||
}
|
||||
}
|
||||
65
benchmark/utils/TestsUtils.swift
Normal file
65
benchmark/utils/TestsUtils.swift
Normal file
@@ -0,0 +1,65 @@
|
||||
//===--- TestsUtils.swift -------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Darwin
|
||||
|
||||
// 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.
|
||||
struct LFSR {
|
||||
// Set the register to some seed that I pulled out of a hat.
|
||||
var lfsr : UInt32 = 0xb78978e7
|
||||
|
||||
mutating func shift() {
|
||||
lfsr = (lfsr >> 1) ^ (UInt32(bitPattern: -Int32((lfsr & 1))) & 0xD0000001)
|
||||
}
|
||||
mutating func randInt() -> 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
|
||||
public func SRand() {
|
||||
lfsrRandomGenerator = LFSR()
|
||||
}
|
||||
|
||||
public func Random() -> Int64 {
|
||||
return lfsrRandomGenerator.randInt()
|
||||
}
|
||||
|
||||
public func CheckResults(res: Bool, _ message: String = "") {
|
||||
if res {
|
||||
return
|
||||
}
|
||||
print(message)
|
||||
abort()
|
||||
}
|
||||
|
||||
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() }
|
||||
|
||||
88
benchmark/utils/convertToJSON.py
Normal file
88
benchmark/utils/convertToJSON.py
Normal file
@@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ===--- convertToJSON.py -------------------------------------------------===//
|
||||
#
|
||||
# This source file is part of the Swift.org open source project
|
||||
#
|
||||
# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
# Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
#
|
||||
# See http://swift.org/LICENSE.txt for license information
|
||||
# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
#
|
||||
# ===----------------------------------------------------------------------===//
|
||||
|
||||
# This script converts results from pre-commit benchmark tests to JSON.
|
||||
# Usage: PrecommitBench_O | convertToJSON.py
|
||||
#
|
||||
# Input example:
|
||||
# #,TEST,SAMPLES,MIN(ms),MAX(ms),MEAN(ms),SD(ms),MEDIAN(ms)
|
||||
# 1,2Sum,1,1318,1318,1318,0,1318
|
||||
# 2,Ackermann,1,805,805,805,0,805
|
||||
#
|
||||
# Totals,2,2123,2123,2123,0,0
|
||||
#
|
||||
# Output for this input:
|
||||
# {
|
||||
# "Machine": {},
|
||||
# "Run": {},
|
||||
# "Tests": [
|
||||
# {
|
||||
# "Data": [
|
||||
# 1318
|
||||
# ],
|
||||
# "Info": {},
|
||||
# "Name": [
|
||||
# "2Sum"
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "Data": [
|
||||
# 805
|
||||
# ],
|
||||
# "Info": {},
|
||||
# "Name": [
|
||||
# "Ackermann"
|
||||
# ]
|
||||
# },
|
||||
# {
|
||||
# "Data": [
|
||||
# 2123
|
||||
# ],
|
||||
# "Info": {},
|
||||
# "Name": [
|
||||
# "Totals"
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
|
||||
import sys
|
||||
import json
|
||||
import re
|
||||
# Parse lines like this
|
||||
# #,TEST,SAMPLES,MIN(ms),MAX(ms),MEAN(ms),SD(ms),MEDIAN(ms)
|
||||
SCORERE = re.compile(r"(\d+),[ \t]*(\w+),[ \t]*([\d.]+),[ \t]*([\d.]+)")
|
||||
|
||||
# The Totals line would be parsed like this.
|
||||
TOTALRE = re.compile(r"()(Totals),[ \t]*([\d.]+),[ \t]*([\d.]+)")
|
||||
KEYGROUP = 2
|
||||
VALGROUP = 4
|
||||
|
||||
if __name__ == "__main__":
|
||||
data = {}
|
||||
data['Tests'] = []
|
||||
data['Machine'] = {}
|
||||
data['Run'] = {}
|
||||
for line in sys.stdin:
|
||||
m = SCORERE.match(line)
|
||||
if not m:
|
||||
m = TOTALRE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
test = {}
|
||||
test['Data'] = [int(m.group(VALGROUP))]
|
||||
test['Info'] = {}
|
||||
test['Name'] = [m.group(KEYGROUP)]
|
||||
data['Tests'].append(test)
|
||||
print(json.dumps(data, sort_keys=True, indent=4))
|
||||
180
benchmark/utils/main.swift
Normal file
180
benchmark/utils/main.swift
Normal file
@@ -0,0 +1,180 @@
|
||||
//===--- main.swift -------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See http://swift.org/LICENSE.txt for license information
|
||||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WARNING: This file is automatically generated from templates and should not
|
||||
// be directly modified. Instead, make changes to
|
||||
// scripts/generate_harness/main.swift_template and run
|
||||
// scripts/generate_harness/generate_harness.py to regenerate this file.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This is just a driver for performance overview tests.
|
||||
import TestsUtils
|
||||
import DriverUtils
|
||||
import Ackermann
|
||||
import AngryPhonebook
|
||||
import Array2D
|
||||
import ArrayAppend
|
||||
import ArrayInClass
|
||||
import ArrayLiteral
|
||||
import ArrayOfGenericPOD
|
||||
import ArrayOfGenericRef
|
||||
import ArrayOfPOD
|
||||
import ArrayOfRef
|
||||
import ArraySubscript
|
||||
import BitCount
|
||||
import ByteSwap
|
||||
import Calculator
|
||||
import CaptureProp
|
||||
import Chars
|
||||
import ClassArrayGetter
|
||||
import DeadArray
|
||||
import DictTest
|
||||
import DictTest2
|
||||
import DictTest3
|
||||
import DictionaryBridge
|
||||
import DictionaryLiteral
|
||||
import DictionaryRemove
|
||||
import DictionarySwap
|
||||
import ErrorHandling
|
||||
import Fibonacci
|
||||
import GlobalClass
|
||||
import Hanoi
|
||||
import Hash
|
||||
import Histogram
|
||||
import Join
|
||||
import LinkedList
|
||||
import MapReduce
|
||||
import Memset
|
||||
import MonteCarloE
|
||||
import MonteCarloPi
|
||||
import NSDictionaryCastToSwift
|
||||
import NSError
|
||||
import NSStringConversion
|
||||
import NopDeinit
|
||||
import ObjectAllocation
|
||||
import OpenClose
|
||||
import Phonebook
|
||||
import PolymorphicCalls
|
||||
import PopFront
|
||||
import PopFrontGeneric
|
||||
import Prims
|
||||
import ProtocolDispatch
|
||||
import RC4
|
||||
import RGBHistogram
|
||||
import RangeAssignment
|
||||
import RecursiveOwnedParameter
|
||||
import StaticArray
|
||||
import SetTests
|
||||
import SevenBoom
|
||||
import Sim2DArray
|
||||
import SortLettersInPlace
|
||||
import SortStrings
|
||||
import StrComplexWalk
|
||||
import StrToInt
|
||||
import StringBuilder
|
||||
import StringInterpolation
|
||||
import StringTests
|
||||
import StringWalk
|
||||
import SuperChars
|
||||
import TwoSum
|
||||
import TypeFlood
|
||||
import Walsh
|
||||
import XorLoop
|
||||
|
||||
precommitTests = [
|
||||
"AngryPhonebook": run_AngryPhonebook,
|
||||
"Array2D": run_Array2D,
|
||||
"ArrayAppend": run_ArrayAppend,
|
||||
"ArrayAppendReserved": run_ArrayAppendReserved,
|
||||
"ArrayInClass": run_ArrayInClass,
|
||||
"ArrayLiteral": run_ArrayLiteral,
|
||||
"ArrayOfGenericPOD": run_ArrayOfGenericPOD,
|
||||
"ArrayOfGenericRef": run_ArrayOfGenericRef,
|
||||
"ArrayOfPOD": run_ArrayOfPOD,
|
||||
"ArrayOfRef": run_ArrayOfRef,
|
||||
"ArraySubscript": run_ArraySubscript,
|
||||
"ArrayValueProp": run_ArrayValueProp,
|
||||
"ArrayValueProp2": run_ArrayValueProp2,
|
||||
"ArrayValueProp3": run_ArrayValueProp3,
|
||||
"ArrayValueProp4": run_ArrayValueProp4,
|
||||
"BitCount": run_BitCount,
|
||||
"ByteSwap": run_ByteSwap,
|
||||
"Calculator": run_Calculator,
|
||||
"CaptureProp": run_CaptureProp,
|
||||
"Chars": run_Chars,
|
||||
"ClassArrayGetter": run_ClassArrayGetter,
|
||||
"DeadArray": run_DeadArray,
|
||||
"Dictionary": run_Dictionary,
|
||||
"Dictionary2": run_Dictionary2,
|
||||
"Dictionary3": run_Dictionary3,
|
||||
"DictionaryBridge": run_DictionaryBridge,
|
||||
"DictionaryLiteral": run_DictionaryLiteral,
|
||||
"DictionaryRemove": run_DictionaryRemove,
|
||||
"DictionarySwap": run_DictionarySwap,
|
||||
"ErrorHandling": run_ErrorHandling,
|
||||
"GlobalClass": run_GlobalClass,
|
||||
"Hanoi": run_Hanoi,
|
||||
"HashTest": run_HashTest,
|
||||
"Histogram": run_Histogram,
|
||||
"Join": run_Join,
|
||||
"LinkedList": run_LinkedList,
|
||||
"MapReduce": run_MapReduce,
|
||||
"Memset": run_Memset,
|
||||
"MonteCarloE": run_MonteCarloE,
|
||||
"MonteCarloPi": run_MonteCarloPi,
|
||||
"NSDictionaryCastToSwift": run_NSDictionaryCastToSwift,
|
||||
"NSError": run_NSError,
|
||||
"NSStringConversion": run_NSStringConversion,
|
||||
"NopDeinit": run_NopDeinit,
|
||||
"ObjectAllocation": run_ObjectAllocation,
|
||||
"OpenClose": run_OpenClose,
|
||||
"Phonebook": run_Phonebook,
|
||||
"PolymorphicCalls": run_PolymorphicCalls,
|
||||
"PopFrontArray": run_PopFrontArray,
|
||||
"PopFrontArrayGeneric": run_PopFrontArrayGeneric,
|
||||
"PopFrontUnsafePointer": run_PopFrontUnsafePointer,
|
||||
"Prims": run_Prims,
|
||||
"ProtocolDispatch": run_ProtocolDispatch,
|
||||
"RC4": run_RC4,
|
||||
"RGBHistogram": run_RGBHistogram,
|
||||
"RangeAssignment": run_RangeAssignment,
|
||||
"RecursiveOwnedParameter": run_RecursiveOwnedParameter,
|
||||
"StaticArray": run_StaticArray,
|
||||
"SetExclusiveOr": run_SetExclusiveOr,
|
||||
"SetIntersect": run_SetIntersect,
|
||||
"SetIsSubsetOf": run_SetIsSubsetOf,
|
||||
"SetUnion": run_SetUnion,
|
||||
"SevenBoom": run_SevenBoom,
|
||||
"Sim2DArray": run_Sim2DArray,
|
||||
"SortLettersInPlace": run_SortLettersInPlace,
|
||||
"SortStrings": run_SortStrings,
|
||||
"StrComplexWalk": run_StrComplexWalk,
|
||||
"StrToInt": run_StrToInt,
|
||||
"StringBuilder": run_StringBuilder,
|
||||
"StringInterpolation": run_StringInterpolation,
|
||||
"StringWalk": run_StringWalk,
|
||||
"StringWithCString": run_StringWithCString,
|
||||
"SuperChars": run_SuperChars,
|
||||
"TwoSum": run_TwoSum,
|
||||
"TypeFlood": run_TypeFlood,
|
||||
"Walsh": run_Walsh,
|
||||
"XorLoop": run_XorLoop,
|
||||
]
|
||||
|
||||
otherTests = [
|
||||
"Ackermann": run_Ackermann,
|
||||
"Fibonacci": run_Fibonacci,
|
||||
]
|
||||
|
||||
|
||||
main()
|
||||
@@ -322,8 +322,8 @@ function(_compile_swift_files dependency_target_out_var_name)
|
||||
list(APPEND swift_flags "-Xfrontend" "-sil-verify-all")
|
||||
endif()
|
||||
|
||||
if(SWIFT_STDLIB_USE_ASSERT_CONFIG_RELEASE)
|
||||
list(APPEND swift_flags "-assert-config" "Release")
|
||||
if(SWIFT_STDLIB_ENABLE_RESILIENCE AND SWIFTFILE_IS_STDLIB)
|
||||
list(APPEND swift_flags "-Xfrontend" "-enable-resilience")
|
||||
endif()
|
||||
|
||||
if(SWIFT_EMIT_SORTED_SIL_OUTPUT)
|
||||
@@ -333,8 +333,10 @@ function(_compile_swift_files dependency_target_out_var_name)
|
||||
# FIXME: Cleaner way to do this?
|
||||
if(SWIFTFILE_IS_STDLIB_CORE)
|
||||
list(APPEND swift_flags
|
||||
"-nostdimport" "-parse-stdlib" "-module-name" "Swift"
|
||||
"-Xfrontend" "-sil-serialize-all")
|
||||
"-nostdimport" "-parse-stdlib" "-module-name" "Swift")
|
||||
if (NOT SWIFT_STDLIB_ENABLE_RESILIENCE)
|
||||
list(APPEND swift_flags "-Xfrontend" "-sil-serialize-all")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(SWIFTFILE_IS_SDK_OVERLAY)
|
||||
|
||||
@@ -25,6 +25,9 @@ unacceptable cost or force widespread opting-out of abstraction. We intend to
|
||||
mitigate this primarily by designing the language and its implementation to
|
||||
minimize unnecessary and unintended abstraction:
|
||||
|
||||
* Avoiding unnecessary language guarantees and taking advantage of that
|
||||
flexibility to limit load-time costs.
|
||||
|
||||
* Within the domain that defines an entity, all the details of its
|
||||
implementation are available.
|
||||
|
||||
@@ -35,19 +38,12 @@ minimize unnecessary and unintended abstraction:
|
||||
independently desirable to reduce accidental API surface area, but happens to
|
||||
also interact well with the performance design.
|
||||
|
||||
* Avoiding unnecessary language guarantees and taking advantage of that
|
||||
flexibility to limit load-time costs.
|
||||
|
||||
We also intend to provide tools to detect inadvertent changes in interfaces.
|
||||
This last point is a specific case of a general tenet of Swift: **the default
|
||||
behavior is safe**. Where possible, choices made when an entity is first
|
||||
published should not limit its evolution in the future.
|
||||
|
||||
.. contents:: :local:
|
||||
|
||||
.. warning:: **This document is still in draft stages.** Large additions and
|
||||
restructuring are still planned, including:
|
||||
|
||||
* A discussion of back-dating, and how it usually is not allowed.
|
||||
* A revisal of the discussion on fixed-layout classes.
|
||||
* A brief discussion of "deployment files", which represent distribution groupings that are themselves versioned. (For example, OS X 10.10.3 contains Foundation version 1153.20.) Deployment files are likely to provide a concrete implementation of "resilience domains".
|
||||
|
||||
Introduction
|
||||
============
|
||||
@@ -65,13 +61,24 @@ This document will frequently refer to a *library* which vends public APIs, and
|
||||
a single *client* that uses them. The same principles apply even when multiple
|
||||
libraries and multiple clients are involved.
|
||||
|
||||
This model is not of interest to libraries that are bundled with their clients
|
||||
(distribution via source, static library, or embedded/sandboxed dynamic
|
||||
library). Because a client always uses a particular version of such a library,
|
||||
there is no need to worry about backwards- or forwards-compatibility. Just as
|
||||
developers with a single app target are not forced to think about access
|
||||
control, anyone writing a bundled library should not be required to use any of
|
||||
the annotations described below in order to achieve full performance.
|
||||
This model is largely not of interest to libraries that are bundled with their
|
||||
clients (distribution via source, static library, or embedded/sandboxed dynamic
|
||||
library, as used by the `Swift Package Manager`_). Because a client always uses
|
||||
a particular version of such a library, there is no need to worry about
|
||||
backwards- or forwards-compatibility. Just as developers with a single app
|
||||
target are not forced to think about access control, anyone writing a bundled
|
||||
library should not be required to use any of the annotations described below in
|
||||
order to achieve full performance.
|
||||
|
||||
.. _Swift Package Manager: https://swift.org/package-manager/
|
||||
|
||||
.. note::
|
||||
|
||||
This model may, however, be useful for library authors that want to
|
||||
preserve *source* compatibility, and it is hoped that the tool for
|
||||
`Checking Binary Compatibility`_ described below will also be useful for
|
||||
this purpose. Additionally, we may decide to use some of these annotations
|
||||
as performance hints for *non-*\ optimized builds.
|
||||
|
||||
The term "resilience" comes from the occasional use of "fragile" to describe
|
||||
certain constructs that have very strict binary compatibility rules. For
|
||||
@@ -85,10 +92,10 @@ Using Versioned API
|
||||
===================
|
||||
|
||||
References to a versioned API must always be guarded with the appropriate
|
||||
availability checks. This means that any client entities that rely on having
|
||||
certain APIs from a library must themselves be restricted to contexts in which
|
||||
those APIs are available. This is accomplished using ``@available`` as well,
|
||||
by specifying the name of the client library along with the required version::
|
||||
availability checks. This means that any client entities that rely on certain
|
||||
APIs from a library must themselves be restricted to contexts in which those
|
||||
APIs are available. This is accomplished using the ``@available`` attribute, by
|
||||
specifying the name of the client library along with the required version::
|
||||
|
||||
// Client code
|
||||
@available(Magician 1.5)
|
||||
@@ -120,7 +127,7 @@ Declaring Library Version Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Swift 2's availability model includes the notion of a *minimum deployment
|
||||
target,* the version of an OS that can be assumed present for the program being
|
||||
target,* the version of an OS that must be present for the program being
|
||||
compiled to run at all. For example, a program compiled with a minimum
|
||||
deployment target of iOS 9.2 will not launch on iOS 9.0.
|
||||
|
||||
@@ -175,8 +182,9 @@ In addition to versioned entities, there are also attributes that are safe to
|
||||
add to declarations when releasing a new version of a library. In most cases,
|
||||
clients can only take advantage of the attributes when using the new release of
|
||||
the library, and therefore the attributes also need to record the version in
|
||||
which they were introduced. If the version is omitted, it is assumed to be the
|
||||
version of the declaration to which the attribute is attached.
|
||||
which they were introduced; these are called *versioned attributes.* If the
|
||||
version is omitted, it is assumed to be the version of the declaration to which
|
||||
the attribute is attached.
|
||||
|
||||
The syntax for marking an entity as versioned has not yet been decided, but the
|
||||
rest of this document will use syntax #1 described below.
|
||||
@@ -279,7 +287,7 @@ No other changes are permitted; the following are particularly of note:
|
||||
- A versioned function may not change its external parameter names (labels).
|
||||
- A versioned function may not add, remove, or reorder parameters, whether or
|
||||
not they have default values.
|
||||
- A versioned function that throws may not become non-throwing.
|
||||
- A versioned function that throws may not become non-throwing or vice versa.
|
||||
- ``@noreturn`` may not be removed from a function.
|
||||
- The ``@noescape`` attribute may not be added to or removed from a parameter.
|
||||
It is not a `versioned attribute` and so there is no way to guarantee that it
|
||||
@@ -351,20 +359,18 @@ polar representation::
|
||||
public init(x: Double, y: Double) { … }
|
||||
}
|
||||
|
||||
and the ``x`` and ``y`` properties have now disappeared. To avoid this, we have
|
||||
the following restrictions on the bodies of inlineable functions:
|
||||
and the ``x`` and ``y`` properties have now disappeared. To avoid this, the bodies of inlineable functions have the following restrictions:
|
||||
|
||||
- **They may not define any local types** (other than typealiases).
|
||||
- They may not define any local types (other than typealiases).
|
||||
|
||||
- **They must not reference any** ``private`` **entities,** except for local
|
||||
functions declared within the inlineable function itself.
|
||||
- They must not reference any ``private`` entities, except for local functions
|
||||
declared within the inlineable function itself.
|
||||
|
||||
- **They must not reference any** ``internal`` **entities except for those that
|
||||
have been** `versioned`_. See below for a discussion of versioning internal
|
||||
API.
|
||||
- They must not reference any ``internal`` entities except for those that have
|
||||
been `versioned`_. See below for a discussion of versioning internal API.
|
||||
|
||||
- **They must not reference any entities less available than the function
|
||||
itself.**
|
||||
- They must not reference any entities from the current module introduced
|
||||
after the function was made inlineable.
|
||||
|
||||
.. _versioned: #versioning-internal-api
|
||||
|
||||
@@ -373,12 +379,6 @@ makes it possible to take an existing function and make it inlineable, as long
|
||||
as the current body makes sense when deploying against an earlier version of
|
||||
the library.
|
||||
|
||||
If the body of an inlineable function is used in any way by a client module
|
||||
(say, to determine that it does not read any global variables), that module
|
||||
must take care to emit and use its own copy of the function. This is because
|
||||
analysis of the function body may not apply to the version of the function
|
||||
currently in the library.
|
||||
|
||||
Default parameter value expressions are subject to the same restrictions as
|
||||
inlineable functions, because they are implemented as inlineable functions.
|
||||
|
||||
@@ -405,7 +405,7 @@ changes are permitted:
|
||||
- Adding (but not removing) a public setter to a computed variable.
|
||||
- Adding or removing a non-public, non-versioned setter.
|
||||
- Changing from a stored variable to a computed variable, or vice versa, as
|
||||
long as a previously-versioned setter is not removed.
|
||||
long as a previously versioned setter is not removed.
|
||||
- Changing the body of an accessor.
|
||||
- Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from
|
||||
an existing variable. This is effectively the same as modifying the body of a
|
||||
@@ -464,7 +464,8 @@ clients to access them more efficiently. This restricts changes a fair amount:
|
||||
- Adding or removing ``weak`` is forbidden.
|
||||
- Adding or removing ``unowned`` is forbidden.
|
||||
- Adding or removing ``@NSCopying`` to/from a variable is permitted but
|
||||
discouraged for the same reason.
|
||||
discouraged for the same reason; like accessors, existing clients may use the
|
||||
new behavior, or the behavior from when they were compiled, or a mix of both.
|
||||
|
||||
.. admonition:: TODO
|
||||
|
||||
@@ -513,21 +514,75 @@ layout.
|
||||
accessors of a property are fine, but those that provide new entry points
|
||||
are trickier.
|
||||
|
||||
Like top-level constants, it is *not* safe to change a ``let`` property into a
|
||||
variable or vice versa. Properties declared with ``let`` are assumed not to
|
||||
change for the entire lifetime of the program once they have been initialized.
|
||||
|
||||
It is not safe to add or remove ``mutating`` or ``nonmutating`` from a member
|
||||
or accessor within a struct. These modifiers are not `versioned attributes
|
||||
<versioned attribute>` and as such there is no safety guarantee for a client
|
||||
deploying against an earlier version of the library.
|
||||
|
||||
|
||||
Methods and Initializers
|
||||
------------------------
|
||||
|
||||
For the most part struct methods and initializers are treated exactly like
|
||||
top-level functions. They permit all of the same modifications and can also be
|
||||
marked ``@inlineable``, with the same restrictions. Inlineable initializers
|
||||
must always delegate to another initializer, since new properties may be added
|
||||
between new releases. For the same reason, initializers declared outside of the
|
||||
struct's module must always delegate to another initializer.
|
||||
|
||||
|
||||
Properties
|
||||
----------
|
||||
|
||||
Struct properties behave largely the same as top-level bindings. They permit
|
||||
all of the same modifications, and also allow adding or removing an initial
|
||||
value entirely.
|
||||
|
||||
Struct properties can also be marked ``@inlineable``, with the same
|
||||
restrictions as for top-level bindings. An inlineable stored property may not
|
||||
become computed, but the offset of its storage within the struct is not
|
||||
necessarily fixed.
|
||||
|
||||
.. note::
|
||||
|
||||
One possible layout algorithm would put all inlineable struct constants at
|
||||
the start of the struct, sorted by availability, so that the offset *could*
|
||||
be fixed. This would have to be balanced against other goals for struct
|
||||
layout.
|
||||
|
||||
Like top-level constants, it is *not* safe to change a ``let`` property into a
|
||||
variable or vice versa. Properties declared with ``let`` are assumed not to
|
||||
change for the entire lifetime of the program once they have been initialized.
|
||||
|
||||
|
||||
Subscripts
|
||||
----------
|
||||
|
||||
Subscripts behave largely the same as properties, except that there are no
|
||||
stored subscripts. This means that the following changes are permitted:
|
||||
|
||||
- Adding (but not removing) a public setter.
|
||||
- Adding or removing a non-public, non-versioned setter.
|
||||
- Changing the body of an accessor.
|
||||
|
||||
Like properties, subscripts can be marked ``@inlineable``, which restricts the
|
||||
set of changes:
|
||||
|
||||
- Adding a versioned setter is still permitted.
|
||||
- Adding or removing a non-public, non-versioned setter is still permitted.
|
||||
- Changing the body of an accessor is permitted but discouraged; existing
|
||||
clients may use the new implementations, or they may use the implementations
|
||||
from the time they were compiled, or a mix of both.
|
||||
|
||||
Any inlineable accessors must follow the rules for `inlineable functions`_,
|
||||
as described above.
|
||||
|
||||
|
||||
New Conformances
|
||||
----------------
|
||||
|
||||
If a conformance is added to a type in version 1.1 of a library, it's important
|
||||
that it isn't accessed in version 1.0. This is obvious if the protocol itself
|
||||
that it isn't accessed in version 1.0. This is implied if the protocol itself
|
||||
was introduced in version 1.1, but needs special handling if both the protocol
|
||||
and the type were available earlier. In this case, the conformance *itself*
|
||||
needs to be labeled as being introduced in version 1.1, so that the compiler
|
||||
@@ -544,13 +599,13 @@ can enforce its safe use.
|
||||
We've considered two possible syntaxes for this::
|
||||
|
||||
@available(1.1)
|
||||
extension MyStruct : SomeProto {…}
|
||||
extension Wand : MagicType {…}
|
||||
|
||||
and
|
||||
|
||||
::
|
||||
|
||||
extension MyStruct : @available(1.1) SomeProto {…}
|
||||
extension Wand : @available(1.1) MagicType {…}
|
||||
|
||||
The former requires fewer changes to the language grammar, but the latter could
|
||||
also be used on the declaration of the type itself (i.e. the ``struct``
|
||||
@@ -569,8 +624,9 @@ Fixed-Contents Structs
|
||||
To opt out of this flexibility, a struct may be marked ``@fixed_contents``.
|
||||
This promises that no stored properties will be added to or removed from the
|
||||
struct, even ``private`` or ``internal`` ones. Additionally, all versioned
|
||||
stored properties in a ``@fixed_contents`` struct are implicitly declared
|
||||
``@inlineable`` (as described above for top-level variables). In effect:
|
||||
instance stored properties in a ``@fixed_contents`` struct are implicitly
|
||||
declared ``@inlineable`` (as described above for top-level variables). In
|
||||
effect:
|
||||
|
||||
- Reordering all members, including stored properties, is still permitted.
|
||||
- Adding new stored instance properties (public or non-public) is not permitted.
|
||||
@@ -598,6 +654,21 @@ generic parameters and members of tuples.
|
||||
This name is intentionally awful to encourage us to come up with a better
|
||||
one.
|
||||
|
||||
While adding or removing stored properties is forbidden, existing properties may
|
||||
still be modified in limited ways:
|
||||
|
||||
- An existing non-versioned ``internal`` property may be made ``private``, or
|
||||
vice versa.
|
||||
- A non-versioned ``internal`` property may be versioned (see `Versioning
|
||||
Internal Declarations`_).
|
||||
- A versioned ``internal`` property may be made ``public`` (without changing
|
||||
its version).
|
||||
|
||||
An initializer of a fixed-contents struct may be declared ``@inlineable`` even
|
||||
if it does not delegate to another initializer, as long as the ``@inlineable``
|
||||
attribute is not introduced earlier than the ``@fixed_contents`` attribute and
|
||||
the struct has no non-versioned stored properties.
|
||||
|
||||
A ``@fixed_contents`` struct is *not* guaranteed to use the same layout as a C
|
||||
struct with a similar "shape". If such a struct is necessary, it should be
|
||||
defined in a C header and imported into Swift.
|
||||
@@ -664,6 +735,26 @@ accommodate new values. More specifically, the following changes are permitted:
|
||||
be useful, and they require essentially the same implementation work as
|
||||
cases added in future versions of a library.
|
||||
|
||||
Adding or removing the ``@objc`` attribute from an enum is not permitted; this
|
||||
affects the enum's memory representation and is not backwards-compatible.
|
||||
|
||||
|
||||
Initializers
|
||||
------------
|
||||
|
||||
For the most part enum initializers are treated exactly like top-level
|
||||
functions. They permit all of the same modifications and can also be marked
|
||||
``@inlineable``, with the same restrictions. Unlike struct initializers, enum
|
||||
initializers do not always need to delegate to another initializer, even if
|
||||
they are ``@inlineable`` or declared in a separate module.
|
||||
|
||||
|
||||
Methods and Subscripts
|
||||
----------------------
|
||||
|
||||
The rules for enum methods and subscripts are identical to those for struct
|
||||
members.
|
||||
|
||||
|
||||
Closed Enums
|
||||
------------
|
||||
@@ -714,8 +805,16 @@ There are very few safe changes to make to protocols:
|
||||
|
||||
- A new non-type requirement may be added to a protocol, as long as it has an
|
||||
unconstrained default implementation.
|
||||
- A new associated type may be added to a protocol, as long as it has a default.
|
||||
- A new optional requirement may be added to an ``@objc`` protocol.
|
||||
- All members may be reordered, including associated types.
|
||||
- Changing *internal* parameter names of function and subscript requirements
|
||||
is permitted.
|
||||
- Reordering generic requirements is permitted (but not the generic parameters
|
||||
themselves).
|
||||
- The ``@warn_unused_result`` and ``@warn_unqualified_access`` attributes may
|
||||
be added to a function requirement without any additional versioning
|
||||
information.
|
||||
|
||||
All other changes to the protocol itself are forbidden, including:
|
||||
|
||||
@@ -726,10 +825,16 @@ Protocol extensions may be more freely modified; `see below`__.
|
||||
|
||||
__ #protocol-extensions
|
||||
|
||||
.. admonition:: TODO
|
||||
.. note::
|
||||
|
||||
Allowing the addition of associated types means implementing some form of
|
||||
"generalized existentials", so that existing existential values (values
|
||||
with protocol type) continue to work even if a protocol gets its first
|
||||
associated type. Until we have that feature implemented, it is only safe to
|
||||
add an associated type to a protocol that already has associated types, or
|
||||
uses ``Self`` in a non-return position (i.e. one that currently cannot be
|
||||
used as the type of a value).
|
||||
|
||||
It would also be nice to be able to add new associated types with default
|
||||
values, but that seems trickier to implement.
|
||||
|
||||
Classes
|
||||
~~~~~~~
|
||||
@@ -782,7 +887,7 @@ Finally, classes allow the following changes that do not apply to structs:
|
||||
|
||||
.. admonition:: TODO
|
||||
|
||||
The latter is very tricky to get right. We've seen it happen a few times in
|
||||
This last is very tricky to get right. We've seen it happen a few times in
|
||||
Apple's SDKs, but at least one of them, `NSCollectionViewItem`_ becoming a
|
||||
subclass of NSViewController instead of the root class NSObject, doesn't
|
||||
strictly follow the rules. While NSViewController was introduced in the
|
||||
@@ -796,11 +901,6 @@ Finally, classes allow the following changes that do not apply to structs:
|
||||
Other than those detailed above, no other changes to a class or its members
|
||||
are permitted. In particular:
|
||||
|
||||
- New designated initializers may not be added to a publicly-subclassable
|
||||
class. This would change the inheritance of convenience initializers, which
|
||||
existing subclasses may depend on.
|
||||
- New ``required`` initializers may not be added to a publicly-subclassable
|
||||
class. There is no way to guarantee their presence on existing subclasses.
|
||||
- ``final`` may not be added to *or* removed from a class or any of its members.
|
||||
The presence of ``final`` enables optimization; its absence means there may
|
||||
be subclasses/overrides that would be broken by the change.
|
||||
@@ -827,12 +927,129 @@ are permitted. In particular:
|
||||
rdar://problem/20829214
|
||||
|
||||
|
||||
Initializers
|
||||
------------
|
||||
|
||||
New designated initializers may not be added to a publicly-subclassable class.
|
||||
This would change the inheritance of convenience initializers, which existing
|
||||
subclasses may depend on. A publicly-subclassable class also may not change
|
||||
a convenience initializer into a designated initializer or vice versa.
|
||||
|
||||
Similarly, new ``required`` initializers may not be added to a
|
||||
publicly-subclassable class, including marking an existing initializer
|
||||
``required``; there is no way to guarantee their presence on existing
|
||||
subclasses. This also limits adding a conformance to a protocol with an
|
||||
initializer requirement if the corresponding initializer is not already
|
||||
``required``.
|
||||
|
||||
All of the modifications permitted for top-level functions are also permitted
|
||||
for class initializers. Convenience initializers may be marked ``@inlineable``,
|
||||
with the same restrictions as top-level functions; designated initializers may
|
||||
not.
|
||||
|
||||
|
||||
Methods
|
||||
-------
|
||||
|
||||
Both class and instance methods allow all of the modifications permitted for
|
||||
top-level functions, but the potential for overrides complicates things a little. They allow the following changes:
|
||||
|
||||
- Changing the body of the method.
|
||||
- Changing *internal* parameter names (i.e. the names used within the method
|
||||
body, not the labels that are part of the method's full name).
|
||||
- Reordering generic requirements (but not the generic parameters themselves).
|
||||
- Adding a default value to a parameter.
|
||||
- Changing or removing a default value is permitted but discouraged; it may
|
||||
break or change the meaning of existing source code.
|
||||
- The ``@noreturn`` attribute may be added to a public method only if it is
|
||||
``final`` or the class is not publicly subclassable. ``@noreturn`` is a
|
||||
`versioned attribute`.
|
||||
- The ``@warn_unused_result`` and ``@warn_unqualified_access`` attributes may
|
||||
be added to a method without any additional versioning information.
|
||||
|
||||
Class and instance methods may be marked ``@inlineable``, with the same
|
||||
restrictions as struct methods. ``dynamic`` methods may not be marked
|
||||
``@inlineable``.
|
||||
|
||||
If an inlineable method is overridden, the overriding method does not need to
|
||||
also be inlineable. Clients may only inline a method when they can devirtualize
|
||||
the call. (This does permit speculative devirtualization.)
|
||||
|
||||
Any method that overrides a ``@noreturn`` method must also be marked
|
||||
``@noreturn``.
|
||||
|
||||
|
||||
Properties
|
||||
----------
|
||||
|
||||
Class and instance properties allow *most* of the modifications permitted for
|
||||
struct properties, but the potential for overrides complicates things a little.
|
||||
Variable properties (those declared with ``var``) allow the following changes:
|
||||
|
||||
- Adding (but not removing) a computed setter to a ``final`` property or a
|
||||
property in a non-publicly-subclassable class.
|
||||
- Adding or removing a non-public, non-versioned setter.
|
||||
- Changing from a stored property to a computed property, or vice versa, as
|
||||
long as a previously versioned setter is not removed.
|
||||
- Changing the body of an accessor.
|
||||
- Adding or removing an observing accessor (``willSet`` or ``didSet``) to/from
|
||||
an existing variable. This is effectively the same as modifying the body of a
|
||||
setter.
|
||||
- Adding, removing, or changing the initial value of a stored variable.
|
||||
- Adding or removing ``weak`` from a variable with ``Optional`` type.
|
||||
- Adding or removing ``unowned`` from a variable.
|
||||
- Adding or removing ``@NSCopying`` to/from a variable.
|
||||
|
||||
Adding a public setter to a computed property that may be overridden is
|
||||
permitted but discouraged; any existing overrides will not know what to do with
|
||||
the setter and will likely not behave correctly.
|
||||
|
||||
Constant properties (those declared with ``let``) still permit changing their
|
||||
value, as well as adding or removing an initial value entirely.
|
||||
|
||||
Both variable and constant properties (on both instances and classes) may be
|
||||
marked ``@inlineable``. This behaves as described for struct properties.
|
||||
``dynamic`` properties may not be marked ``@inlineable``.
|
||||
|
||||
If an inlineable property is overridden, the overriding property does not need
|
||||
to also be inlineable. Clients may only inline a property access when they can
|
||||
devirtualize it. (This does permit speculative devirtualization.)
|
||||
|
||||
|
||||
Subscripts
|
||||
----------
|
||||
|
||||
Subscripts behave much like properties; they inherit the rules of their struct
|
||||
counterparts with a few small changes:
|
||||
|
||||
- Adding (but not removing) a public setter to a ``final`` subscript or a
|
||||
subscript in a non-publicly-subclassable class.
|
||||
- Adding or removing a non-public, non-versioned setter.
|
||||
- Changing the body of an accessor.
|
||||
|
||||
Adding a public setter to a subscript that may be overridden is permitted but
|
||||
discouraged; any existing overrides will not know what to do with the setter
|
||||
and will likely not behave correctly.
|
||||
|
||||
Class subscripts may be marked ``@inlineable``, which behaves as described for
|
||||
struct subscripts. ``dynamic`` subscripts may not be marked ``@inlineable``.
|
||||
|
||||
If an inlineable subscript is overridden, the overriding subscript does not need
|
||||
to also be inlineable. Clients may only inline a subscript access when they can
|
||||
devirtualize it. (This does permit speculative devirtualization.)
|
||||
|
||||
|
||||
Possible Restrictions on Classes
|
||||
--------------------------------
|
||||
|
||||
In addition to ``final``, it may be useful to restrict the size of a class
|
||||
instance (like a struct's ``@fixed_contents``) or the number of overridable
|
||||
members in its virtual dispatch table. These annotations have not been designed.
|
||||
In addition to ``final``, it may be useful to restrict the stored properties of
|
||||
a class instance, like `Fixed-Contents Structs`_. However, there are open
|
||||
questions about how this would actually work, and the compiler still wouldn't
|
||||
be able to make much use of the information, because classes from other
|
||||
libraries must almost always be allocated on the heap.
|
||||
|
||||
The design of this annotation is not covered by this document. As a purely
|
||||
additive feature, it can be added to the model at any time.
|
||||
|
||||
|
||||
Extensions
|
||||
@@ -844,11 +1061,11 @@ The following changes are permitted:
|
||||
- Adding new extensions and removing empty extensions.
|
||||
- Moving a member from one extension to another within the same module, as long
|
||||
as both extensions have the exact same constraints.
|
||||
- Moving a member from an extension to the declaration of the base type,
|
||||
provided that the declaration is in the same module. The reverse is permitted
|
||||
for all members except stored properties, although note that moving all
|
||||
initializers out of a type declaration may cause a new one to be implicitly
|
||||
synthesized.
|
||||
- Moving a member from an unconstrained extension to the declaration of the
|
||||
base type, provided that the declaration is in the same module. The reverse
|
||||
is permitted for all members except stored properties, although note that
|
||||
moving all initializers out of a type declaration may cause a new one to be
|
||||
implicitly synthesized.
|
||||
|
||||
Adding, removing, reordering, and modifying members follow the same rules as
|
||||
the base type; see the sections on structs, enums, and classes above.
|
||||
@@ -868,6 +1085,12 @@ following changes are permitted:
|
||||
- Removing any non-public, non-versioned member.
|
||||
- Changing the body of any methods, initializers, or accessors.
|
||||
|
||||
.. note::
|
||||
|
||||
Although it is not related to evolution, it is worth noting that members of
|
||||
protocol extensions that do *not* satisfy protocol requirements are not
|
||||
overridable, even when the conforming type is a class.
|
||||
|
||||
|
||||
Operators
|
||||
~~~~~~~~~
|
||||
@@ -904,7 +1127,7 @@ Neither top-level nor member typealiases are versioned.
|
||||
A Unifying Theme
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
So far this proposal has talked about ways to give up flexibility for several
|
||||
So far this document has talked about ways to give up flexibility for several
|
||||
different kinds of declarations: ``@inlineable`` for functions,
|
||||
``@fixed_contents`` for structs, etc. Each of these has a different set of
|
||||
constraints it enforces on the library author and promises it makes to clients.
|
||||
@@ -916,7 +1139,7 @@ guarantees. Therefore, all of these attributes are informally referred to as
|
||||
Given that these attributes share several characteristics, we could consider
|
||||
converging on a single common attribute, say ``@fixed``, ``@inline``, or
|
||||
``@fragile``. However, this may be problematic if the same declaration has
|
||||
multiple kinds of flexibility, as in the description of classes above.
|
||||
multiple kinds of flexibility.
|
||||
|
||||
|
||||
Versioning Internal Declarations
|
||||
@@ -946,7 +1169,8 @@ assumed that new overrides may eventually appear from outside the module unless
|
||||
the member is marked ``final`` or the class is not publicly subclassable.
|
||||
|
||||
Non-public conformances are never considered versioned, even if both the
|
||||
conforming type and the protocol are versioned.
|
||||
conforming type and the protocol are versioned. A conformance is considered
|
||||
public if and only if both the conforming type and protocol are public.
|
||||
|
||||
Entities declared ``private`` may not be versioned; the mangled name of such an
|
||||
entity includes an identifier based on the containing file, which means moving
|
||||
@@ -967,6 +1191,42 @@ removes one of the primary reasons to make something inlineable: to allow
|
||||
efficient access to a type while still protecting its invariants.
|
||||
|
||||
|
||||
"Backdating"
|
||||
============
|
||||
|
||||
*Backdating* refers to releasing a new version of a library that contains
|
||||
changes, but pretending those changes were made in a previous version of the
|
||||
library. For example, you might want to release version 1.2 of the "Magician"
|
||||
library, but pretend that the "SpellIncantation" struct was fixed-contents
|
||||
since its introduction in version 1.0.
|
||||
|
||||
**This is not safe.**
|
||||
|
||||
Backdating the availability a versioned entity that was previously non-public
|
||||
is clearly not safe: older versions of the library will not expose the entity
|
||||
as part of their ABI. What may be less obvious is that the fragility attributes
|
||||
likewise are not safe to backdate, even if you know the attributes could have
|
||||
been added in the past. To give one example, the presence of ``@closed`` or
|
||||
``@fixed_contents`` may affect the layout and calling conventions for an enum
|
||||
or struct.
|
||||
|
||||
As the sole exception, it is safe to backdate ``@inlineable`` on a top-level
|
||||
function, a method, a subscript, or a struct or enum initializer. It is not
|
||||
safe to backdate ``@inlineable`` for a top-level binding, a property, or a
|
||||
class initializer. As usual, a library author may not assume that a client will
|
||||
actually inline the call.
|
||||
|
||||
.. note::
|
||||
|
||||
If we add an "SPI" feature, such that the use of specific public entities
|
||||
is limited to certain clients, it *will* be safe to change the set of
|
||||
clients, or remove the restriction altogether. In fact, in such cases the
|
||||
library author is *required* to *not* change the availability info that was
|
||||
originally presented for the limited set of clients, since as mentioned
|
||||
above this may affect how those existing clients use the entities declared
|
||||
in the library.
|
||||
|
||||
|
||||
Optimization
|
||||
============
|
||||
|
||||
@@ -1016,9 +1276,11 @@ outside the current module, since once it's inlined it will be.
|
||||
|
||||
For inlineable code, the availability context is exactly the same as the
|
||||
equivalent non-inlineable code except that the assumed version of the
|
||||
containing library is the version attached to the ``@inlineable`` attribute.
|
||||
Code within this context must be treated as if the containing library were just
|
||||
a normal dependency.
|
||||
containing library is the version attached to the ``@inlineable`` attribute,
|
||||
and any `library version dependencies
|
||||
<#declaring-library-version-dependencies>`_ or minimum deployment target must
|
||||
be specified explicitly using ``@available``. Code within this context must be
|
||||
treated as if the containing library were just a normal dependency.
|
||||
|
||||
A versioned inlineable function still has an exported symbol in the library
|
||||
binary, which may be used when the function is referenced from a client rather
|
||||
@@ -1026,6 +1288,12 @@ than called. This version of the function is not subject to the same
|
||||
restrictions as the version that may be inlined, and so it may be desirable to
|
||||
compile a function twice: once for inlining, once for maximum performance.
|
||||
|
||||
If the body of an inlineable function is used in any way by a client module
|
||||
(say, to determine that it does not read any global variables), that module
|
||||
must take care to emit and use its own copy of the function. This is because
|
||||
analysis of the function body may not apply to the version of the function
|
||||
currently in the library.
|
||||
|
||||
|
||||
Local Availability Contexts
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -1093,18 +1361,47 @@ also in the collection---that is, it should treat all entities as if marked
|
||||
with the appropriate fragility attributes. Modules in this sort of collection
|
||||
are said to be in the same *resilience domain.*
|
||||
|
||||
Exactly how resilience domains are specified is not covered by this proposal,
|
||||
Exactly how resilience domains are specified is not covered by this document,
|
||||
and indeed they are an additive feature. One possibility is that a library's
|
||||
resilience domain defaults to the name of the module, but can be overridden. If
|
||||
a client has the same resilience domain name as a library it is using, it may
|
||||
assume that version of the library will be present at runtime.
|
||||
|
||||
|
||||
Deployments
|
||||
~~~~~~~~~~~
|
||||
|
||||
Related to the concept of a resilience domain is a *deployment.* While a
|
||||
resilience domain allows related libraries to be compiled more efficiently,
|
||||
a deployment groups related libraries together to present semantic version
|
||||
information to clients. The simplest example of this might be an OS release:
|
||||
OS X 10.10.0 contains Foundation version 1151.16 and AppKit version 1343. A
|
||||
deployment thus acts as a "virtual dependency": clients that depend on
|
||||
OS X 10.10 can rely on the presence of both of the library versions above.
|
||||
|
||||
The use of deployments allows clients to only have to think about aggregate
|
||||
dependencies, instead of listing every library they might depend on. It also
|
||||
allows library authors to build `many versions of a library`__ within a larger
|
||||
release cycle, as well as allowing a vendor to bundle together many libraries
|
||||
with uncoordinated release schedules and release them as a logical unit.
|
||||
|
||||
__ https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/index.html#//apple_ref/doc/constant_group/Foundation_Framework_Version_Numbers
|
||||
|
||||
There are lots of details to figure out here, including how to distribute this
|
||||
information. In particular, just like libraries publish the history of their
|
||||
own APIs, a deployment must publish the history of their included library
|
||||
versions, i.e. not just that OS X 10.10 contains Foundation 1151.16 and AppKit
|
||||
1343, but also that OS X 10.9 contains Foundation 1056 and AppKit 1265, and that
|
||||
OS X 10.8 contains Foundation 945.0 and AppKit 1187, and so on, back to the
|
||||
earliest version of the deployment that is supported.
|
||||
|
||||
|
||||
|
||||
Checking Binary Compatibility
|
||||
=============================
|
||||
|
||||
With this many manual controls, it's important that library owners be able to
|
||||
check their work. Therefore, we intend to ship a tool that can compare two
|
||||
check their work. Therefore, we intend to build a tool that can compare two
|
||||
versions of a library's public interface, and present any suspect differences
|
||||
for verification. Important cases include but are not limited to:
|
||||
|
||||
@@ -1113,10 +1410,9 @@ for verification. Important cases include but are not limited to:
|
||||
- Incompatible modifications to versioned entities, such as added protocol
|
||||
conformances lacking versioning information.
|
||||
|
||||
- Unsafely-backdated "fragile" attributes as discussed in the `Giving Up
|
||||
Flexibility`_ section.
|
||||
- Unsafe `backdating <#backdating>`_.
|
||||
|
||||
- Unsafe modifications to entities marked with the "fragile" attributes, such as
|
||||
- Unsafe modifications to entities marked with fragility attributes, such as
|
||||
adding a stored property to a ``@fixed_contents`` struct.
|
||||
|
||||
|
||||
@@ -1145,8 +1441,8 @@ simple checker tool:
|
||||
in addition to *consuming* it.
|
||||
|
||||
- Occasionally a library owner may want to override the inferred versions. This
|
||||
can be accomplished by providing explicit versioning information, as in the
|
||||
proposal.
|
||||
can be accomplished by providing explicit versioning information, as
|
||||
described above.
|
||||
|
||||
- Bugs in the tool manifest as bugs in client programs.
|
||||
|
||||
@@ -1154,10 +1450,108 @@ Because this tool would require a fair amount of additional work, it is not
|
||||
part of this initial model. It is something we may decide to add in the future.
|
||||
|
||||
|
||||
Open Issues
|
||||
===========
|
||||
|
||||
There are still a number of known issues with the model described in this
|
||||
document. We should endeavour to account for each of them, and if we can't come
|
||||
up with a satisfactory implementation we should at least make sure that they
|
||||
will not turn into pitfalls for library or client developers.
|
||||
|
||||
|
||||
Subclass and base both conform to protocol
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
// Library, version 1
|
||||
class Elf {}
|
||||
protocol Summonable {}
|
||||
|
||||
::
|
||||
|
||||
// Client, version 1
|
||||
class ShoemakingElf : Elf, Summonable {}
|
||||
|
||||
::
|
||||
|
||||
// Library, version 2
|
||||
@available(2.0)
|
||||
extension Elf : Summonable {}
|
||||
|
||||
Now ``ShoemakingElf`` conforms to ``Summonable`` in two different ways, which
|
||||
may be incompatible (especially if ``Summonable`` had associated types or
|
||||
requirements involving ``Self``).
|
||||
|
||||
Additionally, the client can't even remove ``ShoemakingElf``'s conformance to
|
||||
``Summonable``, because it may itself be a library with other code depending on
|
||||
it. We could fix that with an annotation to explicitly inherent the conformance
|
||||
of ``Summonable`` from the base class, but even that may not be possible if
|
||||
there are incompatible associated types involved (because changing a member
|
||||
typealias is not a safe change).
|
||||
|
||||
One solution is to disallow adding a conformance for an existing protocol to a
|
||||
publicly-subclassable class.
|
||||
|
||||
|
||||
Recompiling changes a protocol's implementation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
// Library, version 1
|
||||
protocol MagicType {}
|
||||
protocol Wearable {}
|
||||
func use<T: MagicType>(item: T) {}
|
||||
|
||||
::
|
||||
|
||||
// Client, version 1
|
||||
struct Amulet : MagicType, Wearable {}
|
||||
use(Amulet())
|
||||
|
||||
::
|
||||
|
||||
// Library, version 2
|
||||
protocol MagicType {
|
||||
@available(2.0)
|
||||
func equip() { print("Equipped.") }
|
||||
}
|
||||
|
||||
extension Wearable where Self: MagicType {
|
||||
@available(2.0)
|
||||
func equip() { print("You put it on.") }
|
||||
}
|
||||
|
||||
func use<T: MagicType>(item: T) { item.equip() }
|
||||
|
||||
Before the client is recompiled, the implementation of ``equip()`` used for
|
||||
``Amulet`` instances can only be the default implementation, i.e. the one that
|
||||
prints "Equipped". However, recompiling the client will result in the
|
||||
constrained implementation being considered a "better" match for the protocol
|
||||
requirement, thus changing the behavior of the program.
|
||||
|
||||
This should never change the *meaning* of a program, since the default
|
||||
implementation for a newly-added requirement should always be *correct.*
|
||||
However, it may have significantly different performance characteristics or
|
||||
side effects that would make the difference in behavior a surprise.
|
||||
|
||||
This is similar to adding a new overload to an existing set of functions, which
|
||||
can also change the meaning of client code just by recompiling. However, the
|
||||
difference here is that the before-recompilation behavior was never requested
|
||||
or acknowledged by the client; it's just the best the library can do.
|
||||
|
||||
A possible solution here is to require the client to acknowledge the added
|
||||
requirement in some way when it is recompiled.
|
||||
|
||||
(We do not want to perform overload resolution at run time to find the best
|
||||
possible default implementation for a given type.)
|
||||
|
||||
|
||||
Summary
|
||||
=======
|
||||
|
||||
When possible, Swift gives library developers freedom to evolve their code
|
||||
When possible, Swift gives library authors freedom to evolve their code
|
||||
without breaking binary compatibility. This has implications for both the
|
||||
semantics and performance of client code, and so library owners also have tools
|
||||
to waive the ability to make certain future changes. The language guarantees
|
||||
@@ -1177,6 +1571,7 @@ document that affect language semantics:
|
||||
- (planned) Making classes "sealed" by default
|
||||
- (planned) Restricting retroactive modeling (protocol conformances for types you don't own)
|
||||
- (planned) Default implementations in protocols
|
||||
- (planned) Generalized existentials (values of protocol type)
|
||||
- (planned) Open and closed enums
|
||||
- (planned) Syntax for declaring "versioned" entities and their features
|
||||
- (planned) Syntax for declaring inlineable code
|
||||
|
||||
58
docs/SIL.rst
58
docs/SIL.rst
@@ -1047,11 +1047,10 @@ instances. Derived classes inherit the witness tables of their base class.
|
||||
Witness tables are keyed by *protocol conformance*, which is a unique identifier
|
||||
for a concrete type's conformance to a protocol.
|
||||
|
||||
- A *normal protocol conformance*
|
||||
names a (potentially unbound generic) type, the protocol it conforms to, and
|
||||
the module in which the type or extension declaration that provides the
|
||||
conformance appears. These correspond 1:1 to protocol conformance declarations
|
||||
in the source code.
|
||||
- A *normal protocol conformance* names a (potentially unbound generic) type,
|
||||
the protocol it conforms to, and the module in which the type or extension
|
||||
declaration that provides the conformance appears. These correspond 1:1 to
|
||||
protocol conformance declarations in the source code.
|
||||
- If a derived class conforms to a protocol through inheritance from its base
|
||||
class, this is represented by an *inherited protocol conformance*, which
|
||||
simply references the protocol conformance for the base class.
|
||||
@@ -1087,6 +1086,55 @@ Witness tables consist of the following entries:
|
||||
type to the protocol conformance that satisfies that requirement for the
|
||||
associated type.
|
||||
|
||||
Default Witness Tables
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
::
|
||||
|
||||
decl ::= sil-default-witness-table
|
||||
sil-default-witness-table ::= 'sil_default_witness_table'
|
||||
identifier minimum-witness-table-size
|
||||
'{' sil-default-witness-entry* '}'
|
||||
minimum-witness-table-size ::= integer
|
||||
|
||||
SIL encodes requirements with resilient default implementations in a default
|
||||
witness table. We say a requirement has a resilient default implementation if
|
||||
the following conditions hold:
|
||||
|
||||
- The requirement has a default implementation
|
||||
- The requirement is either the last requirement in the protocol, or all
|
||||
subsequent requirements also have resilient default implementations
|
||||
|
||||
The set of requirements with resilient default implementations is stored in
|
||||
protocol metadata.
|
||||
|
||||
The minimum witness table size is the size of the witness table, in words,
|
||||
not including any requirements with resilient default implementations.
|
||||
|
||||
Any conforming witness table must have a size between the minimum size, and
|
||||
the maximum size, which is equal to the minimum size plus the number of
|
||||
default requirements.
|
||||
|
||||
At load time, if the runtime encounters a witness table with fewer than the
|
||||
maximum number of witnesses, the witness table is copied, with default
|
||||
witnesses copied in. This ensures that callers can always expect to find
|
||||
the correct number of requirements in each witness table, and new
|
||||
requirements can be added by the framework author, without breaking client
|
||||
code, as long as the new requirements have resilient default implementations.
|
||||
|
||||
Default witness tables are keyed by the protocol itself. Only protocols with
|
||||
public visibility need a default witness table; private and internal protocols
|
||||
are never seen outside the module, therefore there are no resilience issues
|
||||
with adding new requirements.
|
||||
|
||||
::
|
||||
|
||||
sil-default-witness-entry ::= 'method' sil-decl-ref ':' sil-function-name
|
||||
|
||||
Default witness tables currently contain only one type of entry:
|
||||
|
||||
- *Method entries* map a method requirement of the protocol to a SIL function
|
||||
that implements that method in a manner suitable for all witness types.
|
||||
|
||||
Global Variables
|
||||
~~~~~~~~~~~~~~~~
|
||||
::
|
||||
|
||||
@@ -51,7 +51,7 @@ these targets in the build directory:
|
||||
|
||||
Runs all tests.
|
||||
|
||||
For day-to-day work on the Swift compiler, using check-swift should be
|
||||
For day-to-day work on the Swift compiler, using ``check-swift`` should be
|
||||
sufficient. The buildbot runs validation tests, so if those are accidentally
|
||||
broken, it should not go unnoticed.
|
||||
|
||||
@@ -62,10 +62,10 @@ test suite.
|
||||
For every target above, there are variants for different optimizations:
|
||||
|
||||
* the target itself (e.g., ``check-swift``) -- runs execution tests in
|
||||
``-Onone`` mode;
|
||||
``-Onone`` mode.
|
||||
|
||||
* the target with ``-optimize`` suffix (e.g., ``check-swift-optimize``) -- runs
|
||||
execution tests in ``-O`` mode; This target will only run tests marked as
|
||||
execution tests in ``-O`` mode. This target will only run tests marked as
|
||||
``executable_test``.
|
||||
|
||||
* the target with ``-optimize-unchecked`` suffix (e.g.,
|
||||
@@ -73,6 +73,10 @@ For every target above, there are variants for different optimizations:
|
||||
``-Ounchecked`` mode. This target will only run tests marked as
|
||||
``executable_test``.
|
||||
|
||||
* the target with ``-non-executable`` suffix (e.g.,
|
||||
``check-swift-non-executable-iphoneos-arm64``) -- runs tests not marked with
|
||||
``executable_test`` in ``-Onone`` mode.
|
||||
|
||||
If you need to manually run certain tests, you can invoke LLVM's lit.py script
|
||||
directly. For example::
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ Comparing Solutions
|
||||
The solver explores a potentially large solution space, and it is
|
||||
possible that it will find multiple solutions to the constraint system
|
||||
as given. Such cases are not necessarily ambiguities, because the
|
||||
solver can then compare the solutions to to determine whether one of
|
||||
solver can then compare the solutions to determine whether one of
|
||||
the solutions is better than all of the others. To do so, it computes
|
||||
a "score" for each solution based on a number of factors:
|
||||
|
||||
|
||||
@@ -249,7 +249,9 @@ class ProtocolDescriptorFlags {
|
||||
|
||||
SpecialProtocolMask = 0x000003C0U,
|
||||
SpecialProtocolShift = 6,
|
||||
|
||||
|
||||
IsResilient = 1U << 10U,
|
||||
|
||||
/// Reserved by the ObjC runtime.
|
||||
_ObjCReserved = 0xFFFF0000U,
|
||||
};
|
||||
@@ -277,6 +279,9 @@ public:
|
||||
return ProtocolDescriptorFlags((Data & ~SpecialProtocolMask)
|
||||
| (int_type(sp) << SpecialProtocolShift));
|
||||
}
|
||||
constexpr ProtocolDescriptorFlags withResilient(bool s) const {
|
||||
return ProtocolDescriptorFlags((Data & ~IsResilient) | (s ? IsResilient : 0));
|
||||
}
|
||||
|
||||
/// Was the protocol defined in Swift 1 or 2?
|
||||
bool isSwift() const { return Data & IsSwift; }
|
||||
@@ -313,6 +318,9 @@ public:
|
||||
>> SpecialProtocolShift));
|
||||
}
|
||||
|
||||
/// Can new requirements with default witnesses be added resiliently?
|
||||
bool isResilient() const { return Data & IsResilient; }
|
||||
|
||||
int_type getIntValue() const {
|
||||
return Data;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "swift/AST/ProtocolConformance.h"
|
||||
#include "swift/AST/SearchPathOptions.h"
|
||||
#include "swift/AST/Type.h"
|
||||
#include "swift/AST/TypeAlignments.h"
|
||||
#include "swift/Basic/LangOptions.h"
|
||||
#include "swift/Basic/Malloc.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
@@ -160,14 +161,6 @@ public:
|
||||
typedef llvm::PointerUnion<NominalTypeDecl *, ExtensionDecl *>
|
||||
TypeOrExtensionDecl;
|
||||
|
||||
/// An entry in the protocol conformance map.
|
||||
///
|
||||
/// The pointer is the actual conformance providing the witnesses used to
|
||||
/// provide conformance. The Boolean indicates whether the type explicitly
|
||||
/// conforms to the protocol. A non-null conformance with a false Bool occurs
|
||||
/// when error recovery has suggested implicit conformance.
|
||||
typedef llvm::PointerIntPair<ProtocolConformance *, 1, bool> ConformanceEntry;
|
||||
|
||||
/// ASTContext - This object creates and owns the AST objects.
|
||||
class ASTContext {
|
||||
ASTContext(const ASTContext&) = delete;
|
||||
@@ -221,11 +214,6 @@ public:
|
||||
#define IDENTIFIER_WITH_NAME(Name, IdStr) Identifier Id_##Name;
|
||||
#include "swift/AST/KnownIdentifiers.def"
|
||||
|
||||
// FIXME: Once DenseMap learns about move semantics, use std::unique_ptr
|
||||
// and remove the explicit delete loop in the destructor.
|
||||
typedef llvm::DenseMap<std::pair<CanType, ProtocolDecl *>,
|
||||
ConformanceEntry> ConformsToMap;
|
||||
|
||||
/// \brief The list of external definitions imported by this context.
|
||||
llvm::SetVector<Decl *> ExternalDefinitions;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include "clang/Basic/VersionTuple.h"
|
||||
|
||||
namespace swift {
|
||||
@@ -760,7 +761,10 @@ public:
|
||||
};
|
||||
|
||||
/// Indicates that the given declaration is visible to Objective-C.
|
||||
class ObjCAttr : public DeclAttribute {
|
||||
class ObjCAttr final : public DeclAttribute,
|
||||
private llvm::TrailingObjects<ObjCAttr, SourceLoc> {
|
||||
friend TrailingObjects;
|
||||
|
||||
/// The Objective-C name associated with this entity, stored in its opaque
|
||||
/// representation so that we can use null as an indicator for "no name".
|
||||
void *NameData;
|
||||
@@ -793,7 +797,7 @@ class ObjCAttr : public DeclAttribute {
|
||||
unsigned length = 2;
|
||||
if (auto name = getName())
|
||||
length += name->getNumSelectorPieces();
|
||||
return { reinterpret_cast<SourceLoc *>(this + 1), length };
|
||||
return {getTrailingObjects<SourceLoc>(), length};
|
||||
}
|
||||
|
||||
/// Retrieve the trailing location information.
|
||||
@@ -802,7 +806,7 @@ class ObjCAttr : public DeclAttribute {
|
||||
unsigned length = 2;
|
||||
if (auto name = getName())
|
||||
length += name->getNumSelectorPieces();
|
||||
return { reinterpret_cast<const SourceLoc *>(this + 1), length };
|
||||
return {getTrailingObjects<SourceLoc>(), length};
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user