Skip to content

Commit 1836401

Browse files
committed
[benchmark] Add RandomTree benchmark
1 parent 073e44d commit 1836401

File tree

3 files changed

+257
-0
lines changed

3 files changed

+257
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ set(SWIFT_BENCH_MODULES
141141
single-source/RGBHistogram
142142
single-source/Radix2CooleyTukey
143143
single-source/RandomShuffle
144+
single-source/RandomTree
144145
single-source/RandomValues
145146
single-source/RangeAssignment
146147
single-source/RangeIteration
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
//===--- RandomTree.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+
//===----------------------------------------------------------------------===//
12+
13+
// This test implements three competing versions of randomized binary trees,
14+
// indirectly testing reference counting performance.
15+
16+
import TestsUtils
17+
18+
var rng = SplitMix64(seed: 0)
19+
let count = 10_000
20+
let input = (0 ..< count).shuffled(using: &rng)
21+
22+
public let RandomTree = [
23+
BenchmarkInfo(
24+
name: "RandomTree.insert.ADT",
25+
runFunction: run_ADT_insert,
26+
tags: [.validation, .algorithm, .refcount],
27+
setUpFunction: { blackHole(input) }),
28+
BenchmarkInfo(
29+
name: "RandomTree.insert.Unmanaged",
30+
runFunction: run_Unmanaged_insert,
31+
tags: [.validation, .algorithm, .refcount],
32+
setUpFunction: { blackHole(input) }),
33+
BenchmarkInfo(
34+
name: "RandomTree.insert.UnsafePointer",
35+
runFunction: run_UnsafePointer_insert,
36+
tags: [.validation, .algorithm, .refcount],
37+
setUpFunction: { blackHole(input) }),
38+
]
39+
40+
enum EnumSearchTree<Element: Comparable> {
41+
case empty
42+
indirect case node(EnumSearchTree<Element>, Element, EnumSearchTree<Element>)
43+
}
44+
45+
extension EnumSearchTree {
46+
func forEach(_ body: (Element) -> Void) {
47+
switch self {
48+
case .empty:
49+
break
50+
case let .node(left, value, right):
51+
left.forEach(body)
52+
body(value)
53+
right.forEach(body)
54+
}
55+
}
56+
57+
func contains(_ value: Element) -> Bool {
58+
switch self {
59+
case .empty:
60+
return false
61+
case let .node(left, v, right):
62+
if value == v { return true }
63+
return value < v ? left.contains(value) : right.contains(value)
64+
}
65+
}
66+
67+
func inserting(_ value: __owned Element) -> EnumSearchTree {
68+
switch self {
69+
case .empty:
70+
return .node(.empty, value, .empty)
71+
case let .node(left, root, right):
72+
if value == root {
73+
return self
74+
} else if value < root {
75+
return .node(left.inserting(value), root, right)
76+
} else {
77+
return .node(left, root, right.inserting(value))
78+
}
79+
}
80+
}
81+
}
82+
83+
struct UnmanagedSearchTree<Element: Comparable> {
84+
class Node {
85+
var value: Element
86+
var left: UnmanagedSearchTree
87+
var right: UnmanagedSearchTree
88+
89+
init(
90+
value: Element,
91+
left: UnmanagedSearchTree = .empty,
92+
right: UnmanagedSearchTree = .empty
93+
) {
94+
self.left = left
95+
self.right = right
96+
self.value = value
97+
}
98+
}
99+
100+
static var empty: UnmanagedSearchTree<Element> { UnmanagedSearchTree() }
101+
102+
var root: Unmanaged<Node>?
103+
104+
init() {
105+
self.root = nil
106+
}
107+
108+
init(_root: Unmanaged<Node>?) {
109+
self.root = _root
110+
}
111+
}
112+
113+
extension UnmanagedSearchTree {
114+
mutating func deallocate() {
115+
guard let root = root else { return }
116+
root._withUnsafeGuaranteedRef { root in
117+
root.left.deallocate()
118+
root.right.deallocate()
119+
}
120+
withExtendedLifetime(root) {}
121+
}
122+
}
123+
124+
extension UnmanagedSearchTree {
125+
func forEach(_ body: (Element) -> Void) {
126+
guard let root = root else { return }
127+
root._withUnsafeGuaranteedRef { root in
128+
root.left.forEach(body)
129+
body(root.value)
130+
root.right.forEach(body)
131+
}
132+
}
133+
134+
func contains(_ value: Element) -> Bool {
135+
guard let root = root else { return false }
136+
return root._withUnsafeGuaranteedRef { root in
137+
if value == root.value { return true }
138+
return value < root.value
139+
? root.left.contains(value)
140+
: root.right.contains(value)
141+
}
142+
}
143+
144+
mutating func insert(_ value: __owned Element) {
145+
guard let root = root else {
146+
self.root = Unmanaged.passRetained(Node(value: value))
147+
return
148+
}
149+
root._withUnsafeGuaranteedRef { root in
150+
if value == root.value {
151+
return
152+
} else if value < root.value {
153+
root.left.insert(value)
154+
} else {
155+
root.right.insert(value)
156+
}
157+
}
158+
}
159+
}
160+
161+
struct PointerSearchTree<Element: Comparable> {
162+
struct Node {
163+
var value: Element
164+
var left: PointerSearchTree = .empty
165+
var right: PointerSearchTree = .empty
166+
}
167+
168+
static var empty: PointerSearchTree<Element> { PointerSearchTree() }
169+
170+
var root: UnsafeMutablePointer<Node>?
171+
172+
init() {
173+
self.root = nil
174+
}
175+
176+
init(_root: UnsafeMutablePointer<Node>?) {
177+
self.root = _root
178+
}
179+
}
180+
181+
extension PointerSearchTree {
182+
mutating func deallocate() {
183+
guard let root = root else { return }
184+
root.pointee.left.deallocate()
185+
root.pointee.right.deallocate()
186+
}
187+
}
188+
189+
extension PointerSearchTree {
190+
func forEach(_ body: (Element) -> Void) {
191+
guard let root = root else { return }
192+
root.pointee.left.forEach(body)
193+
body(root.pointee.value)
194+
root.pointee.right.forEach(body)
195+
}
196+
197+
func contains(_ value: Element) -> Bool {
198+
guard let root = root else { return false }
199+
if value == root.pointee.value { return true }
200+
if value < root.pointee.value { return root.pointee.left.contains(value) }
201+
return root.pointee.right.contains(value)
202+
}
203+
204+
mutating func insert(_ value: __owned Element) {
205+
guard let root = root else {
206+
let node = UnsafeMutablePointer<Node>.allocate(capacity: 1)
207+
node.initialize(to: Node(value: value))
208+
self.root = node
209+
return
210+
}
211+
if value == root.pointee.value {
212+
return
213+
} else if value < root.pointee.value {
214+
root.pointee.left.insert(value)
215+
} else {
216+
root.pointee.right.insert(value)
217+
}
218+
}
219+
}
220+
221+
222+
223+
func run_ADT_insert(_ iterations: Int) {
224+
for _ in 0 ..< iterations {
225+
var tree = identity(EnumSearchTree<Int>.empty)
226+
for value in input {
227+
tree = tree.inserting(value)
228+
}
229+
blackHole(tree)
230+
}
231+
}
232+
233+
func run_Unmanaged_insert(_ iterations: Int) {
234+
for _ in 0 ..< iterations {
235+
var tree = identity(UnmanagedSearchTree<Int>.empty)
236+
for value in input {
237+
tree.insert(value)
238+
}
239+
blackHole(tree)
240+
tree.deallocate()
241+
}
242+
}
243+
244+
func run_UnsafePointer_insert(_ iterations: Int) {
245+
for _ in 0 ..< iterations {
246+
var tree = identity(PointerSearchTree<Int>.empty)
247+
for value in input {
248+
tree.insert(value)
249+
}
250+
blackHole(tree)
251+
tree.deallocate()
252+
}
253+
}
254+

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ import RC4
136136
import RGBHistogram
137137
import Radix2CooleyTukey
138138
import RandomShuffle
139+
import RandomTree
139140
import RandomValues
140141
import RangeAssignment
141142
import RangeIteration
@@ -320,6 +321,7 @@ registerBenchmark(RC4Test)
320321
registerBenchmark(RGBHistogram)
321322
registerBenchmark(Radix2CooleyTukey)
322323
registerBenchmark(RandomShuffle)
324+
registerBenchmark(RandomTree)
323325
registerBenchmark(RandomValues)
324326
registerBenchmark(RangeAssignment)
325327
registerBenchmark(RangeIteration)

0 commit comments

Comments
 (0)