Skip to content

Commit cfd3225

Browse files
Add Queue benchmark that tests popLast generically and concretely (#14393)
1 parent 73a7ebc commit cfd3225

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ set(SWIFT_BENCH_MODULES
113113
single-source/Prims
114114
single-source/ProtocolDispatch
115115
single-source/ProtocolDispatch2
116+
single-source/Queue
116117
single-source/RC4
117118
single-source/RGBHistogram
118119
single-source/RangeAssignment

benchmark/single-source/Queue.swift

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
//===--- RangeAssignment.swift --------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
import TestsUtils
14+
15+
public let QueueGeneric = BenchmarkInfo(
16+
name: "QueueGeneric",
17+
runFunction: run_QueueGeneric,
18+
tags: [.validation, .api],
19+
setUpFunction: { buildWorkload() },
20+
tearDownFunction: nil)
21+
22+
public let QueueConcrete = BenchmarkInfo(
23+
name: "QueueConcrete",
24+
runFunction: run_QueueConcrete,
25+
tags: [.validation, .api],
26+
setUpFunction: { buildWorkload() },
27+
tearDownFunction: nil)
28+
29+
// TODO: remove when there is a native equivalent in the std lib
30+
extension RangeReplaceableCollection where Self: BidirectionalCollection {
31+
@_inlineable
32+
public mutating func popLast() -> Element? {
33+
if isEmpty { return nil}
34+
else { return removeLast() }
35+
}
36+
}
37+
38+
public struct Queue<Storage: RangeReplaceableCollection>
39+
where Storage: BidirectionalCollection {
40+
public typealias Element = Storage.Element
41+
42+
internal var _in: Storage
43+
internal var _out: Storage
44+
45+
public init() {
46+
_in = Storage()
47+
_out = Storage()
48+
}
49+
}
50+
51+
extension Queue {
52+
public mutating func enqueue(_ newElement: Element) {
53+
_in.append(newElement)
54+
}
55+
56+
public mutating func dequeue() -> Element? {
57+
if _out.isEmpty {
58+
_out.append(contentsOf: _in.reversed())
59+
_in.removeAll()
60+
}
61+
return _out.popLast()
62+
}
63+
}
64+
65+
func testQueue<Elements: Collection>(elements: Elements)
66+
where Elements.Element: Equatable {
67+
var q = Queue<[Elements.Element]>()
68+
for x in elements { q.enqueue(x) }
69+
let results = sequence(state: q) { $0.dequeue() }
70+
let i = results.reduce(0, { i,_ in i &+ 1 })
71+
for x in elements { q.enqueue(x) }
72+
let j = results.reduce(i, { i,_ in i &+ 1 })
73+
CheckResults(j == elements.count*2)
74+
}
75+
76+
let n = 10_000
77+
let workload = (0..<n).map { "\($0): A long enough string to defeat the SSO, or so I hope." }
78+
79+
public func buildWorkload() {
80+
let contents = workload
81+
_ = contents.reduce(0) { $0 + $1.count }
82+
}
83+
84+
@inline(never)
85+
func run_QueueGeneric(_ scale: Int) {
86+
for _ in 0..<scale {
87+
testQueue(elements: workload)
88+
}
89+
}
90+
91+
public struct ConcreteQueue {
92+
internal var _in: [String]
93+
internal var _out: [String]
94+
95+
public init() {
96+
_in = Array()
97+
_out = Array()
98+
}
99+
}
100+
101+
extension ConcreteQueue {
102+
public mutating func enqueue(_ newElement: String) {
103+
_in.append(newElement)
104+
}
105+
106+
public mutating func dequeue() -> String? {
107+
if _out.isEmpty {
108+
_out.append(contentsOf: _in.reversed())
109+
_in.removeAll()
110+
}
111+
return _out.popLast()
112+
}
113+
}
114+
115+
func testConcreteQueue(elements: [String]) {
116+
var q = ConcreteQueue()
117+
for x in elements { q.enqueue(x) }
118+
let results = sequence(state: q) { $0.dequeue() }
119+
let i = results.reduce(0, { i,_ in i &+ 1 })
120+
for x in elements { q.enqueue(x) }
121+
let j = results.reduce(i, { i,_ in i &+ 1 })
122+
CheckResults(j == elements.count*2)
123+
}
124+
125+
126+
@inline(never)
127+
func run_QueueConcrete(_ scale: Int) {
128+
for _ in 0..<scale {
129+
testConcreteQueue(elements: workload)
130+
}
131+
}
132+

benchmark/utils/main.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ import Prims
101101
import PrimsSplit
102102
import ProtocolDispatch
103103
import ProtocolDispatch2
104+
import Queue
104105
import RC4
105106
import RGBHistogram
106107
import RangeAssignment
@@ -243,6 +244,8 @@ registerBenchmark(Prims)
243244
registerBenchmark(PrimsSplit)
244245
registerBenchmark(ProtocolDispatch)
245246
registerBenchmark(ProtocolDispatch2)
247+
registerBenchmark(QueueGeneric)
248+
registerBenchmark(QueueConcrete)
246249
registerBenchmark(RC4Test)
247250
registerBenchmark(RGBHistogram)
248251
registerBenchmark(RangeAssignment)

0 commit comments

Comments
 (0)