Merge remote-tracking branch 'origin/master' into swift-3-api-guidelines

This commit is contained in:
Max Moiseev
2016-02-15 15:43:34 -08:00
741 changed files with 22676 additions and 6395 deletions

3
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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
View 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
}
```

View 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()

View 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)

View 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())

View 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)

View 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)

View 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)

View 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])

View 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)

View 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)
)

View 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()

View 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

View 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)
}

View 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]).")
}

View 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)
}
}
}
}

View 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
}
}
}
}

View 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)
}
}
}
}

View 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)
}

View 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)")
}

View 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()
}
}

View 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()
}
}

View 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()
}
}

View 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()
}
}

View 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.")
}

View 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.")
}
}

View 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.")
}
}

View 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")
}

View 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)
}
}

View 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))
}
}
}
}
}

View 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)
}
}

View 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")
}

View 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).")
}

View 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)")
}

View 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)")
}

View 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()
}
}

View 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()
}
}

View 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.")
}

View 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)
}

View 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 _ {
}
}
}

View 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)")
}

View 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)
}
}

View 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")
}
}

View 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.")
}
}

View 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);
}

View 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(" ")
}

View 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)")
}

View 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")
}

View 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.")
}

View 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)")
}

View 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)")
}

View 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")
}

View 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
}
}
}

View 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
}
}

View 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.")
}
}

View 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")
}

View 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")
}

View 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()
}
}

View 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)
}

View 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)
}

View 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)")
}
}
}

View 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.")
}
}

View 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()
}
}

View 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")
}
}

View 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
}
}
}

View 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).")
}

View 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)")
}

View 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)
}

View 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")
}

View 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)
}
}

View 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.")
}
}

File diff suppressed because it is too large Load Diff

View 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])
}
}

View 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)")
}
}

View 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)")
}

View 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()
}
}

View 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)")
}
}

View 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 }
}
}

View 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)
}
}

View 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))
}
}
}
}
}

View 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!]).")
}
}
}

View 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>>>())
}
}

View 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)
}
}

View 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)")
}
}

View 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))
}

View 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))
}
}
}

View 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() }

View 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
View 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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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
~~~~~~~~~~~~~~~~
::

View File

@@ -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::

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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