diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml
index 1fdd088..c5f2d1b 100644
--- a/.github/workflows/benchmarks.yml
+++ b/.github/workflows/benchmarks.yml
@@ -36,6 +36,7 @@ jobs:
r-version: ['4.1.2']
lua-version: ['2.0.5'] # Note: Not used as benchmark is broken.
go-version: ['1.17.4'] # Note: Not used as benchmark is broken.
+ swift-version: ['5.5.3']
steps:
- uses: actions/checkout@v3
@@ -99,6 +100,10 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
+ - name: "Set up Swift"
+ uses: fwal/setup-swift@v1
+ with:
+ swift-version: ${{ matrix.swift-version }}
- name: "Run benchmark"
run: |
JULIAHOME=~/julia DSFMTDIR=~/dSFMT/ make gh_action_benchmarks.html
diff --git a/Makefile b/Makefile
index 6f8988d..9ffe201 100644
--- a/Makefile
+++ b/Makefile
@@ -134,8 +134,12 @@ benchmarks/rust.csv: rust/src/main.rs rust/src/util.rs rust/Cargo.lock
cd rust
@for t in $(ITERATIONS); do cargo run --release -q; done >../$@
-LANGUAGES = c fortran go java javascript julia lua mathematica matlab octave python r rust
-GH_ACTION_LANGUAGES = c fortran java javascript julia python r rust
+benchmarks/swift.csv: swift/main.swift
+ cd swift
+ @for t in $(ITERATIONS); do swift run; done >../$@
+
+LANGUAGES = c fortran go java javascript julia lua mathematica matlab octave python r rust swift
+GH_ACTION_LANGUAGES = c fortran java javascript julia python r rust swift
# These were formerly listed in LANGUAGES, but I can't get them to run
# 2017-09-27 johnfgibson
diff --git a/README.md b/README.md
index 6a1a009..a034728 100644
--- a/README.md
+++ b/README.md
@@ -32,3 +32,4 @@ Note that this refers to GNU Make, so BSD users will need to run `gmake`.
* Rust
* Scala
* Stata
+* Swift
diff --git a/bin/table.jl b/bin/table.jl
index a0e0664..1c80fd7 100755
--- a/bin/table.jl
+++ b/bin/table.jl
@@ -48,6 +48,7 @@ const labels = Dict{String, String}(
"octave" => "Octave" ,
"go" => "Go" ,
"rust" => "Rust" ,
+ "swift" => "Swift" ,
)
# Produce the sorting order for the list of languages
diff --git a/bin/versions.sh b/bin/versions.sh
index 5964303..fe88fb1 100755
--- a/bin/versions.sh
+++ b/bin/versions.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# User argument declaring what languages to query:
-DEFAULT_LANGUAGES="c:fortran:go:java:javascript:julia:lua:mathematica:matlab:octave:python:r:rust"
+DEFAULT_LANGUAGES="c:fortran:go:java:javascript:julia:lua:mathematica:matlab:octave:python:r:rust:swift"
LANGUAGES=${1:-DEFAULT_LANGUAGES}
LANGUAGES=":${LANGUAGES}:"
@@ -72,3 +72,8 @@ if [[ $LANGUAGES == *":rust:"* ]]; then
echo -n "rust,"
(cd rust; rustc --version | cut -c 7- | sed 's/ ([0-9a-f]* /
(/g')
fi
+
+if [[ $LANGUAGES == *":swift:"* ]]; then
+ echo -n "swift,"
+ swift --version | grep "version" | cut -f3 -d" "
+fi
diff --git a/swift/Package.swift b/swift/Package.swift
new file mode 100644
index 0000000..8f167cb
--- /dev/null
+++ b/swift/Package.swift
@@ -0,0 +1,19 @@
+// swift-tools-version:5.5.3
+
+import PackageDescription
+
+let package = Package(
+ name: "PerfSwift",
+ dependencies: [
+ .package(url: "https://github.com/apple/swift-numerics", from: "1.0.0"),
+ ],
+ targets: [
+ .executableTarget(
+ name: "PerfSwift",
+ dependencies: [
+ .product(name: "Numerics", package: "swift-numerics"),
+ ],
+ path: "."
+ ),
+ ]
+)
diff --git a/swift/main.swift b/swift/main.swift
new file mode 100644
index 0000000..0eac8e3
--- /dev/null
+++ b/swift/main.swift
@@ -0,0 +1,222 @@
+import Dispatch
+import Foundation
+import Numerics
+
+func fib(_ n: Int) -> Int {
+ if n < 2 {
+ return n
+ }
+ return fib(n-1) + fib(n-2)
+}
+
+func parse_integers(_ t: Int) {
+ for _ in 1 ..< t {
+ let n = Int.random(in: 0...((2 << 32) - 1))
+ let s = "\(n)"
+ let m = Int(s)
+ assert(m == n)
+ }
+}
+
+func qsort_kernel(_ a: inout [Double], _ lo: Int, _ hi: Int) -> [Double] {
+ var low = lo
+ let high = hi
+ var i = low
+ var j = high
+ while i < high {
+ let pivot = a[(low + high) / 2]
+ while i <= j {
+ while a[i] < pivot {
+ i += 1
+ }
+ while a[j] > pivot {
+ j -= 1
+ }
+ if i <= j {
+ let tmp = a[i]
+ a[i] = a[j]
+ a[j] = tmp
+ i += 1
+ j -= 1
+ }
+ }
+ if low < j {
+ a = qsort_kernel(&a, low, j)
+ }
+ low = i
+ j = high
+ }
+ return a
+}
+
+// FIXME
+func randmatstat(_ t: Int) -> (Double, Double) {
+ // let n = 5
+ // var v = [Double](count: t, repeatedValue: 0.0)
+ // var w = [Double](count: t, repeatedValue: 0.0)
+ for _ in 1...t {
+ }
+ // return (std(v)/mean(v), std(w)/mean(w))
+ return (0.75, 0.75)
+}
+
+// FIXME
+func randmatmul(_ n: Int) -> [[Int]] {
+ return [[0]]
+}
+
+func abs2(_ z: Complex) -> Double {
+ return z.real*z.real + z.imaginary*z.imaginary
+}
+
+func mandel(_ z: Complex) -> Int {
+ let maxiter = 80
+ var y = z
+ let c = z
+ for n in 1...maxiter {
+ if (abs2(y) > 4.0) {
+ return n - 1
+ }
+ y = y * y + c
+ }
+ return maxiter
+}
+
+func mandelperf() -> [Int] {
+ let eps = 0.01 // stride will stop short due to numerical imprecision
+ let r1 = stride(from: -2.0, to: 0.5 + eps, by: 0.1)
+ let r2 = stride(from: -1.0, to: 1.0 + eps, by: 0.1)
+ var mandelset = [Int]()
+ for r in r1 {
+ for i in r2 {
+ mandelset.append(mandel(Complex(r, i)))
+ }
+ }
+ return mandelset
+}
+
+func pisum() -> Double {
+ var sum = 0.0
+ for _ in 1...500 {
+ sum = 0.0
+ for k in stride(from: 1.0, to: 10000.0, by: 1.0) {
+ sum += 1.0/(k*k)
+ }
+ }
+ return sum
+}
+
+func printfd(_ n: Int) {
+ let file_url = URL(fileURLWithPath: "/dev/null")
+ let f = try! FileHandle(forWritingTo: file_url)
+ for i in 1...n {
+ let str = "\(i) \(i + 1)"
+ let data = Data(str.utf8)
+ f.write(data)
+ }
+ f.closeFile()
+}
+
+func print_perf(name: String, time: Double) {
+ print("swift," + name + "," + String(time))
+}
+
+// run tests
+func main() {
+ let mintrials = 5
+
+ assert(fib(20) == 6765)
+ var tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ _ = fib(20)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "recursion_fibonacci", time: tmin)
+
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ parse_integers(1000)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "parse_integers", time: tmin)
+
+ // mandelperf has numerical errors workaround true assert value
+ // assert(mandelperf().reduce(0, +) == 14791)
+ assert(mandelperf().reduce(0, +) == 14643)
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ _ = mandelperf()
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "userfunc_mandelbrot", time: tmin)
+
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ var lst = [Double]()
+ for _ in 0 ..< 50000 {
+ let random_double = Double.random(in: 0..<1)
+ lst.append(random_double)
+ }
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ _ = qsort_kernel(&lst, 0, lst.count-1)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "recursion_quicksort", time: tmin)
+
+ assert(abs(pisum()-1.644834071848065) < 1e-6)
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ _ = pisum()
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "iteration_pi_sum", time: tmin)
+
+ let (s1, s2) = randmatstat(1000)
+ assert(s1 > 0.5 && s2 < 1.0)
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ _ = randmatstat(100)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "matrix_statistics", time: tmin)
+
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ let C = randmatmul(1000)
+ assert(C[0][0] >= 0)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "matrix_multiply", time: tmin)
+
+ tmin = Double.greatestFiniteMagnitude
+ for _ in 1...mintrials {
+ let start_time = DispatchTime.now().uptimeNanoseconds
+ printfd(100000)
+ let end_time = DispatchTime.now().uptimeNanoseconds
+ let t = Double(end_time - start_time) / 1_000_000
+ if t < tmin {tmin = t}
+ }
+ print_perf(name: "print_to_file", time: tmin)
+}
+
+main()