yamlBench.nim
1 import "../yaml", commonBench 2 import math, strutils, stopwatch, terminal, algorithm, random, streams 3 4 from nimlets_yaml import objKind 5 6 type 7 Level = tuple 8 kind: YamlNodeKind 9 len: int 10 11 proc genString(maxLen: int): string = 12 let len = random(maxLen) 13 result = "" 14 for i in 1 .. len: result.add(cast[char](random(127 - 32) + 32)) 15 16 proc genBlockString(): string = 17 let lines = 5 + random(10) 18 let flow = random(2) == 0 19 result = "" 20 for i in 1 .. lines: 21 let lineLen = 32 + random(12) 22 for i in i .. lineLen: result.add(cast[char](random(127 - 33) + 33)) 23 result.add(if flow: ' ' else: '\l') 24 result.add('\l') 25 26 proc genKey(): string = 27 let genPossiblePlainKey = random(1.0) < 0.75 28 if genPossiblePlainKey: 29 result = "" 30 let len = random(24) + 1 31 for i in 1 .. len: 32 let c = random(26 + 26 + 10) 33 if c < 26: result.add(char(c + 65)) 34 elif c < 52: result.add(char(c + 97 - 26)) 35 else: result.add(char(c + 48 - 52)) 36 else: result = genString(31) & char(random(26) + 65) 37 38 proc genYamlString(size: int, maxStringLen: int, 39 style: PresentationStyle): string = 40 ## Generates a random YAML string. 41 ## size is in KiB, mayStringLen in characters. 42 43 randomize(size * maxStringLen * ord(style)) 44 45 let targetSize = size * 1024 46 var 47 target = newStringStream() 48 input = iterator(): YamlStreamEvent = 49 var 50 levels = newSeq[Level]() 51 curSize = 1 52 levels.add((kind: yMapping, len: 0)) 53 yield startDocEvent() 54 yield startMapEvent() 55 56 while levels.len > 0: 57 let 58 objectCloseProbability = 59 float(levels[levels.high].len + levels.high) * 0.025 60 closeObject = random(1.0) <= objectCloseProbability 61 62 if (closeObject and levels.len > 1) or curSize > targetSize: 63 case levels[levels.high].kind 64 of yMapping: yield endMapEvent() 65 of ySequence: yield endSeqEvent() 66 else: assert(false) 67 curSize += 1 68 discard levels.pop() 69 continue 70 71 levels[levels.high].len += 1 72 if levels[levels.high].kind == yMapping: 73 let key = genKey() 74 yield scalarEvent(key) 75 76 let 77 objectValueProbability = 78 0.8 / float(levels.len * levels.len) 79 generateObjectValue = random(1.0) <= objectValueProbability 80 hasTag = random(2) == 0 81 var tag = yTagQuestionMark 82 83 if generateObjectValue: 84 let objectKind = if random(3) == 0: ySequence else: yMapping 85 case objectKind 86 of yMapping: 87 if hasTag: tag = yTagMapping 88 yield startMapEvent(tag) 89 of ySequence: 90 if hasTag: tag = yTagSequence 91 yield startSeqEvent(tag) 92 else: assert(false) 93 curSize += 1 94 levels.add((kind: objectKind, len: 0)) 95 else: 96 var s: string 97 case random(11) 98 of 0..4: 99 s = genString(maxStringLen) 100 if hasTag: tag = yTagString 101 of 5: 102 s = genBlockString() 103 of 6..7: 104 s = $random(32000) 105 if hasTag: tag = yTagInteger 106 of 8..9: 107 s = $(random(424242.4242) - 212121.21) 108 if hasTag: tag = yTagFloat 109 of 10: 110 case random(3) 111 of 0: 112 s = "true" 113 if hasTag: tag = yTagBoolean 114 of 1: 115 s = "false" 116 if hasTag: tag = yTagBoolean 117 of 2: 118 s = "null" 119 if hasTag: tag = yTagNull 120 else: discard 121 else: discard 122 123 yield scalarEvent(s, tag) 124 curSize += s.len 125 yield endDocEvent() 126 var yStream = initYamlStream(input) 127 present(yStream, target, initExtendedTagLibrary(), 128 defineOptions(style=style, outputVersion=ov1_1)) 129 result = target.data 130 131 var 132 cYaml1k, cYaml10k, cYaml100k, cLibYaml1k, cLibYaml10k, cLibYaml100k, 133 cYaml1m, cLibYaml1m: int64 134 yaml1k = genYamlString(1, 32, psDefault) 135 yaml10k = genYamlString(10, 32, psDefault) 136 yaml100k = genYamlString(100, 32, psDefault) 137 yaml1m = genYamlString(1000, 32, psDefault) 138 tagLib = initExtendedTagLibrary() 139 parser = newYamlParser(tagLib) 140 141 block: 142 multibench(cYaml1k, 100): 143 let res = loadDOM(yaml1k) 144 assert res.root.kind == yMapping 145 146 block: 147 multibench(cYaml10k, 100): 148 let res = loadDOM(yaml10k) 149 assert res.root.kind == yMapping 150 151 block: 152 multibench(cYaml100k, 100): 153 let res = loadDOM(yaml100k) 154 assert res.root.kind == yMapping 155 156 block: 157 multibench(cYaml1m, 2): 158 let res = loadDOM(yaml1m) 159 assert res.root.kind == yMapping 160 161 block: 162 multibench(cLibYaml1k, 100): 163 let res = nimlets_yaml.load(yaml1k) 164 assert res[0].objKind == nimlets_yaml.YamlObjKind.Map 165 166 block: 167 multibench(cLibYaml10k, 100): 168 let res = nimlets_yaml.load(yaml10k) 169 assert res[0].objKind == nimlets_yaml.YamlObjKind.Map 170 171 block: 172 multibench(cLibYaml100k, 100): 173 let res = nimlets_yaml.load(yaml100k) 174 assert res[0].objKind == nimlets_yaml.YamlObjKind.Map 175 176 block: 177 multibench(cLibYaml1m, 2): 178 let res = nimlets_yaml.load(yaml1m) 179 assert res[0].objKind == nimlets_yaml.YamlObjKind.Map 180 181 proc writeResult(caption: string, num: int64) = 182 styledWriteLine(stdout, resetStyle, caption, fgGreen, $num, resetStyle, "μs") 183 184 setForegroundColor(fgWhite) 185 186 writeStyled "Benchmark: Processing YAML input\n" 187 writeStyled "================================\n" 188 writeStyled "1k input\n--------\n" 189 writeResult "NimYAML: ", cYaml1k div 1000 190 writeResult "LibYAML: ", cLibYaml1k div 1000 191 setForegroundColor(fgWhite) 192 writeStyled "10k input\n---------\n" 193 writeResult "NimYAML: ", cYaml10k div 1000 194 writeResult "LibYAML: ", cLibYaml10k div 1000 195 setForegroundColor(fgWhite) 196 writeStyled "100k input\n----------\n" 197 writeResult "NimYAML: ", cYaml100k div 1000 198 writeResult "LibYAML: ", cLibYaml100k div 1000 199 setForegroundColor(fgWhite) 200 writeStyled "1m input\n---------\n" 201 writeResult "NimYAML: ", cYaml1m div 1000 202 writeResult "LibYAML: ", cLibYaml1m div 1000