Skip to content

Commit 9d5dd75

Browse files
authored
Merge pull request swiftlang#34435 from valeriyvan/StringDecodeUTF16Benchmark
Add benchmarks for UTF16 decoding
2 parents 90708d1 + e0966d6 commit 9d5dd75

File tree

3 files changed

+226
-0
lines changed

3 files changed

+226
-0
lines changed

benchmark/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ set(SWIFT_BENCH_MODULES
198198
single-source/TwoSum
199199
single-source/TypeFlood
200200
single-source/UTF8Decode
201+
single-source/UTF16Decode
201202
single-source/Walsh
202203
single-source/WordCount
203204
single-source/XorLoop
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
//===--- UTF16Decode.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+
import Foundation
15+
16+
public let benchmarks = [
17+
BenchmarkInfo(
18+
name: "UTF16Decode",
19+
runFunction: run_UTF16Decode,
20+
tags: [.validation, .api, .String],
21+
setUpFunction: setUp),
22+
BenchmarkInfo(
23+
name: "UTF16Decode.initFromCustom.cont",
24+
runFunction: run_UTF16Decode_InitFromCustom_contiguous,
25+
tags: [.validation, .api, .String],
26+
setUpFunction: setUp),
27+
BenchmarkInfo(
28+
name: "UTF16Decode.initFromCustom.cont.ascii",
29+
runFunction: run_UTF16Decode_InitFromCustom_contiguous_ascii,
30+
tags: [.validation, .api, .String, .skip],
31+
setUpFunction: setUp),
32+
BenchmarkInfo(
33+
name: "UTF16Decode.initFromCustom.noncont",
34+
runFunction: run_UTF16Decode_InitFromCustom_noncontiguous,
35+
tags: [.validation, .api, .String],
36+
setUpFunction: setUp),
37+
BenchmarkInfo(
38+
name: "UTF16Decode.initFromCustom.noncont.ascii",
39+
runFunction: run_UTF16Decode_InitFromCustom_noncontiguous_ascii,
40+
tags: [.validation, .api, .String, .skip],
41+
setUpFunction: setUp),
42+
BenchmarkInfo(
43+
name: "UTF16Decode.initFromData",
44+
runFunction: run_UTF16Decode_InitFromData,
45+
tags: [.validation, .api, .String],
46+
setUpFunction: setUp),
47+
BenchmarkInfo(
48+
name: "UTF16Decode.initDecoding",
49+
runFunction: run_UTF16Decode_InitDecoding,
50+
tags: [.validation, .api, .String],
51+
setUpFunction: setUp),
52+
BenchmarkInfo(
53+
name: "UTF16Decode.initFromData.ascii",
54+
runFunction: run_UTF16Decode_InitFromData_ascii,
55+
tags: [.validation, .api, .String, .skip],
56+
setUpFunction: setUp),
57+
BenchmarkInfo(
58+
name: "UTF16Decode.initDecoding.ascii",
59+
runFunction: run_UTF16Decode_InitDecoding_ascii,
60+
tags: [.validation, .api, .String, .skip],
61+
setUpFunction: setUp),
62+
BenchmarkInfo(
63+
name: "UTF16Decode.initFromData.asciiAsAscii",
64+
runFunction: run_UTF16Decode_InitFromData_ascii_as_ascii,
65+
tags: [.validation, .api, .String, .skip],
66+
setUpFunction: setUp),
67+
]
68+
69+
typealias CodeUnit = UInt16
70+
71+
// 1-byte sequences
72+
// This test case is the longest as it's the most performance sensitive.
73+
let ascii = "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."
74+
let asciiCodeUnits: [CodeUnit] = Array(ascii.utf16)
75+
let asciiData: Data = asciiCodeUnits.withUnsafeBytes { Data($0) }
76+
77+
// 2-byte sequences
78+
let russian = "Ру́сский язы́к один из восточнославянских языков, национальный язык русского народа."
79+
// 3-byte sequences
80+
let japanese = "日本語(にほんご、にっぽんご)は、主に日本国内や日本人同士の間で使われている言語である。"
81+
// 4-byte sequences
82+
// Most commonly emoji, which are usually mixed with other text.
83+
let emoji = "Panda 🐼, Dog 🐶, Cat 🐱, Mouse 🐭."
84+
85+
let allStrings: [[CodeUnit]] = [ascii, russian, japanese, emoji].map { Array($0.utf16) }
86+
let allStringsCodeUnits: [CodeUnit] = Array(allStrings.joined())
87+
let allStringsData: Data = allStringsCodeUnits.withUnsafeBytes { Data($0) }
88+
89+
func setUp() {
90+
blackHole(asciiCodeUnits)
91+
blackHole(asciiData)
92+
blackHole(allStrings)
93+
blackHole(allStringsCodeUnits)
94+
blackHole(allStringsData)
95+
blackHole(allStringsCustomContiguous)
96+
blackHole(asciiCustomContiguous)
97+
blackHole(allStringsCustomNoncontiguous)
98+
blackHole(asciiCustomNoncontiguous)
99+
}
100+
101+
@inline(never)
102+
public func run_UTF16Decode(_ N: Int) {
103+
func isEmpty(_ result: UnicodeDecodingResult) -> Bool {
104+
switch result {
105+
case .emptyInput:
106+
return true
107+
default:
108+
return false
109+
}
110+
}
111+
112+
for _ in 1...200*N {
113+
for string in allStrings {
114+
var it = string.makeIterator()
115+
var utf16 = UTF16()
116+
while !isEmpty(utf16.decode(&it)) { }
117+
}
118+
}
119+
}
120+
121+
@inline(never)
122+
public func run_UTF16Decode_InitFromData(_ N: Int) {
123+
for _ in 0..<200*N {
124+
blackHole(String(data: allStringsData, encoding: .utf16))
125+
}
126+
}
127+
128+
@inline(never)
129+
public func run_UTF16Decode_InitDecoding(_ N: Int) {
130+
for _ in 0..<2*N {
131+
blackHole(String(decoding: allStringsCodeUnits, as: UTF16.self))
132+
}
133+
}
134+
135+
@inline(never)
136+
public func run_UTF16Decode_InitFromData_ascii(_ N: Int) {
137+
for _ in 0..<100*N {
138+
blackHole(String(data: asciiData, encoding: .utf16))
139+
}
140+
}
141+
142+
@inline(never)
143+
public func run_UTF16Decode_InitDecoding_ascii(_ N: Int) {
144+
for _ in 0..<N {
145+
blackHole(String(decoding: asciiCodeUnits, as: UTF16.self))
146+
}
147+
}
148+
149+
@inline(never)
150+
public func run_UTF16Decode_InitFromData_ascii_as_ascii(_ N: Int) {
151+
for _ in 0..<1_000*N {
152+
blackHole(String(data: asciiData, encoding: .ascii))
153+
}
154+
}
155+
156+
struct CustomContiguousCollection: Collection {
157+
let storage: [CodeUnit]
158+
typealias Index = Int
159+
typealias Element = CodeUnit
160+
161+
init(_ codeUnits: [CodeUnit]) { self.storage = codeUnits }
162+
subscript(position: Int) -> Element { self.storage[position] }
163+
var startIndex: Index { 0 }
164+
var endIndex: Index { storage.count }
165+
func index(after i: Index) -> Index { i+1 }
166+
167+
@inline(never)
168+
func withContiguousStorageIfAvailable<R>(
169+
_ body: (UnsafeBufferPointer<CodeUnit>) throws -> R
170+
) rethrows -> R? {
171+
try storage.withContiguousStorageIfAvailable(body)
172+
}
173+
}
174+
struct CustomNoncontiguousCollection: Collection {
175+
let storage: [CodeUnit]
176+
typealias Index = Int
177+
typealias Element = CodeUnit
178+
179+
init(_ codeUnits: [CodeUnit]) { self.storage = codeUnits }
180+
subscript(position: Int) -> Element { self.storage[position] }
181+
var startIndex: Index { 0 }
182+
var endIndex: Index { storage.count }
183+
func index(after i: Index) -> Index { i+1 }
184+
185+
@inline(never)
186+
func withContiguousStorageIfAvailable<R>(
187+
_ body: (UnsafeBufferPointer<UInt8>) throws -> R
188+
) rethrows -> R? {
189+
nil
190+
}
191+
}
192+
let allStringsCustomContiguous = CustomContiguousCollection(allStringsCodeUnits)
193+
let asciiCustomContiguous = CustomContiguousCollection(Array(ascii.utf16))
194+
let allStringsCustomNoncontiguous = CustomNoncontiguousCollection(allStringsCodeUnits)
195+
let asciiCustomNoncontiguous = CustomNoncontiguousCollection(Array(ascii.utf16))
196+
197+
@inline(never)
198+
public func run_UTF16Decode_InitFromCustom_contiguous(_ N: Int) {
199+
for _ in 0..<20*N {
200+
blackHole(String(decoding: allStringsCustomContiguous, as: UTF16.self))
201+
}
202+
}
203+
204+
@inline(never)
205+
public func run_UTF16Decode_InitFromCustom_contiguous_ascii(_ N: Int) {
206+
for _ in 0..<10*N {
207+
blackHole(String(decoding: asciiCustomContiguous, as: UTF16.self))
208+
}
209+
}
210+
211+
@inline(never)
212+
public func run_UTF16Decode_InitFromCustom_noncontiguous(_ N: Int) {
213+
for _ in 0..<20*N {
214+
blackHole(String(decoding: allStringsCustomNoncontiguous, as: UTF16.self))
215+
}
216+
}
217+
218+
@inline(never)
219+
public func run_UTF16Decode_InitFromCustom_noncontiguous_ascii(_ N: Int) {
220+
for _ in 0..<10*N {
221+
blackHole(String(decoding: asciiCustomNoncontiguous, as: UTF16.self))
222+
}
223+
}

benchmark/utils/main.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ import SuperChars
199199
import TwoSum
200200
import TypeFlood
201201
import UTF8Decode
202+
import UTF16Decode
202203
import Walsh
203204
import WordCount
204205
import XorLoop
@@ -393,6 +394,7 @@ register(SuperChars.benchmarks)
393394
register(TwoSum.benchmarks)
394395
register(TypeFlood.benchmarks)
395396
register(UTF8Decode.benchmarks)
397+
register(UTF16Decode.benchmarks)
396398
register(Walsh.benchmarks)
397399
register(WordCount.benchmarks)
398400
register(XorLoop.benchmarks)

0 commit comments

Comments
 (0)