Skip to content

Commit 7e9b46e

Browse files
committed
Add SortArrayInClass benchmark.
This currently copies the array each time it swaps elements. This makes it 1500x slower than it should be to sort the array. The benchmark now runs in 15ms but should be around 10us when fully optimized. This algorithm is an interesting optimization problem involving array optimization, uniqueness, bounds checks, and exclusivity. But the general first order problem is how to modify a CoW data structure that's stored in a class property. As it stands, the property getter retains the class property around the modify accesses that checks uniqueness.
1 parent 1afd0f7 commit 7e9b46e

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ set(SWIFT_BENCH_MODULES
151151
single-source/SetTests
152152
single-source/SevenBoom
153153
single-source/Sim2DArray
154+
single-source/SortArrayInClass
154155
single-source/SortIntPyramids
155156
single-source/SortLargeExistentials
156157
single-source/SortLettersInPlace
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//===--- SortArrayInClass.swift -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
// This benchmark is derived from user code that encoutered a major
12+
// performance problem in normal usage. Contributed by Saleem
13+
// Abdulrasool (compnerd).
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
import TestsUtils
18+
19+
// Specifically tests efficient access to Array subscript when the
20+
// array is a class property, but also generally tests quicksort in a
21+
// class which needs a slew of array optimizations, uniqueness, bounds
22+
// and exclusivity optimizations.
23+
public let SortArrayInClass = [
24+
BenchmarkInfo(
25+
name: "SortArrayInClass",
26+
runFunction: run_SortArrayInClass,
27+
tags: [.abstraction, .safetychecks, .exclusivity, .algorithm, .api, .Array])
28+
]
29+
30+
let LARGE_ARRAY_SIZE = 10000
31+
32+
class Sorter {
33+
var array: [Int]
34+
init(size: Int) {
35+
array = Array((0..<size).reversed())
36+
}
37+
38+
private func _swap(i: Int, j: Int) {
39+
let t = array[i]
40+
// This currently copies the entire array. Assigning to a
41+
// temporary, or using swapAt would avoid the copy, but users
42+
// shouldn't need to know that.
43+
array[i] = array[j]
44+
array[j] = t
45+
}
46+
47+
private func _quicksort(left: Int, right: Int) {
48+
49+
if left < right {
50+
let pivot = array[left + ((right - left) / 2)]
51+
var left_new = left
52+
var right_new = right
53+
54+
repeat {
55+
while array[left_new] < pivot {
56+
left_new += 1
57+
}
58+
while pivot < array[right_new] {
59+
right_new -= 1
60+
}
61+
if left_new <= right_new {
62+
_swap(i:left_new, j:right_new)
63+
left_new += 1
64+
right_new -= 1
65+
}
66+
} while left_new <= right_new
67+
68+
_quicksort(left: left, right: right_new)
69+
_quicksort(left: left_new, right:right)
70+
}
71+
}
72+
73+
func quicksort() {
74+
_quicksort(left:0, right:array.count - 1);
75+
}
76+
}
77+
78+
public func run_SortArrayInClass(_ N: Int) {
79+
for _ in 1...N {
80+
// The array needs to be reinitialized before each sort, so it
81+
// can't be a setup/tearDown function.
82+
let sorter = Sorter(size:LARGE_ARRAY_SIZE)
83+
sorter.quicksort()
84+
}
85+
}

benchmark/utils/TestsUtils.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public enum BenchmarkCategory : String {
2828
case runtime, refcount, metadata
2929
// Other general areas of compiled code validation.
3030
case abstraction, safetychecks, exceptions, bridging, concurrency, existential
31+
case exclusivity
3132

3233
// Algorithms are "micro" that test some well-known algorithm in isolation:
3334
// sorting, searching, hashing, fibonaci, crypto, etc.

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ import SequenceAlgos
146146
import SetTests
147147
import SevenBoom
148148
import Sim2DArray
149+
import SortArrayInClass
149150
import SortIntPyramids
150151
import SortLargeExistentials
151152
import SortLettersInPlace
@@ -325,6 +326,7 @@ registerBenchmark(SequenceAlgos)
325326
registerBenchmark(SetTests)
326327
registerBenchmark(SevenBoom)
327328
registerBenchmark(Sim2DArray)
329+
registerBenchmark(SortArrayInClass)
328330
registerBenchmark(SortIntPyramids)
329331
registerBenchmark(SortLargeExistentials)
330332
registerBenchmark(SortLettersInPlace)

0 commit comments

Comments
 (0)