Skip to content

Commit 350d0c3

Browse files
authored
Merge pull request #30041 from lorentey/RandomTree
[benchmark] Add RandomTree benchmark
2 parents 49017c8 + 4804425 commit 350d0c3

File tree

3 files changed

+343
-0
lines changed

3 files changed

+343
-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: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
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 = 400
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.slow",
30+
runFunction: run_SlowUnmanaged_insert,
31+
tags: [.validation, .algorithm, .refcount],
32+
setUpFunction: { blackHole(input) }),
33+
BenchmarkInfo(
34+
name: "RandomTree.insert.Unmanaged.fast",
35+
runFunction: run_FastUnmanaged_insert,
36+
tags: [.validation, .algorithm, .refcount],
37+
setUpFunction: { blackHole(input) }),
38+
BenchmarkInfo(
39+
name: "RandomTree.insert.UnsafePointer",
40+
runFunction: run_UnsafePointer_insert,
41+
tags: [.validation, .algorithm, .refcount],
42+
setUpFunction: { blackHole(input) }),
43+
]
44+
45+
enum EnumSearchTree<Element: Comparable> {
46+
case empty
47+
indirect case node(EnumSearchTree<Element>, Element, EnumSearchTree<Element>)
48+
}
49+
50+
extension EnumSearchTree {
51+
func forEach(_ body: (Element) -> Void) {
52+
switch self {
53+
case .empty:
54+
break
55+
case let .node(left, value, right):
56+
left.forEach(body)
57+
body(value)
58+
right.forEach(body)
59+
}
60+
}
61+
62+
func contains(_ value: Element) -> Bool {
63+
switch self {
64+
case .empty:
65+
return false
66+
case let .node(left, v, right):
67+
if value == v { return true }
68+
return value < v ? left.contains(value) : right.contains(value)
69+
}
70+
}
71+
72+
func inserting(_ value: __owned Element) -> EnumSearchTree {
73+
switch self {
74+
case .empty:
75+
return .node(.empty, value, .empty)
76+
case let .node(left, root, right):
77+
if value == root {
78+
return self
79+
} else if value < root {
80+
return .node(left.inserting(value), root, right)
81+
} else {
82+
return .node(left, root, right.inserting(value))
83+
}
84+
}
85+
}
86+
}
87+
88+
struct SlowUnmanagedSearchTree<Element: Comparable> {
89+
class Node {
90+
var value: Element
91+
var left: SlowUnmanagedSearchTree
92+
var right: SlowUnmanagedSearchTree
93+
94+
init(
95+
value: Element,
96+
left: SlowUnmanagedSearchTree = .empty,
97+
right: SlowUnmanagedSearchTree = .empty
98+
) {
99+
self.left = left
100+
self.right = right
101+
self.value = value
102+
}
103+
}
104+
105+
static var empty: SlowUnmanagedSearchTree<Element> { SlowUnmanagedSearchTree() }
106+
107+
var root: Unmanaged<Node>?
108+
109+
init() {
110+
self.root = nil
111+
}
112+
113+
init(_root: Unmanaged<Node>?) {
114+
self.root = _root
115+
}
116+
}
117+
118+
extension SlowUnmanagedSearchTree {
119+
mutating func deallocate() {
120+
guard let root = root?.takeRetainedValue() else { return }
121+
root.left.deallocate()
122+
root.right.deallocate()
123+
}
124+
}
125+
126+
extension SlowUnmanagedSearchTree {
127+
func forEach(_ body: (Element) -> Void) {
128+
guard let root = root?.takeUnretainedValue() else { return }
129+
root.left.forEach(body)
130+
body(root.value)
131+
root.right.forEach(body)
132+
}
133+
134+
func contains(_ value: Element) -> Bool {
135+
guard let root = root?.takeUnretainedValue() else { return false }
136+
if value == root.value { return true }
137+
return value < root.value
138+
? root.left.contains(value)
139+
: root.right.contains(value)
140+
}
141+
142+
mutating func insert(_ value: __owned Element) {
143+
guard let root = root?.takeUnretainedValue() else {
144+
self.root = Unmanaged.passRetained(Node(value: value))
145+
return
146+
}
147+
if value == root.value {
148+
return
149+
} else if value < root.value {
150+
root.left.insert(value)
151+
} else {
152+
root.right.insert(value)
153+
}
154+
}
155+
}
156+
157+
struct FastUnmanagedSearchTree<Element: Comparable> {
158+
class Node {
159+
var value: Element
160+
var left: FastUnmanagedSearchTree
161+
var right: FastUnmanagedSearchTree
162+
163+
init(
164+
value: Element,
165+
left: FastUnmanagedSearchTree = .empty,
166+
right: FastUnmanagedSearchTree = .empty
167+
) {
168+
self.left = left
169+
self.right = right
170+
self.value = value
171+
}
172+
}
173+
174+
static var empty: FastUnmanagedSearchTree<Element> { FastUnmanagedSearchTree() }
175+
176+
var root: Unmanaged<Node>?
177+
178+
init() {
179+
self.root = nil
180+
}
181+
182+
init(_root: Unmanaged<Node>?) {
183+
self.root = _root
184+
}
185+
}
186+
187+
extension FastUnmanagedSearchTree {
188+
mutating func deallocate() {
189+
guard let root = root else { return }
190+
root._withUnsafeGuaranteedRef { root in
191+
root.left.deallocate()
192+
root.right.deallocate()
193+
}
194+
root.release()
195+
}
196+
}
197+
198+
extension FastUnmanagedSearchTree {
199+
func forEach(_ body: (Element) -> Void) {
200+
guard let root = root else { return }
201+
root._withUnsafeGuaranteedRef { root in
202+
root.left.forEach(body)
203+
body(root.value)
204+
root.right.forEach(body)
205+
}
206+
}
207+
208+
func contains(_ value: Element) -> Bool {
209+
guard let root = root else { return false }
210+
return root._withUnsafeGuaranteedRef { root in
211+
if value == root.value { return true }
212+
return value < root.value
213+
? root.left.contains(value)
214+
: root.right.contains(value)
215+
}
216+
}
217+
218+
mutating func insert(_ value: __owned Element) {
219+
guard let root = root else {
220+
self.root = Unmanaged.passRetained(Node(value: value))
221+
return
222+
}
223+
root._withUnsafeGuaranteedRef { root in
224+
if value == root.value {
225+
return
226+
} else if value < root.value {
227+
root.left.insert(value)
228+
} else {
229+
root.right.insert(value)
230+
}
231+
}
232+
}
233+
}
234+
235+
struct PointerSearchTree<Element: Comparable> {
236+
struct Node {
237+
var value: Element
238+
var left: PointerSearchTree = .empty
239+
var right: PointerSearchTree = .empty
240+
}
241+
242+
static var empty: PointerSearchTree<Element> { PointerSearchTree() }
243+
244+
var root: UnsafeMutablePointer<Node>?
245+
246+
init() {
247+
self.root = nil
248+
}
249+
250+
init(_root: UnsafeMutablePointer<Node>?) {
251+
self.root = _root
252+
}
253+
}
254+
255+
extension PointerSearchTree {
256+
mutating func deallocate() {
257+
guard let root = root else { return }
258+
root.pointee.left.deallocate()
259+
root.pointee.right.deallocate()
260+
root.deallocate()
261+
}
262+
}
263+
264+
extension PointerSearchTree {
265+
func forEach(_ body: (Element) -> Void) {
266+
guard let root = root else { return }
267+
root.pointee.left.forEach(body)
268+
body(root.pointee.value)
269+
root.pointee.right.forEach(body)
270+
}
271+
272+
func contains(_ value: Element) -> Bool {
273+
guard let root = root else { return false }
274+
if value == root.pointee.value { return true }
275+
if value < root.pointee.value { return root.pointee.left.contains(value) }
276+
return root.pointee.right.contains(value)
277+
}
278+
279+
mutating func insert(_ value: __owned Element) {
280+
guard let root = root else {
281+
let node = UnsafeMutablePointer<Node>.allocate(capacity: 1)
282+
node.initialize(to: Node(value: value))
283+
self.root = node
284+
return
285+
}
286+
if value == root.pointee.value {
287+
return
288+
} else if value < root.pointee.value {
289+
root.pointee.left.insert(value)
290+
} else {
291+
root.pointee.right.insert(value)
292+
}
293+
}
294+
}
295+
296+
297+
298+
func run_ADT_insert(_ iterations: Int) {
299+
for _ in 0 ..< iterations {
300+
var tree = identity(EnumSearchTree<Int>.empty)
301+
for value in input {
302+
tree = tree.inserting(value)
303+
}
304+
blackHole(tree)
305+
}
306+
}
307+
308+
func run_SlowUnmanaged_insert(_ iterations: Int) {
309+
for _ in 0 ..< iterations {
310+
var tree = identity(SlowUnmanagedSearchTree<Int>.empty)
311+
for value in input {
312+
tree.insert(value)
313+
}
314+
blackHole(tree)
315+
tree.deallocate()
316+
}
317+
}
318+
319+
func run_FastUnmanaged_insert(_ iterations: Int) {
320+
for _ in 0 ..< iterations {
321+
var tree = identity(FastUnmanagedSearchTree<Int>.empty)
322+
for value in input {
323+
tree.insert(value)
324+
}
325+
blackHole(tree)
326+
tree.deallocate()
327+
}
328+
}
329+
330+
func run_UnsafePointer_insert(_ iterations: Int) {
331+
for _ in 0 ..< iterations {
332+
var tree = identity(PointerSearchTree<Int>.empty)
333+
for value in input {
334+
tree.insert(value)
335+
}
336+
blackHole(tree)
337+
tree.deallocate()
338+
}
339+
}
340+

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)