Skip to content

Commit 7f1ba5d

Browse files
authored
Merge pull request #14992 from milseman/bench_builder
[benchmark] More StringBuilder/Interpolation benchmarks
2 parents 6755e73 + 87b2473 commit 7f1ba5d

File tree

3 files changed

+144
-19
lines changed

3 files changed

+144
-19
lines changed

benchmark/single-source/StringBuilder.swift

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,30 @@
1313
import TestsUtils
1414

1515
public let StringBuilder = [
16-
BenchmarkInfo(name: "StringAdder", runFunction: run_StringAdder, tags: [.validation, .api, .String]),
17-
BenchmarkInfo(name: "StringBuilder", runFunction: run_StringBuilder, tags: [.validation, .api, .String]),
18-
BenchmarkInfo(name: "StringBuilderLong", runFunction: run_StringBuilderLong, tags: [.validation, .api, .String]),
19-
BenchmarkInfo(name: "StringUTF16Builder", runFunction: run_StringUTF16Builder, tags: [.validation, .api, .String]),
16+
BenchmarkInfo(
17+
name: "StringAdder",
18+
runFunction: run_StringAdder,
19+
tags: [.validation, .api, .String]),
20+
BenchmarkInfo(
21+
name: "StringBuilder",
22+
runFunction: run_StringBuilder,
23+
tags: [.validation, .api, .String]),
24+
BenchmarkInfo(
25+
name: "StringUTF16Builder",
26+
runFunction: run_StringUTF16Builder,
27+
tags: [.validation, .api, .String]),
28+
BenchmarkInfo(
29+
name: "StringUTF16SubstringBuilder",
30+
runFunction: run_StringUTF16SubstringBuilder,
31+
tags: [.validation, .api, .String]),
32+
BenchmarkInfo(
33+
name: "StringBuilderLong",
34+
runFunction: run_StringBuilderLong,
35+
tags: [.validation, .api, .String]),
36+
BenchmarkInfo(
37+
name: "StringBuilderWithLongSubstring",
38+
runFunction: run_StringBuilderWithLongSubstring,
39+
tags: [.validation, .api, .String]),
2040
BenchmarkInfo(
2141
name: "StringWordBuilder",
2242
runFunction: run_StringWordBuilder,
@@ -29,7 +49,7 @@ public let StringBuilder = [
2949

3050
@inline(never)
3151
func buildString(_ i: String) -> String {
32-
var sb = i
52+
var sb = getString(i)
3353
for str in ["b","c","d","pizza"] {
3454
sb += str
3555
}
@@ -39,54 +59,95 @@ func buildString(_ i: String) -> String {
3959
@inline(never)
4060
public func run_StringBuilder(_ N: Int) {
4161
for _ in 1...5000*N {
42-
_ = buildString(getString("a"))
62+
blackHole(buildString("a"))
4363
}
4464
}
4565

4666
@inline(never)
4767
func addString(_ i: String) -> String {
48-
let s = i + "b" + "c" + "d" + "pizza"
68+
let s = getString(i) + "b" + "c" + "d" + "pizza"
4969
return s
5070
}
5171

5272
@inline(never)
5373
public func run_StringAdder(_ N: Int) {
5474
for _ in 1...5000*N {
55-
_ = addString(getString("a"))
75+
blackHole(addString("a"))
5676
}
5777
}
5878

5979
@inline(never)
6080
func buildStringUTF16(_ i: String) -> String {
61-
var sb = i
81+
var sb = getString(i)
6282
for str in ["🎉","c","d","pizza"] {
6383
sb += str
6484
}
6585
return sb
6686
}
6787

88+
@inline(never)
89+
func buildStringFromSmallSubstrings(_ i: String) -> String {
90+
var sb = getString(i)
91+
for str in ["_🎉","cd","de","pizza"] {
92+
sb += str.dropFirst()
93+
}
94+
return sb
95+
}
96+
6897
@inline(never)
6998
public func run_StringUTF16Builder(_ N: Int) {
7099
for _ in 1...5000*N {
71-
_ = buildStringUTF16("a")
100+
blackHole(buildStringUTF16("a"))
101+
}
102+
}
103+
104+
@inline(never)
105+
public func run_StringUTF16SubstringBuilder(_ N: Int) {
106+
for _ in 1...5000*N {
107+
blackHole(buildStringFromSmallSubstrings("a"))
72108
}
73109
}
74110

111+
func getLongString() -> String {
112+
let long = """
113+
Swift is a multi-paradigm, compiled programming language created for
114+
iOS, OS X, watchOS, tvOS and Linux development by Apple Inc. Swift is
115+
designed to work with Apple's Cocoa and Cocoa Touch frameworks and the
116+
large body of existing Objective-C code written for Apple products. Swift
117+
is intended to be more resilient to erroneous code (\"safer\") than
118+
Objective-C and also more concise. It is built with the LLVM compiler
119+
framework included in Xcode 6 and later and uses the Objective-C runtime,
120+
which allows C, Objective-C, C++ and Swift code to run within a single
121+
program.
122+
"""
123+
return getString(long)
124+
}
75125

76126
@inline(never)
77127
func buildStringLong(_ i: String) -> String {
78-
var sb = i
79-
let long = "Swift is a multi-paradigm, compiled programming language created for iOS, OS X, watchOS, tvOS and Linux development by Apple Inc. Swift is designed to work with Apple's Cocoa and Cocoa Touch frameworks and the large body of existing Objective-C code written for Apple products. Swift is intended to be more resilient to erroneous code (\"safer\") than Objective-C and also more concise. It is built with the LLVM compiler framework included in Xcode 6 and later and uses the Objective-C runtime, which allows C, Objective-C, C++ and Swift code to run within a single program."
80-
sb += long
128+
var sb = getString(i)
129+
sb += getLongString()
81130
return sb
82131
}
83132

84-
133+
@inline(never)
134+
func buildStringWithLongSubstring(_ i: String) -> String {
135+
var sb = getString(i)
136+
sb += getLongString().dropFirst()
137+
return sb
138+
}
85139

86140
@inline(never)
87141
public func run_StringBuilderLong(_ N: Int) {
88142
for _ in 1...5000*N {
89-
_ = buildStringLong("👻")
143+
blackHole(buildStringLong("👻"))
144+
}
145+
}
146+
147+
@inline(never)
148+
public func run_StringBuilderWithLongSubstring(_ N: Int) {
149+
for _ in 1...5000*N {
150+
blackHole(buildStringWithLongSubstring("👻"))
90151
}
91152
}
92153

@@ -96,6 +157,7 @@ func buildString(
96157
count: Int,
97158
reservingCapacity: Bool
98159
) -> String {
160+
let word = getString(word)
99161
var sb = ""
100162
if reservingCapacity {
101163
sb.reserveCapacity(count * word.unicodeScalars.count)
@@ -108,10 +170,12 @@ func buildString(
108170

109171
@inline(never)
110172
public func run_StringWordBuilder(_ N: Int) {
111-
_ = buildString(word: "bumfuzzle", count: 50_000 * N, reservingCapacity: false)
173+
blackHole(buildString(
174+
word: "bumfuzzle", count: 50_000 * N, reservingCapacity: false))
112175
}
113176

114177
@inline(never)
115178
public func run_StringWordBuilderReservingCapacity(_ N: Int) {
116-
_ = buildString(word: "bumfuzzle", count: 50_000 * N, reservingCapacity: true)
179+
blackHole(buildString(
180+
word: "bumfuzzle", count: 50_000 * N, reservingCapacity: true))
117181
}

benchmark/single-source/StringInterpolation.swift

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ public let StringInterpolation = BenchmarkInfo(
1616
name: "StringInterpolation",
1717
runFunction: run_StringInterpolation,
1818
tags: [.validation, .api, .String])
19+
public let StringInterpolationSmall = BenchmarkInfo(
20+
name: "StringInterpolationSmall",
21+
runFunction: run_StringInterpolationSmall,
22+
tags: [.validation, .api, .String])
23+
public let StringInterpolationManySmallSegments = BenchmarkInfo(
24+
name: "StringInterpolationManySmallSegments",
25+
runFunction: run_StringInterpolationManySmallSegments,
26+
tags: [.validation, .api, .String])
1927

2028
class RefTypePrintable : CustomStringConvertible {
2129
var description: String {
@@ -33,15 +41,66 @@ public func run_StringInterpolation(_ N: Int) {
3341
for _ in 1...100*N {
3442
var result = 0
3543
for _ in 1...reps {
36-
let s = "\(anInt) abcdefdhijklmn \(aRefCountedObject) abcdefdhijklmn \u{01}"
44+
let s: String = getString(
45+
"\(anInt) abcdefdhijklmn \(aRefCountedObject) abcdefdhijklmn \u{01}")
3746
let utf16 = s.utf16
3847

3948
// FIXME: if String is not stored as UTF-16 on this platform, then the
4049
// following operation has a non-trivial cost and needs to be replaced
4150
// with an operation on the native storage type.
42-
result = result &+ Int(utf16[utf16.index(before: utf16.endIndex)])
51+
result = result &+ Int(utf16.last!)
52+
blackHole(s)
53+
}
54+
CheckResults(result == refResult)
55+
}
56+
}
57+
58+
@inline(never)
59+
public func run_StringInterpolationSmall(_ N: Int) {
60+
let reps = 100
61+
let refResult = reps
62+
let anInt: Int64 = 0x42
63+
64+
for _ in 1...100*N {
65+
var result = 0
66+
for _ in 1...reps {
67+
let s: String = getString(
68+
"\(getString("int")): \(anInt) \(getString("abc")) \u{01}")
69+
result = result &+ Int(s.utf8.last!)
70+
blackHole(s)
4371
}
4472
CheckResults(result == refResult)
4573
}
4674
}
4775

76+
@inline(never)
77+
public func run_StringInterpolationManySmallSegments(_ N: Int) {
78+
let numHex = min(UInt64(N), 0x0FFF_FFFF_FFFF_FFFF)
79+
let numOct = min(UInt64(N), 0x0000_03FF_FFFF_FFFF)
80+
let numBin = min(UInt64(N), 0x7FFF)
81+
let segments = [
82+
"abc",
83+
String(numHex, radix: 16),
84+
"0123456789",
85+
String(Double.pi/2),
86+
"*barely* small!",
87+
String(numOct, radix: 8),
88+
"",
89+
String(numBin, radix: 2),
90+
]
91+
assert(segments.count == 8)
92+
93+
func getSegment(_ i: Int) -> String {
94+
return getString(segments[i])
95+
}
96+
97+
let reps = 100
98+
for _ in 1...100*N {
99+
for _ in 1...reps {
100+
blackHole("""
101+
\(getSegment(0)) \(getSegment(1))/\(getSegment(2))_\(getSegment(3))
102+
\(getSegment(4)) \(getSegment(5)), \(getSegment(6))~~\(getSegment(7))
103+
""")
104+
}
105+
}
106+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ registerBenchmark(StringComparison)
280280
registerBenchmark(StringEdits)
281281
registerBenchmark(StringEnum)
282282
registerBenchmark(StringInterpolation)
283+
registerBenchmark(StringInterpolationSmall)
284+
registerBenchmark(StringInterpolationManySmallSegments)
283285
registerBenchmark(StringMatch)
284286
registerBenchmark(StringRemoveDupes)
285287
registerBenchmark(StringTests)

0 commit comments

Comments
 (0)