Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions bench/algorithm/coro-prime-sieve/4.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import chronos
import std/os
import std/strutils



##
## # Channel[T]
##
## I craeted a very simple async-awaitable channel type so I can match the
## reference Go implementation this benchmark originated from.
##


type Channel[T] = object
## An simple one-item, async-awaitable Channel.
untilIsEmpty: Future[void]
untilIsFull: Future[void]
val: T


proc newChannel[T](): ref Channel[T] =
## Initializer. Allocate a new ref Channel object on the heap.
result = new Channel[T]
result[].untilIsEmpty = newFuture[void]()
result[].untilIsFull = newFuture[void]()
result[].untilIsEmpty.complete()


proc send(chan: ref Channel[int], val: int) {.async.} =
# Accept val if empty, otherwise, suspend until empty.
await chan[].untilIsEmpty
chan[].untilIsEmpty = newFuture[void]()
chan[].val = val
chan[].untilIsFull.complete()


proc recv[T](chan: ref Channel[T]): Future[T] {.async.} =
# Return held val if full, otherwise, suspend until full.
await chan[].untilIsFull
chan[].untilIsFull = newFuture[void]()
result = chan[].val
chan[].untilIsEmpty.complete()



##
## # Benchmark
##
## Below, "Concurrent Prime Sieve" that matches Go reference implementation.
##
## [X] Uses coroutines.
## [X] Uses a coroutine scheduler.
## [X] Uses an async channel for communitating between coroutines.
## [X] Same 3 functions, structured like the reference.
##


proc generate(chan: ref Channel[int]) {.async.} =
## Send the sequence 2, 3, 4, ... to cannel `chan`.
for i in 2 .. int.high:
await chan.send(i)


proc filter(inChan, outChan: ref Channel[int], prime: int) {.async.} =
## Copy the values from channel `inChan` to channel `outChan`, removing those
## divisible by `prime`.
while true:
let i = await inChan.recv() # revieve value from `inChan`
if i mod prime != 0:
await outChan.send(i) # send `i` to `outChan`


proc main(n: int) {.async.} =
## The prime sieve: Daisy-chain filter processes.
var firstChan = newChannel[int]() # craete a new channel
asyncCheck generate(firstChan) # launch generate coroutine
for i in 0 ..< n:
let prime = await firstChan.recv()
echo prime
var secondChan = newChannel[int]()
asyncCheck filter(firstChan, secondChan, prime)
firstChan = secondChan


when isMainModule:

let n = if paramCount() > 0: parseInt(paramStr(1)) else: 100
waitFor main(n)


3 changes: 2 additions & 1 deletion bench/bench_nim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ problems:
source:
- 1.nim
- 3.nim
- 4.nim
- name: lru
source:
- 1.nim
Expand Down Expand Up @@ -60,7 +61,7 @@ environments:
include: nim
include_sub_dir:
before_build:
build: nimble build app -y --mm:orc -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --verbose
build: nimble build app -y --mm:orc -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --passC="-march=native -mtune=native -flto -fwhole-program" --verbose
after_build:
- cp app out
out_dir: out
Expand Down
1 change: 1 addition & 0 deletions bench/include/nim/app.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ bin = @["app"]
# Dependencies

requires "nim >= 2.0.0"
requires "chronos"
Loading