1414// to test uppercase and lowercase ASCII string fast paths.
1515import TestsUtils
1616
17- public let AngryPhonebook = BenchmarkInfo (
18- name: " AngryPhonebook " ,
19- runFunction: run_AngryPhonebook,
20- tags: [ . validation, . api, . String] ,
21- legacyFactor: 7 )
17+ let t : [ BenchmarkCategory ] = [ . validation, . api, . String]
18+
19+ public let AngryPhonebook = [
20+ BenchmarkInfo (
21+ name: " AngryPhonebook " ,
22+ runFunction: run_AngryPhonebook,
23+ tags: t,
24+ legacyFactor: 7 ) ,
25+
26+ // Small String Workloads
27+ BenchmarkInfo (
28+ name: " AngryPhonebook.ASCII.Small " ,
29+ runFunction: { angryPhonebook ( $0, ascii) } ,
30+ tags: t,
31+ setUpFunction: { blackHole ( ascii) } ) ,
32+ BenchmarkInfo (
33+ name: " AngryPhonebook.Strasse.Small " ,
34+ runFunction: { angryPhonebook ( $0, strasse) } ,
35+ tags: t,
36+ setUpFunction: { blackHole ( strasse) } ) ,
37+ BenchmarkInfo (
38+ name: " AngryPhonebook.Armenian.Small " ,
39+ runFunction: { angryPhonebook ( $0, armenian) } ,
40+ tags: t,
41+ setUpFunction: { blackHole ( armenian) } ) ,
42+ BenchmarkInfo (
43+ name: " AngryPhonebook.Cyrillic.Small " ,
44+ runFunction: { angryPhonebook ( $0, cyrillic) } ,
45+ tags: t,
46+ setUpFunction: { blackHole ( cyrillic) } ) ,
47+
48+ // Regular String Workloads
49+ BenchmarkInfo (
50+ name: " AngryPhonebook.ASCII " ,
51+ runFunction: { angryPhonebook ( $0, precomposed: longASCII) } ,
52+ tags: t,
53+ setUpFunction: { blackHole ( longASCII) } ) ,
54+ BenchmarkInfo (
55+ name: " AngryPhonebook.Strasse " ,
56+ runFunction: { angryPhonebook ( $0, precomposed: longStrasse) } ,
57+ tags: t,
58+ setUpFunction: { blackHole ( longStrasse) } ) ,
59+ BenchmarkInfo (
60+ name: " AngryPhonebook.Armenian " ,
61+ runFunction: { angryPhonebook ( $0, precomposed: longArmenian) } ,
62+ tags: t,
63+ setUpFunction: { blackHole ( longArmenian) } ) ,
64+ BenchmarkInfo (
65+ name: " AngryPhonebook.Cyrillic " ,
66+ runFunction: { angryPhonebook ( $0, precomposed: longCyrillic) } ,
67+ tags: t,
68+ setUpFunction: { blackHole ( longCyrillic) } )
69+ ]
2270
2371let words = [
2472 " James " , " John " , " Robert " , " Michael " , " William " , " David " , " Richard " , " Joseph " ,
@@ -38,3 +86,67 @@ public func run_AngryPhonebook(_ N: Int) {
3886 }
3987 }
4088}
89+
90+ // Workloads for various scripts. Always 20 names for 400 pairings.
91+ // To keep the performance of various scripts roughly comparable, aim for
92+ // a total length of approximately 120 characters.
93+ // E.g.: `ascii.joined(separator: "").count == 124`
94+ // Every name should fit in 15-bytes UTF-8 encoded, to excercise the small
95+ // string optimization.
96+ // E.g.: `armenian.allSatisfy { $0._guts.isSmall } == true`
97+
98+ // Workload Size Statistics
99+ // SMALL | UTF-8 | UTF-16 | REGULAR | UTF-8 | UTF-16
100+ // ---------|-------|--------|--------------|---------|--------
101+ // ascii | 124 B | 248 B | longASCII | 6158 B | 12316 B
102+ // strasse | 140 B | 240 B | longStrasse | 6798 B | 11996 B
103+ // armenian | 232 B | 232 B | longArmenian | 10478 B | 11676 B
104+ // cyrillic | 238 B | 238 B | longCyrillic | 10718 B | 11916 B
105+
106+ let ascii = Array ( words. prefix ( 20 ) )
107+ // Pathological case, uppercase: ß -> SS
108+ let strasse = Array ( repeating: " Straße " , count: 20 )
109+
110+ let armenian = [
111+ " Արմեն " , " Աննա " , " Հարութ " , " Միքայել " , " Մարիա " , " Դավիթ " , " Վարդան " ,
112+ " Նարինե " , " Տիգրան " , " Տաթևիկ " , " Թագուհի " , " Թամարա " , " Ազնաուր " , " Գրիգոր " ,
113+ " Կոմիտաս " , " Հայկ " , " Գառնիկ " , " Վահրամ " , " Վահագն " , " Գևորգ " ]
114+
115+ let cyrillic = [
116+ " Ульяна " , " Аркадий " , " Аня " , " Даниил " , " Дмитрий " , " Эдуард " , " Юрій " , " Давид " ,
117+ " Анна " , " Дмитрий " , " Евгений " , " Борис " , " Ксения " , " Артур " , " Аполлон " ,
118+ " Соломон " , " Николай " , " Кристи " , " Надежда " , " Спартак " ]
119+
120+ /// Precompose the phonebook into one large string of comma separated names.
121+ func phonebook( _ names: [ String ] ) -> String {
122+ names. map { firstName in
123+ names. map { lastName in
124+ firstName + " " + lastName
125+ } . joined ( separator: " , " )
126+ } . joined ( separator: " , " )
127+ }
128+
129+ let longASCII = phonebook ( ascii)
130+ let longStrasse = phonebook ( strasse)
131+ let longArmenian = phonebook ( armenian)
132+ let longCyrillic = phonebook ( cyrillic)
133+
134+ @inline ( never)
135+ public func angryPhonebook( _ N: Int , _ names: [ String ] ) {
136+ assert ( names. count == 20 )
137+ // Permute the names.
138+ for _ in 1 ... N {
139+ for firstname in names {
140+ for lastname in names {
141+ blackHole ( ( firstname. uppercased ( ) , lastname. lowercased ( ) ) )
142+ }
143+ }
144+ }
145+ }
146+
147+ @inline ( never)
148+ public func angryPhonebook( _ N: Int , precomposed names: String ) {
149+ for _ in 1 ... N {
150+ blackHole ( ( names. uppercased ( ) , names. lowercased ( ) ) )
151+ }
152+ }
0 commit comments