Skip to content

Commit

Permalink
[benchmark] Review and extend Heap benchmarks (#76)
Browse files Browse the repository at this point in the history
* [benchmark] Review and extend Heap benchmarks

* FoundationBenchmark only supports Apple platforms

* Rewrite CFBinaryHeap benchmarks in pure Swift
  • Loading branch information
lorentey authored Aug 7, 2021
1 parent 940c963 commit cc69069
Show file tree
Hide file tree
Showing 19 changed files with 476 additions and 196 deletions.
81 changes: 81 additions & 0 deletions Benchmarks/Benchmarks/CppBenchmarks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,49 @@ internal class CppUnorderedMap {
}
}

internal class CppPriorityQueue {
var ptr: UnsafeMutableRawPointer?

init(_ input: [Int]) {
self.ptr = input.withUnsafeBufferPointer { buffer in
cpp_priority_queue_create(buffer.baseAddress, buffer.count)
}
}

convenience init() {
self.init([])
}

deinit {
destroy()
}

func destroy() {
if let ptr = ptr {
cpp_priority_queue_destroy(ptr)
}
ptr = nil
}

func push(_ value: Int) {
cpp_priority_queue_push(ptr, value)
}

func push(_ values: [Int]) {
values.withUnsafeBufferPointer { buffer in
cpp_priority_queue_push_loop(ptr, buffer.baseAddress, buffer.count)
}
}

func pop() -> Int {
cpp_priority_queue_pop(ptr)
}

func popAll() {
cpp_priority_queue_pop_all(ptr)
}
}


extension Benchmark {
public mutating func addCppBenchmarks() {
Expand Down Expand Up @@ -625,5 +668,43 @@ extension Benchmark {
map.destroy()
}
}

//--------------------------------------------------------------------------

self.addSimple(
title: "std::priority_queue<intptr_t> construct from buffer",
input: [Int].self
) { input in
let pq = CppPriorityQueue(input)
blackHole(pq)
}

self.add(
title: "std::priority_queue<intptr_t> push",
input: [Int].self
) { input in
return { timer in
let pq = CppPriorityQueue()
timer.measure {
pq.push(input)
}
blackHole(pq)
pq.destroy()
}
}

self.add(
title: "std::priority_queue<intptr_t> pop",
input: [Int].self
) { input in
return { timer in
let pq = CppPriorityQueue(input)
timer.measure {
pq.popAll()
}
blackHole(pq)
pq.destroy()
}
}
}
}
103 changes: 103 additions & 0 deletions Benchmarks/Benchmarks/FoundationBenchmarks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

import CollectionsBenchmark

#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
import Foundation

extension CFBinaryHeap {
internal static func _create(capacity: Int) -> CFBinaryHeap {
var callbacks = CFBinaryHeapCallBacks(
version: 0,
retain: nil,
release: nil,
copyDescription: { value in
let result = "\(Int(bitPattern: value))" as NSString
return Unmanaged.passRetained(result)
},
compare: { left, right, context in
let left = Int(bitPattern: left)
let right = Int(bitPattern: right)
if left == right { return .compareEqualTo }
if left < right { return .compareLessThan }
return .compareGreaterThan
})
return CFBinaryHeapCreate(kCFAllocatorDefault, capacity, &callbacks, nil)
}
}
#endif

extension Benchmark {
public mutating func addFoundationBenchmarks() {
self.add(
title: "CFBinaryHeapAddValue",
input: [Int].self
) { input in
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
return { timer in
let heap = CFBinaryHeap._create(capacity: 0)
timer.measure {
for value in input {
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
}
}
blackHole(heap)
}
#else
// CFBinaryHeap isn't available
return nil
#endif
}

self.add(
title: "CFBinaryHeapAddValue, reserving capacity",
input: [Int].self
) { input in
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
return { timer in
let heap = CFBinaryHeap._create(capacity: input.count)
timer.measure {
for value in input {
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
}
}
blackHole(heap)
}
#else
return nil
#endif
}

self.add(
title: "CFBinaryHeapRemoveMinimumValue",
input: [Int].self
) { input in
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
return { timer in
let heap = CFBinaryHeap._create(capacity: input.count)
for value in input {
CFBinaryHeapAddValue(heap, UnsafeRawPointer(bitPattern: value))
}
timer.measure {
for _ in 0 ..< input.count {
blackHole(CFBinaryHeapGetMinimum(heap))
CFBinaryHeapRemoveMinimumValue(heap)
}
}
blackHole(heap)
}
#else
return nil
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ extension Benchmark {
blackHole(Heap(0..<size))
}

self.addSimple(
title: "Heap<Int> init from buffer",
input: [Int].self
) { input in
blackHole(Heap(input))
}

self.addSimple(
title: "Heap<Int> insert",
input: [Int].self
Expand Down Expand Up @@ -79,44 +86,3 @@ extension Benchmark {
}
}
}

// MARK: -

extension Benchmark {
public mutating func addCFBinaryHeapBenchmarks() {
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
self.addSimple(
title: "CFBinaryHeap insert",
input: [Int].self
) { input in
let heap = BinaryHeap()
for i in input {
heap.insert(i)
}
precondition(heap.count == input.count)
blackHole(heap)
}

self.add(
title: "CFBinaryHeap removeMinimumValue",
input: [Int].self
) { input in
return { timer in
let heap = BinaryHeap()
for i in input {
heap.insert(i)
}

timer.measure {
while heap.count > 0 {
let min = heap.popMinimum()
blackHole(min)
}
}
precondition(heap.count == 0)
blackHole(heap)
}
}
#endif
}
}
109 changes: 72 additions & 37 deletions Benchmarks/Benchmarks/Library.json
Original file line number Diff line number Diff line change
Expand Up @@ -761,47 +761,48 @@
]
},
]
}
]
},
{
"kind": "group",
"title": "PriorityQueue",
"contents": [
{
"kind": "chart",
"title": "operations",
"tasks": [
"Heap<Int> init from range",
"Heap<Int> insert",
"Heap<Int> insert(contentsOf:)",
"Heap<Int> popMax",
"Heap<Int> popMin"
]
},
{
"kind": "chart",
"title": "initializers",
"tasks": [
"Heap<Int> init from range"
]
},
{
"kind": "chart",
"title": "insert",
"tasks": [
"Heap<Int> insert",
"Heap<Int> insert(contentsOf:)"
"kind": "group",
"title": "Heap",
"contents": [
{
"kind": "chart",
"title": "operations",
"tasks": [
"Heap<Int> init from range",
"Heap<Int> insert",
"Heap<Int> insert(contentsOf:)",
"Heap<Int> popMax",
"Heap<Int> popMin"
]
},
{
"kind": "chart",
"title": "initializers",
"tasks": [
"Heap<Int> init from range",
"Heap<Int> init from buffer"
]
},
{
"kind": "chart",
"title": "insert",
"tasks": [
"Heap<Int> insert",
"Heap<Int> insert(contentsOf:)"
]
},
{
"kind": "chart",
"title": "remove",
"tasks": [
"Heap<Int> popMax",
"Heap<Int> popMin"
]
}
]
},
{
"kind": "chart",
"title": "remove",
"tasks": [
"Heap<Int> popMax",
"Heap<Int> popMin"
]
}
]
},
{
Expand Down Expand Up @@ -2035,6 +2036,40 @@
},
]
},
{
"kind": "group",
"title": "Heap vs std::priority_queue",
"directory": "Heap + priority_queue",
"contents": [
{
"kind": "chart",
"title": "initializers",
"tasks": [
"std::priority_queue<intptr_t> construct from buffer",
"Heap<Int> init from buffer",
]
},
{
"kind": "chart",
"title": "insert",
"tasks": [
"std::priority_queue<intptr_t> push",
"CFBinaryHeapAddValue",
"Heap<Int> insert"
]
},
{
"kind": "chart",
"title": "pop",
"tasks": [
"std::priority_queue<intptr_t> pop",
"CFBinaryHeapRemoveMinimumValue",
"Heap<Int> popMin",
"Heap<Int> popMax"
]
},
]
}
]
},
]
Expand Down
Loading

0 comments on commit cc69069

Please sign in to comment.