Skip to content

Commit a8831c9

Browse files
author
Kevin Lewis
committed
fix build and add new implementations
1 parent 6863f1c commit a8831c9

File tree

4 files changed

+137
-4
lines changed

4 files changed

+137
-4
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import chronos
2+
import std/os
3+
import std/strutils
4+
5+
6+
7+
8+
9+
10+
11+
proc generate(chan: AsyncQueue[int]) {.async.} =
12+
## Send the sequence 2, 3, 4, ... to cannel `chan`.
13+
for i in 2 .. int.high:
14+
await chan.addFirst(i)
15+
16+
17+
proc filter(inChan, outChan: AsyncQueue[int], prime: int) {.async.} =
18+
## Copy the values from channel `inChan` to channel `outChan`, removing those
19+
## divisible by `prime`.
20+
while true:
21+
let i = await inChan.popLast() # revieve value from `inChan`
22+
if i mod prime != 0:
23+
await outChan.addFirst(i) # send `i` to `outChan`
24+
25+
26+
proc main(n: int) {.async.} =
27+
## The prime sieve: Daisy-chain filter processes.
28+
var firstChan = newAsyncQueue[int](1) # craete a new channel
29+
asyncCheck generate(firstChan) # launch generate coroutine
30+
for i in 0 ..< n:
31+
let prime = await firstChan.popLast()
32+
echo prime
33+
var secondChan = newAsyncQueue[int](1)
34+
asyncCheck filter(firstChan, secondChan, prime)
35+
firstChan = secondChan
36+
37+
38+
when isMainModule:
39+
40+
let n = if paramCount() > 0: parseInt(paramStr(1)) else: 100
41+
waitFor main(n)
42+
43+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import yasync
2+
import chronos
3+
import std/os
4+
import std/strutils
5+
6+
7+
##
8+
## Channel implementation copied from the `yasync` repo, testcase `test7.nim`
9+
##
10+
11+
type
12+
Channel[T] = object
13+
waitingCont: ptr Cont[T]
14+
sendingCont: ptr Cont[void]
15+
val: T
16+
17+
proc send[T](c: var Channel[T], v: T, env: ptr Cont[void]) {.asyncRaw.} =
18+
doAssert(c.sendingCont == nil, "Too many senders")
19+
if c.waitingCont == nil:
20+
c.val = v
21+
c.sendingCont = env
22+
else:
23+
let cont = c.waitingCont
24+
c.waitingCont = nil
25+
cont.complete(v)
26+
env.complete()
27+
28+
proc recv[T](c: var Channel[T], env: ptr Cont[T]) {.asyncRaw.} =
29+
doAssert(c.waitingCont == nil, "Too many receivers")
30+
if c.sendingCont == nil:
31+
c.waitingCont = env
32+
else:
33+
let cont = c.sendingCont
34+
c.sendingCont = nil
35+
env.complete(c.val)
36+
cont.complete()
37+
38+
proc newChannel[T](): ref Channel[T] =
39+
new(result)
40+
41+
42+
##
43+
## # Benchmark
44+
##
45+
## Below, "Concurrent Prime Sieve" that matches Go reference implementation.
46+
##
47+
## [X] Uses coroutines.
48+
## [X] Uses a coroutine scheduler.
49+
## [X] Uses an async channel for communitating between coroutines.
50+
## [X] Same 3 functions, structured like the reference.
51+
##
52+
53+
proc generate(chan: ref Channel[int]) {.yasync.async.} =
54+
## Send the sequence 2, 3, 4, ... to cannel `chan`.
55+
for i in 2 .. int.high:
56+
await chan[].send(i)
57+
58+
proc filter(inChan, outChan: ref Channel[int], prime: int) {.yasync.async.} =
59+
## Copy the values from channel `inChan` to channel `outChan`, removing those
60+
## divisible by `prime`.
61+
while true:
62+
let i = await inChan[].recv() # revieve value from `inChan`
63+
if i mod prime != 0:
64+
await outChan[].send(i) # send `i` to `outChan`
65+
66+
proc main(n: int) {.yasync.async.} =
67+
## The prime sieve: Daisy-chain filter processes.
68+
var firstChan = newChannel[int]() # craete a new channel
69+
discard generate(firstChan) # launch generate coroutine
70+
for i in 0 ..< n:
71+
let prime = await firstChan[].recv()
72+
echo prime
73+
var secondChan = newChannel[int]()
74+
discard filter(firstChan, secondChan, prime)
75+
firstChan = secondChan
76+
77+
when isMainModule:
78+
79+
let n = if paramCount() > 0: parseInt(paramStr(1)) else: 100
80+
var env: asyncCallEnvType(main(n))
81+
asyncLaunchWithEnv(env, main(n))
82+
83+

bench/bench_nim.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ problems:
3434
- 1.nim
3535
- 3.nim
3636
- 4.nim
37+
- 5.nim
38+
- 6.nim
3739
- name: lru
3840
source:
3941
- 1.nim
@@ -60,8 +62,10 @@ environments:
6062
# docker: nimlang/nim
6163
include: nim
6264
include_sub_dir:
63-
before_build: nimble install --depsOnly
64-
build: nimble build app -y --mm:orc -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --verbose
65+
before_build:
66+
- nimble refresh
67+
- nimble install --depsOnly
68+
build: nimble cpp app -y --mm:orc -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --passC=-march=native --passC=-mtune=native --passC=-flto --passC=-fwhole-program --verbose
6569
after_build:
6670
- cp app out
6771
out_dir: out
@@ -72,8 +76,10 @@ environments:
7276
# docker: nimlang/nim
7377
include: nim
7478
include_sub_dir:
75-
before_build: nimble install --depsOnly
76-
build: nimble build app -y --mm:orc --cc:clang -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --verbose
79+
before_build:
80+
- nimble refresh
81+
- nimble install --depsOnly
82+
build: nimble build app -y --mm:orc --cc:clang -d:danger --panics:on -d:nimCoroutines --threads:on --tlsEmulation:off --verbose
7783
after_build:
7884
- cp app out
7985
out_dir: out

bench/include/nim/app.nimble

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ bin = @["app"]
1111

1212
requires "nim >= 2.0.0"
1313
requires "chronos"
14+
requires "yasync"

0 commit comments

Comments
 (0)