Don't import/export chronos by default (#20)
Chronos support is optional and should not have to be imported in order to use faststreams for non-async use cases, as doing so pollutes the global namespace and slows down compilation. `async` support must now explicitly be enabled with -d:async_backend=chronos|asyncdispatch
This commit is contained in:
parent
5eb7fd0c90
commit
3a0ab42573
10 changed files with 841 additions and 705 deletions
|
|
@ -2,15 +2,11 @@
|
|||
|
||||
import
|
||||
os, unittest2, strutils, random,
|
||||
stew/ranges/ptr_arith, testutils,
|
||||
testutils,
|
||||
../faststreams, ../faststreams/textio
|
||||
|
||||
setCurrentDir getAppDir()
|
||||
|
||||
proc bytes(s: string): seq[byte] =
|
||||
result = newSeqOfCap[byte](s.len)
|
||||
for c in s: result.add byte(c)
|
||||
|
||||
proc str(bytes: openarray[byte]): string =
|
||||
result = newStringOfCap(bytes.len)
|
||||
for b in items(bytes):
|
||||
|
|
@ -28,7 +24,7 @@ const
|
|||
asciiTableFile = "files" / "ascii_table.txt"
|
||||
asciiTableContents = slurp(asciiTableFile)
|
||||
|
||||
procSuite "input stream":
|
||||
suite "input stream":
|
||||
template emptyInputTests(suiteName, setupCode: untyped) =
|
||||
suite suiteName & " empty inputs":
|
||||
setup setupCode
|
||||
|
|
|
|||
|
|
@ -154,6 +154,15 @@ suite "output stream":
|
|||
|
||||
checkOutputsMatch()
|
||||
|
||||
test "memcpy":
|
||||
var x = 0x42'u8
|
||||
|
||||
nimSeq.add x
|
||||
memStream.writeMemCopy x
|
||||
let memStreamRes = memStream.getOutput
|
||||
|
||||
check memStreamRes == nimSeq
|
||||
|
||||
template undelayedOutput(content: seq[byte]) {.dirty.} =
|
||||
nimSeq.add content
|
||||
streamWritingToExistingBuffer.write content
|
||||
|
|
|
|||
|
|
@ -1,128 +1,136 @@
|
|||
{.used.}
|
||||
|
||||
import
|
||||
# Std lib:
|
||||
std/[strutils, random, base64, terminal],
|
||||
# Other packages:
|
||||
testutils/unittests,
|
||||
|
||||
# FastStreams modules:
|
||||
../faststreams/[pipelines, multisync],
|
||||
# Testing modules:
|
||||
./base64 as fsBase64
|
||||
../faststreams/[pipelines, multisync]
|
||||
|
||||
include system/timers
|
||||
when fsAsyncSupport:
|
||||
import
|
||||
# Std lib:
|
||||
std/[strutils, random, base64, terminal],
|
||||
# FastStreams modules:
|
||||
../faststreams/[pipelines, multisync],
|
||||
# Testing modules:
|
||||
./base64 as fsBase64
|
||||
|
||||
type
|
||||
TestTimes = object
|
||||
fsPipeline: Nanos
|
||||
fsAsyncPipeline: Nanos
|
||||
stdFunctionCalls: Nanos
|
||||
include system/timers
|
||||
|
||||
proc upcaseAllCharacters(i: InputStream, o: OutputStream) {.fsMultiSync.} =
|
||||
let inputLen = i.len
|
||||
if inputLen.isSome:
|
||||
o.ensureRunway inputLen.get
|
||||
type
|
||||
TestTimes = object
|
||||
fsPipeline: Nanos
|
||||
fsAsyncPipeline: Nanos
|
||||
stdFunctionCalls: Nanos
|
||||
|
||||
while i.readable:
|
||||
o.write toUpperAscii(i.read.char)
|
||||
proc upcaseAllCharacters(i: InputStream, o: OutputStream) {.fsMultiSync.} =
|
||||
let inputLen = i.len
|
||||
if inputLen.isSome:
|
||||
o.ensureRunway inputLen.get
|
||||
|
||||
close o
|
||||
while i.readable:
|
||||
o.write toUpperAscii(i.read.char)
|
||||
|
||||
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"
|
||||
close o
|
||||
|
||||
template timeit(timerVar: var Nanos, code: untyped) =
|
||||
let t0 = getTicks()
|
||||
code
|
||||
timerVar = int(getTicks() - t0) div 1000000
|
||||
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"
|
||||
|
||||
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)
|
||||
discard sp.readinto(data)
|
||||
result = cast[string](data)
|
||||
template timeit(timerVar: var Nanos, code: untyped) =
|
||||
let t0 = getTicks()
|
||||
code
|
||||
timerVar = int(getTicks() - t0) div 1000000
|
||||
|
||||
procSuite "pipelines":
|
||||
let 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.
|
||||
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)
|
||||
discard sp.readinto(data)
|
||||
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)
|
||||
test "upper-case/base64 pipeline benchmark":
|
||||
var
|
||||
times: TestTimes
|
||||
stdRes: string
|
||||
fsRes: string
|
||||
fsAsyncRes: string
|
||||
|
||||
timeIt times.stdFunctionCalls:
|
||||
stdRes = base64.decode(base64.encode(toUpperAscii(inputText)))
|
||||
let inputText = loremIpsum.repeat(5000)
|
||||
|
||||
timeIt times.fsPipeline:
|
||||
fsRes = executePipeline(unsafeMemoryInput(inputText),
|
||||
timeIt times.stdFunctionCalls:
|
||||
stdRes = base64.decode(base64.encode(toUpperAscii(inputText)))
|
||||
|
||||
timeIt times.fsPipeline:
|
||||
fsRes = executePipeline(unsafeMemoryInput(inputText),
|
||||
upcaseAllCharacters,
|
||||
base64encode,
|
||||
base64decode,
|
||||
getOutput string)
|
||||
|
||||
timeIt times.fsAsyncPipeline:
|
||||
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,
|
||||
upcaseAllCharacters,
|
||||
base64encode,
|
||||
base64decode,
|
||||
getOutput string)
|
||||
|
||||
timeIt times.fsAsyncPipeline:
|
||||
fsAsyncRes = waitFor executePipeline(Async unsafeMemoryInput(inputText),
|
||||
upcaseAllCharacters,
|
||||
base64encode,
|
||||
base64decode,
|
||||
getOutput string)
|
||||
let fsAsyncres = await f
|
||||
|
||||
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,
|
||||
upcaseAllCharacters,
|
||||
base64encode,
|
||||
base64decode,
|
||||
getOutput string)
|
||||
|
||||
let fsAsyncres = await f
|
||||
|
||||
check fsAsyncRes == toUpperAscii(inputText)
|
||||
check fsAsyncRes == toUpperAscii(inputText)
|
||||
else:
|
||||
test "pipelines":
|
||||
skip
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue