Files
swift-mirror/benchmark/single-source/AngryPhonebook.swift
2023-08-31 18:50:10 -03:00

153 lines
5.3 KiB
Swift

//===--- AngryPhonebook.swift ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 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
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
// This test is based on single-source/Phonebook, with
// to test uppercase and lowercase ASCII string fast paths.
import TestsUtils
let t: [BenchmarkCategory] = [.validation, .api, .String]
public let benchmarks = [
BenchmarkInfo(
name: "AngryPhonebook",
runFunction: run_AngryPhonebook,
tags: t,
legacyFactor: 7),
// Small String Workloads
BenchmarkInfo(
name: "AngryPhonebook.ASCII2.Small",
runFunction: { angryPhonebook($0*10, ascii) },
tags: t,
setUpFunction: { blackHole(ascii) }),
BenchmarkInfo(
name: "AngryPhonebook.Strasse.Small",
runFunction: { angryPhonebook($0, strasse) },
tags: t,
setUpFunction: { blackHole(strasse) }),
BenchmarkInfo(
name: "AngryPhonebook.Armenian.Small",
runFunction: { angryPhonebook($0, armenian) },
tags: t,
setUpFunction: { blackHole(armenian) }),
BenchmarkInfo(
name: "AngryPhonebook.Cyrillic.Small",
runFunction: { angryPhonebook($0, cyrillic) },
tags: t,
setUpFunction: { blackHole(cyrillic) }),
// Regular String Workloads
BenchmarkInfo(
name: "AngryPhonebook.ASCII2",
runFunction: { angryPhonebook($0*10, precomposed: longASCII) },
tags: t,
setUpFunction: { blackHole(longASCII) }),
BenchmarkInfo(
name: "AngryPhonebook.Strasse",
runFunction: { angryPhonebook($0, precomposed: longStrasse) },
tags: t,
setUpFunction: { blackHole(longStrasse) }),
BenchmarkInfo(
name: "AngryPhonebook.Armenian",
runFunction: { angryPhonebook($0, precomposed: longArmenian) },
tags: t,
setUpFunction: { blackHole(longArmenian) }),
BenchmarkInfo(
name: "AngryPhonebook.Cyrillic",
runFunction: { angryPhonebook($0, precomposed: longCyrillic) },
tags: t,
setUpFunction: { blackHole(longCyrillic) })
]
let words = [
"James", "John", "Robert", "Michael", "William", "David", "Richard", "Joseph",
"Charles", "Thomas", "Christopher", "Daniel", "Matthew", "Donald", "Anthony",
"Paul", "Mark", "George", "Steven", "Kenneth", "Andrew", "Edward", "Brian",
"Joshua", "Kevin", "Ronald", "Timothy", "Jason", "Jeffrey", "Gary", "Ryan",
"Nicholas", "Eric", "Stephen", "Jacob", "Larry", "Frank"]
@inline(never)
public func run_AngryPhonebook(_ n: Int) {
// Permute the names.
for _ in 1...n {
for firstname in words {
for lastname in words {
_ = (firstname.uppercased(), lastname.lowercased())
}
}
}
}
// Workloads for various scripts. Always 20 names for 400 pairings.
// To keep the performance of various scripts roughly comparable, aim for
// a total length of approximately 120 characters.
// E.g.: `ascii.joined(separator: "").count == 124`
// Every name should fit in 15-bytes UTF-8 encoded, to exercise the small
// string optimization.
// E.g.: `armenian.allSatisfy { $0._guts.isSmall } == true`
// Workload Size Statistics
// SMALL | UTF-8 | UTF-16 | REGULAR | UTF-8 | UTF-16
// ---------|-------|--------|--------------|---------|--------
// ascii | 124 B | 248 B | longASCII | 6158 B | 12316 B
// strasse | 140 B | 240 B | longStrasse | 6798 B | 11996 B
// armenian | 232 B | 232 B | longArmenian | 10478 B | 11676 B
// cyrillic | 238 B | 238 B | longCyrillic | 10718 B | 11916 B
let ascii = Array(words.prefix(20))
// Pathological case, uppercase: ß -> SS
let strasse = Array(repeating: "Straße", count: 20)
let armenian = [
"Արմեն", "Աննա", "Հարութ", "Միքայել", "Մարիա", "Դավիթ", "Վարդան",
"Նարինե", "Տիգրան", "Տաթևիկ", "Թագուհի", "Թամարա", "Ազնաուր", "Գրիգոր",
"Կոմիտաս", "Հայկ", "Գառնիկ", "Վահրամ", "Վահագն", "Գևորգ"]
let cyrillic = [
"Ульяна", "Аркадий", "Аня", "Даниил", "Дмитрий", "Эдуард", "Юрій", "Давид",
"Анна", "Дмитрий", "Евгений", "Борис", "Ксения", "Артур", "Аполлон",
"Соломон", "Николай", "Кристи", "Надежда", "Спартак"]
/// Precompose the phonebook into one large string of comma separated names.
func phonebook(_ names: [String]) -> String {
names.map { firstName in
names.map { lastName in
firstName + " " + lastName
}.joined(separator: ", ")
}.joined(separator: ", ")
}
let longASCII = phonebook(ascii)
let longStrasse = phonebook(strasse)
let longArmenian = phonebook(armenian)
let longCyrillic = phonebook(cyrillic)
@inline(never)
public func angryPhonebook(_ n: Int, _ names: [String]) {
assert(names.count == 20)
// Permute the names.
for _ in 1...n {
for firstname in names {
for lastname in names {
blackHole((firstname.uppercased(), lastname.lowercased()))
}
}
}
}
@inline(never)
public func angryPhonebook(_ n: Int, precomposed names: String) {
for _ in 1...n {
blackHole((names.uppercased(), names.lowercased()))
}
}