Skip to content

Commit cc69069

Browse files
authored
[benchmark] Review and extend Heap benchmarks (apple#76)
* [benchmark] Review and extend Heap benchmarks * FoundationBenchmark only supports Apple platforms * Rewrite CFBinaryHeap benchmarks in pure Swift
1 parent 940c963 commit cc69069

19 files changed

+476
-196
lines changed

Benchmarks/Benchmarks/CppBenchmarks.swift

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,49 @@ internal class CppUnorderedMap {
9696
}
9797
}
9898

99+
internal class CppPriorityQueue {
100+
var ptr: UnsafeMutableRawPointer?
101+
102+
init(_ input: [Int]) {
103+
self.ptr = input.withUnsafeBufferPointer { buffer in
104+
cpp_priority_queue_create(buffer.baseAddress, buffer.count)
105+
}
106+
}
107+
108+
convenience init() {
109+
self.init([])
110+
}
111+
112+
deinit {
113+
destroy()
114+
}
115+
116+
func destroy() {
117+
if let ptr = ptr {
118+
cpp_priority_queue_destroy(ptr)
119+
}
120+
ptr = nil
121+
}
122+
123+
func push(_ value: Int) {
124+
cpp_priority_queue_push(ptr, value)
125+
}
126+
127+
func push(_ values: [Int]) {
128+
values.withUnsafeBufferPointer { buffer in
129+
cpp_priority_queue_push_loop(ptr, buffer.baseAddress, buffer.count)
130+
}
131+
}
132+
133+
func pop() -> Int {
134+
cpp_priority_queue_pop(ptr)
135+
}
136+
137+
func popAll() {
138+
cpp_priority_queue_pop_all(ptr)
139+
}
140+
}
141+
99142

100143
extension Benchmark {
101144
public mutating func addCppBenchmarks() {
@@ -625,5 +668,43 @@ extension Benchmark {
625668
map.destroy()
626669
}
627670
}
671+
672+
//--------------------------------------------------------------------------
673+
674+
self.addSimple(
675+
title: "std::priority_queue<intptr_t> construct from buffer",
676+
input: [Int].self
677+
) { input in
678+
let pq = CppPriorityQueue(input)
679+
blackHole(pq)
680+
}
681+
682+
self.add(
683+
title: "std::priority_queue<intptr_t> push",
684+
input: [Int].self
685+
) { input in
686+
return { timer in
687+
let pq = CppPriorityQueue()
688+
timer.measure {
689+
pq.push(input)
690+
}
691+
blackHole(pq)
692+
pq.destroy()
693+
}
694+
}
695+
696+
self.add(
697+
title: "std::priority_queue<intptr_t> pop",
698+
input: [Int].self
699+
) { input in
700+
return { timer in
701+
let pq = CppPriorityQueue(input)
702+
timer.measure {
703+
pq.popAll()
704+
}
705+
blackHole(pq)
706+
pq.destroy()
707+
}
708+
}
628709
}
629710
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Collections open source project
4+
//
5+
// Copyright (c) 2021 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+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
import CollectionsBenchmark
13+
14+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
15+
import Foundation
16+
17+
extension CFBinaryHeap {
18+
internal static func _create(capacity: Int) -> CFBinaryHeap {
19+
var callbacks = CFBinaryHeapCallBacks(
20+
version: 0,
21+
retain: nil,
22+
release: nil,
23+
copyDescription: { value in
24+
let result = "\(Int(bitPattern: value))" as NSString
25+
return Unmanaged.passRetained(result)
26+
},
27+
compare: { left, right, context in
28+
let left = Int(bitPattern: left)
29+
let right = Int(bitPattern: right)
30+
if left == right { return .compareEqualTo }
31+
if left < right { return .compareLessThan }
32+
return .compareGreaterThan
33+
})
34+
return CFBinaryHeapCreate(kCFAllocatorDefault, capacity, &callbacks, nil)
35+
}
36+
}
37+
#endif
38+
39+
extension Benchmark {
40+
public mutating func addFoundationBenchmarks() {
41+
self.add(
42+
title: "CFBinaryHeapAddValue",
43+
input: [Int].self
44+
) { input in
45+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
46+
return { timer in
47+
let heap = CFBinaryHeap._create(capacity: 0)
48+
timer.measure {
49+
for value in input {
50+
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
51+
}
52+
}
53+
blackHole(heap)
54+
}
55+
#else
56+
// CFBinaryHeap isn't available
57+
return nil
58+
#endif
59+
}
60+
61+
self.add(
62+
title: "CFBinaryHeapAddValue, reserving capacity",
63+
input: [Int].self
64+
) { input in
65+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
66+
return { timer in
67+
let heap = CFBinaryHeap._create(capacity: input.count)
68+
timer.measure {
69+
for value in input {
70+
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
71+
}
72+
}
73+
blackHole(heap)
74+
}
75+
#else
76+
return nil
77+
#endif
78+
}
79+
80+
self.add(
81+
title: "CFBinaryHeapRemoveMinimumValue",
82+
input: [Int].self
83+
) { input in
84+
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
85+
return { timer in
86+
let heap = CFBinaryHeap._create(capacity: input.count)
87+
for value in input {
88+
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
89+
}
90+
timer.measure {
91+
for _ in 0 ..< input.count {
92+
blackHole(CFBinaryHeapGetMinimum(heap))
93+
CFBinaryHeapRemoveMinimumValue(heap)
94+
}
95+
}
96+
blackHole(heap)
97+
}
98+
#else
99+
return nil
100+
#endif
101+
}
102+
}
103+
}

Benchmarks/Benchmarks/PriorityQueueBenchmarks.swift renamed to Benchmarks/Benchmarks/HeapBenchmarks.swift

Lines changed: 7 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ extension Benchmark {
2222
blackHole(Heap(0..<size))
2323
}
2424

25+
self.addSimple(
26+
title: "Heap<Int> init from buffer",
27+
input: [Int].self
28+
) { input in
29+
blackHole(Heap(input))
30+
}
31+
2532
self.addSimple(
2633
title: "Heap<Int> insert",
2734
input: [Int].self
@@ -79,44 +86,3 @@ extension Benchmark {
7986
}
8087
}
8188
}
82-
83-
// MARK: -
84-
85-
extension Benchmark {
86-
public mutating func addCFBinaryHeapBenchmarks() {
87-
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
88-
self.addSimple(
89-
title: "CFBinaryHeap insert",
90-
input: [Int].self
91-
) { input in
92-
let heap = BinaryHeap()
93-
for i in input {
94-
heap.insert(i)
95-
}
96-
precondition(heap.count == input.count)
97-
blackHole(heap)
98-
}
99-
100-
self.add(
101-
title: "CFBinaryHeap removeMinimumValue",
102-
input: [Int].self
103-
) { input in
104-
return { timer in
105-
let heap = BinaryHeap()
106-
for i in input {
107-
heap.insert(i)
108-
}
109-
110-
timer.measure {
111-
while heap.count > 0 {
112-
let min = heap.popMinimum()
113-
blackHole(min)
114-
}
115-
}
116-
precondition(heap.count == 0)
117-
blackHole(heap)
118-
}
119-
}
120-
#endif
121-
}
122-
}

Benchmarks/Benchmarks/Library.json

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -761,47 +761,48 @@
761761
]
762762
},
763763
]
764-
}
765-
]
766-
},
767-
{
768-
"kind": "group",
769-
"title": "PriorityQueue",
770-
"contents": [
771-
{
772-
"kind": "chart",
773-
"title": "operations",
774-
"tasks": [
775-
"Heap<Int> init from range",
776-
"Heap<Int> insert",
777-
"Heap<Int> insert(contentsOf:)",
778-
"Heap<Int> popMax",
779-
"Heap<Int> popMin"
780-
]
781764
},
782765
{
783-
"kind": "chart",
784-
"title": "initializers",
785-
"tasks": [
786-
"Heap<Int> init from range"
787-
]
788-
},
789-
{
790-
"kind": "chart",
791-
"title": "insert",
792-
"tasks": [
793-
"Heap<Int> insert",
794-
"Heap<Int> insert(contentsOf:)"
766+
"kind": "group",
767+
"title": "Heap",
768+
"contents": [
769+
{
770+
"kind": "chart",
771+
"title": "operations",
772+
"tasks": [
773+
"Heap<Int> init from range",
774+
"Heap<Int> insert",
775+
"Heap<Int> insert(contentsOf:)",
776+
"Heap<Int> popMax",
777+
"Heap<Int> popMin"
778+
]
779+
},
780+
{
781+
"kind": "chart",
782+
"title": "initializers",
783+
"tasks": [
784+
"Heap<Int> init from range",
785+
"Heap<Int> init from buffer"
786+
]
787+
},
788+
{
789+
"kind": "chart",
790+
"title": "insert",
791+
"tasks": [
792+
"Heap<Int> insert",
793+
"Heap<Int> insert(contentsOf:)"
794+
]
795+
},
796+
{
797+
"kind": "chart",
798+
"title": "remove",
799+
"tasks": [
800+
"Heap<Int> popMax",
801+
"Heap<Int> popMin"
802+
]
803+
}
795804
]
796805
},
797-
{
798-
"kind": "chart",
799-
"title": "remove",
800-
"tasks": [
801-
"Heap<Int> popMax",
802-
"Heap<Int> popMin"
803-
]
804-
}
805806
]
806807
},
807808
{
@@ -2035,6 +2036,40 @@
20352036
},
20362037
]
20372038
},
2039+
{
2040+
"kind": "group",
2041+
"title": "Heap vs std::priority_queue",
2042+
"directory": "Heap + priority_queue",
2043+
"contents": [
2044+
{
2045+
"kind": "chart",
2046+
"title": "initializers",
2047+
"tasks": [
2048+
"std::priority_queue<intptr_t> construct from buffer",
2049+
"Heap<Int> init from buffer",
2050+
]
2051+
},
2052+
{
2053+
"kind": "chart",
2054+
"title": "insert",
2055+
"tasks": [
2056+
"std::priority_queue<intptr_t> push",
2057+
"CFBinaryHeapAddValue",
2058+
"Heap<Int> insert"
2059+
]
2060+
},
2061+
{
2062+
"kind": "chart",
2063+
"title": "pop",
2064+
"tasks": [
2065+
"std::priority_queue<intptr_t> pop",
2066+
"CFBinaryHeapRemoveMinimumValue",
2067+
"Heap<Int> popMin",
2068+
"Heap<Int> popMax"
2069+
]
2070+
},
2071+
]
2072+
}
20382073
]
20392074
},
20402075
]

0 commit comments

Comments
 (0)