2020-04-29 18:19:18 +00:00
|
|
|
{.used.}
|
|
|
|
|
2020-04-13 18:59:34 +00:00
|
|
|
import
|
2022-09-10 05:25:22 +00:00
|
|
|
unittest2,
|
2021-08-20 11:10:26 +00:00
|
|
|
|
2020-05-03 23:47:01 +00:00
|
|
|
# FastStreams modules:
|
2021-08-20 11:10:26 +00:00
|
|
|
../faststreams/[pipelines, multisync]
|
|
|
|
|
|
|
|
when fsAsyncSupport:
|
|
|
|
import
|
|
|
|
# Std lib:
|
|
|
|
std/[strutils, random, base64, terminal],
|
|
|
|
# FastStreams modules:
|
|
|
|
../faststreams/[pipelines, multisync],
|
|
|
|
# Testing modules:
|
2022-09-10 05:25:22 +00:00
|
|
|
./base64 as fsBase64,
|
|
|
|
chronos/unittest2/asynctests
|
2021-08-20 11:10:26 +00:00
|
|
|
|
|
|
|
include system/timers
|
|
|
|
|
|
|
|
type
|
|
|
|
TestTimes = object
|
|
|
|
fsPipeline: Nanos
|
|
|
|
fsAsyncPipeline: Nanos
|
|
|
|
stdFunctionCalls: Nanos
|
|
|
|
|
|
|
|
proc upcaseAllCharacters(i: InputStream, o: OutputStream) {.fsMultiSync.} =
|
|
|
|
let inputLen = i.len
|
|
|
|
if inputLen.isSome:
|
|
|
|
o.ensureRunway inputLen.get
|
|
|
|
|
|
|
|
while i.readable:
|
|
|
|
o.write toUpperAscii(i.read.char)
|
|
|
|
|
|
|
|
close o
|
|
|
|
|
|
|
|
proc printTimes(t: TestTimes) =
|
|
|
|
styledEcho " cpu time [FS Sync ]: ", styleBright, $t.fsPipeline, "ms"
|
|
|
|
styledEcho " cpu time [FS Async ]: ", styleBright, $t.fsAsyncPipeline, "ms"
|
|
|
|
styledEcho " cpu time [Std Lib ]: ", styleBright, $t.stdFunctionCalls, "ms"
|
|
|
|
|
|
|
|
template timeit(timerVar: var Nanos, code: untyped) =
|
|
|
|
let t0 = getTicks()
|
|
|
|
code
|
2022-03-17 21:13:32 +00:00
|
|
|
timerVar = int64(getTicks() - t0) div 1000000
|
2021-08-20 11:10:26 +00:00
|
|
|
|
|
|
|
proc getOutput(sp: AsyncInputStream, T: type string): Future[string] {.async.} =
|
|
|
|
# this proc is a quick hack to let the test pass
|
|
|
|
# do not use it in production code
|
|
|
|
let size = sp.totalUnconsumedBytes()
|
|
|
|
if size > 0:
|
|
|
|
var data = newSeq[byte](size)
|
2021-12-05 15:11:54 +00:00
|
|
|
discard sp.readInto(data)
|
2021-08-20 11:10:26 +00:00
|
|
|
result = cast[string](data)
|
|
|
|
|
|
|
|
suite "pipelines":
|
|
|
|
const loremIpsum = """
|
|
|
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
|
|
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
|
|
|
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
|
|
|
|
ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
|
|
|
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
|
|
|
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
|
|
|
est laborum.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
test "upper-case/base64 pipeline benchmark":
|
|
|
|
var
|
|
|
|
times: TestTimes
|
|
|
|
stdRes: string
|
|
|
|
fsRes: string
|
|
|
|
fsAsyncRes: string
|
|
|
|
|
|
|
|
let inputText = loremIpsum.repeat(5000)
|
|
|
|
|
2021-12-05 15:11:54 +00:00
|
|
|
timeit times.stdFunctionCalls:
|
2021-08-20 11:10:26 +00:00
|
|
|
stdRes = base64.decode(base64.encode(toUpperAscii(inputText)))
|
|
|
|
|
2021-12-05 15:11:54 +00:00
|
|
|
timeit times.fsPipeline:
|
2021-08-20 11:10:26 +00:00
|
|
|
fsRes = executePipeline(unsafeMemoryInput(inputText),
|
|
|
|
upcaseAllCharacters,
|
|
|
|
base64encode,
|
|
|
|
base64decode,
|
|
|
|
getOutput string)
|
|
|
|
|
2021-12-05 15:11:54 +00:00
|
|
|
timeit times.fsAsyncPipeline:
|
2021-08-20 11:10:26 +00:00
|
|
|
fsAsyncRes = waitFor executePipeline(Async unsafeMemoryInput(inputText),
|
|
|
|
upcaseAllCharacters,
|
|
|
|
base64encode,
|
|
|
|
base64decode,
|
|
|
|
getOutput string)
|
|
|
|
|
|
|
|
check fsAsyncRes == stdRes
|
|
|
|
check fsRes == stdRes
|
|
|
|
|
|
|
|
printTimes times
|
|
|
|
|
|
|
|
asyncTest "upper-case/base64 async pipeline":
|
|
|
|
let pipe = asyncPipe()
|
|
|
|
let inputText = repeat(loremIpsum, 100)
|
|
|
|
|
|
|
|
proc pipeFeeder(s: AsyncOutputStream) {.gcsafe, async.} =
|
|
|
|
randomize 1234
|
|
|
|
var pos = 0
|
|
|
|
|
|
|
|
while pos != inputText.len:
|
|
|
|
let bytesToWrite = rand(15)
|
|
|
|
|
|
|
|
if bytesToWrite == 0:
|
|
|
|
s.write inputText[pos]
|
|
|
|
inc pos
|
|
|
|
else:
|
|
|
|
let endPos = min(pos + bytesToWrite, inputText.len)
|
|
|
|
s.writeAndWait inputText[pos ..< endPos]
|
|
|
|
pos = endPos
|
|
|
|
|
|
|
|
let sleep = rand(50) - 45
|
|
|
|
if sleep > 0:
|
|
|
|
await sleepAsync(sleep.milliseconds)
|
|
|
|
|
|
|
|
close s
|
|
|
|
|
|
|
|
asyncCheck pipeFeeder(pipe.initWriter)
|
|
|
|
|
|
|
|
let f = executePipeline(pipe.initReader,
|
2020-05-03 23:47:01 +00:00
|
|
|
upcaseAllCharacters,
|
|
|
|
base64encode,
|
|
|
|
base64decode,
|
|
|
|
getOutput string)
|
|
|
|
|
2021-08-20 11:10:26 +00:00
|
|
|
let fsAsyncres = await f
|
2020-05-03 23:47:01 +00:00
|
|
|
|
2021-12-05 15:11:54 +00:00
|
|
|
check fsAsyncres == toUpperAscii(inputText)
|
2021-08-20 11:10:26 +00:00
|
|
|
else:
|
|
|
|
test "pipelines":
|
|
|
|
skip
|