NimYAML/bench/yamlBench.nim

203 lines
6.8 KiB
Nim

import "../yaml", commonBench
import math, strutils, stopwatch, terminal, algorithm, random, streams
from nimlets_yaml import objKind
type
Level = tuple
kind: YamlNodeKind
len: int
proc genString(maxLen: int): string =
let len = random(maxLen)
result = ""
for i in 1 .. len: result.add(cast[char](random(127 - 32) + 32))
proc genBlockString(): string =
let lines = 5 + random(10)
let flow = random(2) == 0
result = ""
for i in 1 .. lines:
let lineLen = 32 + random(12)
for i in i .. lineLen: result.add(cast[char](random(127 - 33) + 33))
result.add(if flow: ' ' else: '\l')
result.add('\l')
proc genKey(): string =
let genPossiblePlainKey = random(1.0) < 0.75
if genPossiblePlainKey:
result = ""
let len = random(24) + 1
for i in 1 .. len:
let c = random(26 + 26 + 10)
if c < 26: result.add(char(c + 65))
elif c < 52: result.add(char(c + 97 - 26))
else: result.add(char(c + 48 - 52))
else: result = genString(31) & char(random(26) + 65)
proc genYamlString(size: int, maxStringLen: int,
style: PresentationStyle): string =
## Generates a random YAML string.
## size is in KiB, mayStringLen in characters.
randomize(size * maxStringLen * ord(style))
let targetSize = size * 1024
var
target = newStringStream()
input = iterator(): YamlStreamEvent =
var
levels = newSeq[Level]()
curSize = 1
levels.add((kind: yMapping, len: 0))
yield startDocEvent()
yield startMapEvent()
while levels.len > 0:
let
objectCloseProbability =
float(levels[levels.high].len + levels.high) * 0.025
closeObject = random(1.0) <= objectCloseProbability
if (closeObject and levels.len > 1) or curSize > targetSize:
case levels[levels.high].kind
of yMapping: yield endMapEvent()
of ySequence: yield endSeqEvent()
else: assert(false)
curSize += 1
discard levels.pop()
continue
levels[levels.high].len += 1
if levels[levels.high].kind == yMapping:
let key = genKey()
yield scalarEvent(key)
let
objectValueProbability =
0.8 / float(levels.len * levels.len)
generateObjectValue = random(1.0) <= objectValueProbability
hasTag = random(2) == 0
var tag = yTagQuestionMark
if generateObjectValue:
let objectKind = if random(3) == 0: ySequence else: yMapping
case objectKind
of yMapping:
if hasTag: tag = yTagMapping
yield startMapEvent(tag)
of ySequence:
if hasTag: tag = yTagSequence
yield startSeqEvent(tag)
else: assert(false)
curSize += 1
levels.add((kind: objectKind, len: 0))
else:
var s: string
case random(11)
of 0..4:
s = genString(maxStringLen)
if hasTag: tag = yTagString
of 5:
s = genBlockString()
of 6..7:
s = $random(32000)
if hasTag: tag = yTagInteger
of 8..9:
s = $(random(424242.4242) - 212121.21)
if hasTag: tag = yTagFloat
of 10:
case random(3)
of 0:
s = "true"
if hasTag: tag = yTagBoolean
of 1:
s = "false"
if hasTag: tag = yTagBoolean
of 2:
s = "null"
if hasTag: tag = yTagNull
else: discard
else: discard
yield scalarEvent(s, tag)
curSize += s.len
yield endDocEvent()
var yStream = initYamlStream(input)
present(yStream, target, initExtendedTagLibrary(),
defineOptions(style=style, outputVersion=ov1_1))
result = target.data
var
cYaml1k, cYaml10k, cYaml100k, cLibYaml1k, cLibYaml10k, cLibYaml100k,
cYaml1m, cLibYaml1m: int64
yaml1k = genYamlString(1, 32, psDefault)
yaml10k = genYamlString(10, 32, psDefault)
yaml100k = genYamlString(100, 32, psDefault)
yaml1m = genYamlString(1000, 32, psDefault)
tagLib = initExtendedTagLibrary()
parser = newYamlParser(tagLib)
block:
multibench(cYaml1k, 100):
let res = loadDOM(yaml1k)
assert res.root.kind == yMapping
block:
multibench(cYaml10k, 100):
let res = loadDOM(yaml10k)
assert res.root.kind == yMapping
block:
multibench(cYaml100k, 100):
let res = loadDOM(yaml100k)
assert res.root.kind == yMapping
block:
multibench(cYaml1m, 2):
let res = loadDOM(yaml1m)
assert res.root.kind == yMapping
block:
multibench(cLibYaml1k, 100):
let res = nimlets_yaml.load(yaml1k)
assert res[0].objKind == nimlets_yaml.YamlObjKind.Map
block:
multibench(cLibYaml10k, 100):
let res = nimlets_yaml.load(yaml10k)
assert res[0].objKind == nimlets_yaml.YamlObjKind.Map
block:
multibench(cLibYaml100k, 100):
let res = nimlets_yaml.load(yaml100k)
assert res[0].objKind == nimlets_yaml.YamlObjKind.Map
block:
multibench(cLibYaml1m, 2):
let res = nimlets_yaml.load(yaml1m)
assert res[0].objKind == nimlets_yaml.YamlObjKind.Map
proc writeResult(caption: string, num: int64) =
styledWriteLine(stdout, resetStyle, caption, fgGreen, $num, resetStyle, "μs")
setForegroundColor(fgWhite)
writeStyled "Benchmark: Processing YAML input\n"
writeStyled "================================\n"
writeStyled "1k input\n--------\n"
writeResult "NimYAML: ", cYaml1k div 1000
writeResult "LibYAML: ", cLibYaml1k div 1000
setForegroundColor(fgWhite)
writeStyled "10k input\n---------\n"
writeResult "NimYAML: ", cYaml10k div 1000
writeResult "LibYAML: ", cLibYaml10k div 1000
setForegroundColor(fgWhite)
writeStyled "100k input\n----------\n"
writeResult "NimYAML: ", cYaml100k div 1000
writeResult "LibYAML: ", cLibYaml100k div 1000
setForegroundColor(fgWhite)
writeStyled "1m input\n---------\n"
writeResult "NimYAML: ", cYaml1m div 1000
writeResult "LibYAML: ", cLibYaml1m div 1000