Skip to content
This repository was archived by the owner on Apr 23, 2021. It is now read-only.

Commit c78c490

Browse files
authored
Merge pull request #14 from ktoso/benchmarks
+simple benchmarks to have a gut feeling how mutating and the CoW cos…
2 parents 63f427d + 3ebd624 commit c78c490

File tree

9 files changed

+1745
-1
lines changed

9 files changed

+1745
-1
lines changed

Package.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,30 @@ let package = Package(
1111
name: "Baggage",
1212
dependencies: []
1313
),
14+
15+
// ==== --------------------------------------------------------------------------------------------------------
16+
// MARK: Tests
17+
1418
.testTarget(
1519
name: "BaggageTests",
1620
dependencies: [
1721
"Baggage"
1822
]
19-
)
23+
),
24+
25+
// ==== --------------------------------------------------------------------------------------------------------
26+
// MARK: Performance / Benchmarks
27+
28+
.target(
29+
name: "Benchmarks",
30+
dependencies: [
31+
"Baggage",
32+
"SwiftBenchmarkTools",
33+
]
34+
),
35+
.target(
36+
name: "SwiftBenchmarkTools",
37+
dependencies: []
38+
),
2039
]
2140
)
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Baggage Context open source project
4+
//
5+
// Copyright (c) 2020 Moritz Lang and the Swift Baggage Context project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
//
10+
// SPDX-License-Identifier: Apache-2.0
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
import Baggage
15+
import Dispatch
16+
import class Foundation.NSLock
17+
import SwiftBenchmarkTools
18+
public let BaggagePassingBenchmarks: [BenchmarkInfo] = [
19+
// ==== ----------------------------------------------------------------------------------------------------------------
20+
// MARK: "Read only" context passing around
21+
BenchmarkInfo(
22+
name: "BaggagePassingBenchmarks.pass_async_empty_100_000 ",
23+
runFunction: { _ in
24+
let context = BaggageContext()
25+
pass_async(context: context, times: 100_000)
26+
},
27+
tags: [],
28+
setUpFunction: { setUp() },
29+
tearDownFunction: tearDown
30+
),
31+
BenchmarkInfo(
32+
name: "BaggagePassingBenchmarks.pass_async_smol_100_000 ",
33+
runFunction: { _ in
34+
var context = BaggageContext()
35+
context.k1 = "one"
36+
context.k2 = "two"
37+
context.k3 = "three"
38+
context.k4 = "four"
39+
pass_async(context: context, times: 100_000)
40+
},
41+
tags: [],
42+
setUpFunction: { setUp() },
43+
tearDownFunction: tearDown
44+
),
45+
BenchmarkInfo(
46+
name: "BaggagePassingBenchmarks.pass_async_small_nonconst_100_000",
47+
runFunction: { _ in
48+
var context = BaggageContext()
49+
context.k1 = "\(Int.random(in: 1 ... Int.max))"
50+
context.k2 = "\(Int.random(in: 1 ... Int.max))"
51+
context.k3 = "\(Int.random(in: 1 ... Int.max))"
52+
context.k4 = "\(Int.random(in: 1 ... Int.max))"
53+
pass_async(context: context, times: 100_000)
54+
},
55+
tags: [],
56+
setUpFunction: { setUp() },
57+
tearDownFunction: tearDown
58+
),
59+
60+
// ==== ------------------------------------------------------------------------------------------------------------
61+
// MARK: Passing & Mutating
62+
// Since the context is backed by a dictionary (and nothing else) we rely on its CoW semantics, those writes cause copies
63+
// whilst the previous benchmarks which are read-only do not cause copies of the underlying storage (dictionary).
64+
65+
BenchmarkInfo(
66+
name: "BaggagePassingBenchmarks.pass_mut_async_small_100_000 ",
67+
runFunction: { _ in
68+
var context = BaggageContext()
69+
context.k1 = "\(Int.random(in: 1 ... Int.max))"
70+
context.k2 = "\(Int.random(in: 1 ... Int.max))"
71+
context.k3 = "\(Int.random(in: 1 ... Int.max))"
72+
context.k4 = "\(Int.random(in: 1 ... Int.max))"
73+
pass_mut_async(context: context, times: 100_000)
74+
},
75+
tags: [],
76+
setUpFunction: { setUp() },
77+
tearDownFunction: tearDown
78+
),
79+
]
80+
81+
private func setUp() {
82+
// ...
83+
}
84+
85+
private func tearDown() {
86+
// ...
87+
}
88+
89+
@inline(never)
90+
func pass_async(context: BaggageContext, times remaining: Int) {
91+
let latch = CountDownLatch(from: 1)
92+
93+
func pass_async0(context: BaggageContext, times remaining: Int) {
94+
if remaining == 0 {
95+
latch.countDown()
96+
}
97+
DispatchQueue.global().async {
98+
pass_async0(context: context, times: remaining - 1)
99+
}
100+
}
101+
102+
pass_async0(context: context, times: remaining - 1)
103+
104+
latch.wait()
105+
}
106+
107+
@inline(never)
108+
func pass_mut_async(context: BaggageContext, times remaining: Int) {
109+
var context = context
110+
let latch = CountDownLatch(from: 1)
111+
112+
func pass_async0(context: BaggageContext, times remaining: Int) {
113+
if remaining == 0 {
114+
latch.countDown()
115+
}
116+
117+
DispatchQueue.global().async {
118+
// mutate the context
119+
var context = context
120+
context.passCounter = remaining
121+
122+
pass_async0(context: context, times: remaining - 1)
123+
}
124+
}
125+
126+
context.passCounter = remaining
127+
pass_async0(context: context, times: remaining - 1)
128+
129+
latch.wait()
130+
}
131+
132+
// ==== ----------------------------------------------------------------------------------------------------------------
133+
// MARK: Baggage Keys
134+
135+
private enum TestPassCounterKey: BaggageContextKey {
136+
typealias Value = Int
137+
}
138+
139+
private enum TestK1: BaggageContextKey {
140+
typealias Value = String
141+
}
142+
143+
private enum TestK2: BaggageContextKey {
144+
typealias Value = String
145+
}
146+
147+
private enum TestK3: BaggageContextKey {
148+
typealias Value = String
149+
}
150+
151+
private enum TestK4: BaggageContextKey {
152+
typealias Value = String
153+
}
154+
155+
private enum TestKD1: BaggageContextKey {
156+
typealias Value = [String: String]
157+
}
158+
159+
extension BaggageContext {
160+
fileprivate var passCounter: TestPassCounterKey.Value {
161+
get { self[TestPassCounterKey.self] ?? 0 }
162+
set { self[TestPassCounterKey.self] = newValue }
163+
}
164+
165+
fileprivate var k1: TestK1.Value? {
166+
get { self[TestK1.self] }
167+
set { self[TestK1.self] = newValue }
168+
}
169+
170+
fileprivate var k2: TestK2.Value? {
171+
get { self[TestK2.self] }
172+
set { self[TestK2.self] = newValue }
173+
}
174+
175+
fileprivate var k3: TestK3.Value? {
176+
get { self[TestK3.self] }
177+
set { self[TestK3.self] = newValue }
178+
}
179+
180+
fileprivate var k4: TestK4.Value? {
181+
get { self[TestK4.self] }
182+
set { self[TestK4.self] = newValue }
183+
}
184+
185+
fileprivate var kd1: TestKD1.Value? {
186+
get { self[TestKD1.self] }
187+
set { self[TestKD1.self] = newValue }
188+
}
189+
}

0 commit comments

Comments
 (0)