Skip to content

Commit d021e8d

Browse files
committed
[benchmark] Add DictionaryOfObjects benchmark
This tests performance of dictionary when both key and value are objects. (We have fast paths otherwise because we know that the dictionary cannot be backed by an objective c dictionary)
1 parent 2b12cc8 commit d021e8d

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

benchmark/single-source/DictTest.swift

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,156 @@ public func run_Dictionary(scale: Int) {
145145
CheckResults(count == N*541,
146146
"IncorrectResults in DictTest: \(count) != \(N*541).")
147147
}
148+
149+
class Box<T : Hashable where T : Equatable> : Hashable {
150+
var value: T
151+
152+
init(_ v: T) {
153+
value = v
154+
}
155+
156+
var hashValue : Int {
157+
return value.hashValue
158+
}
159+
}
160+
161+
extension Box : Equatable {
162+
}
163+
164+
func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
165+
return lhs.value == rhs.value
166+
}
167+
168+
@inline(never)
169+
public func run_DictionaryOfObjects(scale: Int) {
170+
let Input = [
171+
// Text from http://en.wikipedia.org/wiki/Hash_table
172+
"hash", "table",
173+
"in", "computing", "a", "hash", "table", "also", "hash", "map", "is",
174+
"a", "data", "structure", "used", "to", "implement", "an", "associative",
175+
"array", "a", "structure", "that", "can", "map", "keys", "to", "values",
176+
"a", "hash", "table", "uses", "a", "hash", "function", "to", "compute",
177+
"an", "index", "into", "an", "array", "of", "buckets", "or", "slots",
178+
"from", "which", "the", "correct", "value", "can", "be", "found",
179+
"ideally", "the", "hash", "function", "will", "assign", "each", "key",
180+
"to", "a", "unique", "bucket", "but", "this", "situation", "is",
181+
"rarely", "achievable", "in", "practice", "usually", "some", "keys",
182+
"will", "hash", "to", "the", "same", "bucket", "instead", "most", "hash",
183+
"table", "designs", "assume", "that", "hash", "collisions", "different",
184+
"keys", "that", "are", "assigned", "by", "the", "hash", "function", "to",
185+
"the", "same", "bucket", "will", "occur", "and", "must", "be",
186+
"accommodated", "in", "some", "way", "in", "a", "well", "dimensioned",
187+
"hash", "table", "the", "average", "cost", "number", "of",
188+
"instructions", "for", "each", "lookup", "is", "independent", "of",
189+
"the", "number", "of", "elements", "stored", "in", "the", "table",
190+
"many", "hash", "table", "designs", "also", "allow", "arbitrary",
191+
"insertions", "and", "deletions", "of", "key", "value", "pairs", "at",
192+
"amortized", "constant", "average", "cost", "per", "operation", "in",
193+
"many", "situations", "hash", "tables", "turn", "out", "to", "be",
194+
"more", "efficient", "than", "search", "trees", "or", "any", "other",
195+
"table", "lookup", "structure", "for", "this", "reason", "they", "are",
196+
"widely", "used", "in", "many", "kinds", "of", "computer", "software",
197+
"particularly", "for", "associative", "arrays", "database", "indexing",
198+
"caches", "and", "sets",
199+
200+
"hashing",
201+
"the", "idea", "of", "hashing", "is", "to", "distribute", "the",
202+
"entries", "key", "value", "pairs", "across", "an", "array", "of",
203+
"buckets", "given", "a", "key", "the", "algorithm", "computes", "an",
204+
"index", "that", "suggests", "where", "the", "entry", "can", "be",
205+
"found", "index", "f", "key", "array", "size", "often", "this", "is",
206+
"done", "in", "two", "steps", "hash", "hashfunc", "key", "index", "hash",
207+
"array", "size", "in", "this", "method", "the", "hash", "is",
208+
"independent", "of", "the", "array", "size", "and", "it", "is", "then",
209+
"reduced", "to", "an", "index", "a", "number", "between", "and", "array",
210+
"size", "using", "the", "modulus", "operator", "in", "the", "case",
211+
"that", "the", "array", "size", "is", "a", "power", "of", "two", "the",
212+
"remainder", "operation", "is", "reduced", "to", "masking", "which",
213+
"improves", "speed", "but", "can", "increase", "problems", "with", "a",
214+
"poor", "hash", "function",
215+
216+
"choosing", "a", "good", "hash", "function",
217+
"a", "good", "hash", "function", "and", "implementation", "algorithm",
218+
"are", "essential", "for", "good", "hash", "table", "performance", "but",
219+
"may", "be", "difficult", "to", "achieve", "a", "basic", "requirement",
220+
"is", "that", "the", "function", "should", "provide", "a", "uniform",
221+
"distribution", "of", "hash", "values", "a", "non", "uniform",
222+
"distribution", "increases", "the", "number", "of", "collisions", "and",
223+
"the", "cost", "of", "resolving", "them", "uniformity", "is",
224+
"sometimes", "difficult", "to", "ensure", "by", "design", "but", "may",
225+
"be", "evaluated", "empirically", "using", "statistical", "tests", "e",
226+
"g", "a", "pearson", "s", "chi", "squared", "test", "for", "discrete",
227+
"uniform", "distributions", "the", "distribution", "needs", "to", "be",
228+
"uniform", "only", "for", "table", "sizes", "that", "occur", "in", "the",
229+
"application", "in", "particular", "if", "one", "uses", "dynamic",
230+
"resizing", "with", "exact", "doubling", "and", "halving", "of", "the",
231+
"table", "size", "s", "then", "the", "hash", "function", "needs", "to",
232+
"be", "uniform", "only", "when", "s", "is", "a", "power", "of", "two",
233+
"on", "the", "other", "hand", "some", "hashing", "algorithms", "provide",
234+
"uniform", "hashes", "only", "when", "s", "is", "a", "prime", "number",
235+
"for", "open", "addressing", "schemes", "the", "hash", "function",
236+
"should", "also", "avoid", "clustering", "the", "mapping", "of", "two",
237+
"or", "more", "keys", "to", "consecutive", "slots", "such", "clustering",
238+
"may", "cause", "the", "lookup", "cost", "to", "skyrocket", "even", "if",
239+
"the", "load", "factor", "is", "low", "and", "collisions", "are",
240+
"infrequent", "the", "popular", "multiplicative", "hash", "3", "is",
241+
"claimed", "to", "have", "particularly", "poor", "clustering",
242+
"behavior", "cryptographic", "hash", "functions", "are", "believed",
243+
"to", "provide", "good", "hash", "functions", "for", "any", "table",
244+
"size", "s", "either", "by", "modulo", "reduction", "or", "by", "bit",
245+
"masking", "they", "may", "also", "be", "appropriate", "if", "there",
246+
"is", "a", "risk", "of", "malicious", "users", "trying", "to",
247+
"sabotage", "a", "network", "service", "by", "submitting", "requests",
248+
"designed", "to", "generate", "a", "large", "number", "of", "collisions",
249+
"in", "the", "server", "s", "hash", "tables", "however", "the", "risk",
250+
"of", "sabotage", "can", "also", "be", "avoided", "by", "cheaper",
251+
"methods", "such", "as", "applying", "a", "secret", "salt", "to", "the",
252+
"data", "or", "using", "a", "universal", "hash", "function",
253+
254+
"perfect", "hash", "function",
255+
"if", "all", "keys", "are", "known", "ahead", "of", "time", "a",
256+
"perfect", "hash", "function", "can", "be", "used", "to", "create", "a",
257+
"perfect", "hash", "table", "that", "has", "no", "collisions", "if",
258+
"minimal", "perfect", "hashing", "is", "used", "every", "location", "in",
259+
"the", "hash", "table", "can", "be", "used", "as", "well", "perfect",
260+
"hashing", "allows", "for", "constant", "time", "lookups", "in", "the",
261+
"worst", "case", "this", "is", "in", "contrast", "to", "most",
262+
"chaining", "and", "open", "addressing", "methods", "where", "the",
263+
"time", "for", "lookup", "is", "low", "on", "average", "but", "may",
264+
"be", "very", "large", "proportional", "to", "the", "number", "of",
265+
"entries", "for", "some", "sets", "of", "keys"
266+
]
267+
268+
var Dict: Dictionary<Box<String>, Box<Bool>> = [:]
269+
let N = 5*scale
270+
271+
// Check performance of filling the dictionary:
272+
for _ in 1...N {
273+
Dict = [:]
274+
for word in Input {
275+
Dict[Box(word)] = Box(true);
276+
}
277+
}
278+
CheckResults(Dict.count == 270,
279+
"IncorrectResults in DictTest: \(Dict.count) != 270.")
280+
281+
// Check performance of searching in the dictionary:
282+
// Fill the dictionary with words from the first half of the text
283+
Dict = [:]
284+
for i in 0 ..< Input.count/2 {
285+
let word = Input[i]
286+
Dict[Box(word)] = Box(true)
287+
}
288+
289+
// Count number of words from the first half in the entire text
290+
var count = 0
291+
for _ in 1...N {
292+
for word in Input {
293+
if Dict[Box(word)] != nil {
294+
count += 1
295+
}
296+
}
297+
}
298+
CheckResults(count == N*541,
299+
"IncorrectResults in DictTestAllObjects: \(count) != \(N*541).")
300+
}

benchmark/utils/main.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ precommitTests = [
119119
"ClassArrayGetter": run_ClassArrayGetter,
120120
"DeadArray": run_DeadArray,
121121
"Dictionary": run_Dictionary,
122+
"DictionaryOfObjects": run_DictionaryOfObjects,
122123
"Dictionary2": run_Dictionary2,
123124
"Dictionary3": run_Dictionary3,
124125
"DictionaryBridge": run_DictionaryBridge,

0 commit comments

Comments
 (0)