diff options
Diffstat (limited to 'tests/parallel')
32 files changed, 1137 insertions, 0 deletions
diff --git a/tests/parallel/nim.cfg b/tests/parallel/nim.cfg new file mode 100644 index 000000000..d0d2a9305 --- /dev/null +++ b/tests/parallel/nim.cfg @@ -0,0 +1,2 @@ +threads:on +--experimental diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim new file mode 100644 index 000000000..191939100 --- /dev/null +++ b/tests/parallel/t10913.nim @@ -0,0 +1,20 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" +""" + +# bug #10913 + +import threadpool + +proc useParallel*[T](unused: T) = + # use a generic T here to show the problem. + {.push experimental: "parallel".} + parallel: + for i in 0..4: + spawn echo "echo in parallel" + sync() + + {.pop.} + +useParallel(1) diff --git a/tests/parallel/t5000.nim b/tests/parallel/t5000.nim new file mode 100644 index 000000000..1dd47a61c --- /dev/null +++ b/tests/parallel/t5000.nim @@ -0,0 +1,25 @@ +discard """ + output: '''50005000''' + disabled: "true" +""" + +# XXX this seems to deadlock certain Linux machines + +import threadpool, strutils + +proc foo(x: int): string = $x + +proc main() = + var a = newSeq[int]() + for i in 1..10000: + add(a, i) + + var s = 0 + for i in a: + s += parseInt(^spawn(foo(i))) + echo s + +setMaxPoolSize 2 + +parallel: + spawn main() diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim new file mode 100644 index 000000000..7817a1c9e --- /dev/null +++ b/tests/parallel/t7535.nim @@ -0,0 +1,11 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]" +""" + +import threadpool + +# bug #7535 +proc print_parallel_nok(r: uint32) = + for x in 0..r: + spawn (proc (x: uint32) = echo x) diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim new file mode 100644 index 000000000..254f03416 --- /dev/null +++ b/tests/parallel/t9691.nim @@ -0,0 +1,9 @@ +discard """ + matrix: "--mm:refc; --mm:orc" + errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter" +""" + +# bug #9691 + +import threadpool +spawn echo() diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim new file mode 100644 index 000000000..9479227aa --- /dev/null +++ b/tests/parallel/tarray_of_channels.nim @@ -0,0 +1,39 @@ +discard """ +sortoutput: true +output: ''' +(x: 0.0) +(x: 0.0) +(x: 0.0) +test +test +test +''' +disabled: "openbsd" +""" + +# bug #2257 +import threadpool + +type StringChannel = Channel[string] +var channels: array[1..3, StringChannel] + +type + MyObject[T] = object + x: T + +var global: MyObject[string] +var globalB: MyObject[float] + +proc consumer(ix : int) {.thread.} = + echo channels[ix].recv() ###### not GC-safe: 'channels' + echo globalB + +proc main = + for ix in 1..3: channels[ix].open() + for ix in 1..3: spawn consumer(ix) + for ix in 1..3: channels[ix].send("test") + sync() + for ix in 1..3: channels[ix].close() + +when true: + main() diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim new file mode 100644 index 000000000..f3ccd166a --- /dev/null +++ b/tests/parallel/tblocking_channel.nim @@ -0,0 +1,39 @@ +discard """ +output: "" +disabled: "freebsd" # see #15725 +""" + +import threadpool, os + +var chan: Channel[int] + +chan.open(2) +chan.send(1) +chan.send(2) +doAssert(not chan.trySend(3)) # At this point chan is at max capacity + +proc receiver() = + doAssert(chan.recv() == 1) + doAssert(chan.recv() == 2) + doAssert(chan.recv() == 3) + doAssert(chan.recv() == 4) + doAssert(chan.recv() == 5) + +var msgSent = false + +proc emitter() = + chan.send(3) + msgSent = true + +spawn emitter() +# At this point emitter should be stuck in `send` +sleep(50) # Sleep a bit to ensure that it is still stuck +doAssert(not msgSent) + +spawn receiver() +sleep(50) # Sleep a bit to let receicer consume the messages +doAssert(msgSent) # Sender should be unblocked + +doAssert(chan.trySend(4)) +chan.send(5) +sync() diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim new file mode 100644 index 000000000..a89aa910b --- /dev/null +++ b/tests/parallel/tconvexhull.nim @@ -0,0 +1,60 @@ +discard """ + matrix: "--mm:refc" + output: ''' +''' +""" + +# parallel convex hull for Nim bigbreak +# nim c --threads:on -d:release pconvex_hull.nim +import algorithm, sequtils, threadpool + +type Point = tuple[x, y: float] + +proc cmpPoint(a, b: Point): int = + result = cmp(a.x, b.x) + if result == 0: + result = cmp(a.y, b.y) + +template cross[T](o, a, b: T): untyped = + (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) + +template pro(): untyped = + while lr1 > 0 and cross(result[lr1 - 1], result[lr1], p[i]) <= 0: + discard result.pop + lr1 -= 1 + result.add(p[i]) + lr1 += 1 + +proc half[T](p: seq[T]; upper: bool): seq[T] = + var i, lr1: int + result = @[] + lr1 = -1 + if upper: + i = 0 + while i <= high(p): + pro() + i += 1 + else: + i = high(p) + while i >= low(p): + pro() + i -= 1 + discard result.pop + +proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] = + if len(points) < 2: return points + points.sort(cmp) + var ul: array[2, FlowVar[seq[T]]] + parallel: + for k in 0..ul.high: + ul[k] = spawn half[T](points, k == 0) + result = concat(^ul[0], ^ul[1]) + +var s = map(toSeq(0..9999), proc(x: int): Point = (float(x div 100), float(x mod 100))) +# On some runs, this pool size reduction will set the "shutdown" attribute on the +# worker thread that executes our spawned task, before we can read the flowvars. +setMaxPoolSize 2 + +for i in 0..2: + doAssert convex_hull[Point](s, cmpPoint) == + @[(0.0, 0.0), (99.0, 0.0), (99.0, 99.0), (0.0, 99.0)] diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim new file mode 100644 index 000000000..96ca15ca3 --- /dev/null +++ b/tests/parallel/tdeepcopy.nim @@ -0,0 +1,55 @@ +discard """ + matrix: "--mm:refc" + output: ''' +13 abc +called deepCopy for int +called deepCopy for int +done999 999 +''' +""" + +import threadpool + +block one: + type + PBinaryTree = ref object + le, ri: PBinaryTree + value: int + + proc main = + var x: PBinaryTree + deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13)))) + var y: string + deepCopy y, "abc" + echo x.ri.le.value, " ", y + + main() + + +block two: + type + Bar[T] = object + x: T + + proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] = + result.new + result.x = b.x + when T is int: + echo "called deepCopy for int" + else: + echo "called deepCopy for something else" + + proc foo(b: ref Bar[int]): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + + proc main = + var dummy: ref Bar[int] + new(dummy) + dummy.x = 44 + #parallel: + let f = spawn foo(dummy) + let b = spawn foo(dummy) + echo "done", ^f, " ", ^b + + main() diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim new file mode 100644 index 000000000..e8305173d --- /dev/null +++ b/tests/parallel/tdeepcopy2.nim @@ -0,0 +1,38 @@ +discard """ + matrix: "--mm:refc" + output: ''' +called deepCopy for int +called deepCopy for int +done999 999 +''' +""" + +import threadpool + + +type + Bar[T] = object + x: T + +proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] = + result.new + result.x = b.x + when T is int: + echo "called deepCopy for int" + else: + echo "called deepCopy for something else" + +proc foo(b: ref Bar[int]): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + +proc main = + var dummy: ref Bar[int] + new(dummy) + dummy.x = 44 + #parallel: + let f = spawn foo(dummy) + let b = spawn foo(dummy) + echo "done", ^f, " ", ^b + +main() diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim new file mode 100644 index 000000000..6892e7383 --- /dev/null +++ b/tests/parallel/tdisjoint_slice1.nim @@ -0,0 +1,51 @@ +discard """ + matrix: "--mm:refc" + outputsub: "EVEN 28" +""" + +import threadpool, locks + +block one: + proc odd(a: int) = echo "ODD ", a + proc even(a: int) = echo "EVEN ", a + + proc main() = + var a: array[0..30, int] + for i in low(a)..high(a): a[i] = i + parallel: + var i = 0 + while i <= 29: + spawn even(a[i]) + spawn odd(a[i+1]) + inc i, 2 + # is correct here + + main() + + +block two: + var echoLock: Lock + initLock echoLock + + proc f(a: openArray[int]) = + for x in a: + withLock echoLock: + echo x + + proc f(a: int) = + withLock echoLock: + echo a + + proc main() = + var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] + parallel: + spawn f(a[0..2]) + #spawn f(a[16..30]) + var i = 3 + while i <= 8: + spawn f(a[i]) + spawn f(a[i+1]) + inc i, 2 + # is correct here + + main() diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim new file mode 100644 index 000000000..e44b29a87 --- /dev/null +++ b/tests/parallel/tflowvar.nim @@ -0,0 +1,38 @@ +discard """ + matrix: "--mm:refc" + output: '''foobarfoobar +bazbearbazbear + +1''' + cmd: "nim $target --threads:on $options $file" + disabled: "openbsd" +""" + +import threadpool + +proc computeSomething(a, b: string): string = a & b & a & b & "\n" + +proc main = + let fvA = spawn computeSomething("foo", "bar") + let fvB = spawn computeSomething("baz", "bear") + + echo(^fvA, ^fvB) + +main() +sync() + + +type + TIntSeq = seq[int] + +proc t(): TIntSeq = + result = @[1] + +proc p(): int = + var a: FlowVar[TIntSeq] + parallel: + var aa = spawn t() + a = aa + result = (^a)[0] + +echo p() diff --git a/tests/parallel/tforstmt.nim b/tests/parallel/tforstmt.nim new file mode 100644 index 000000000..58de833f3 --- /dev/null +++ b/tests/parallel/tforstmt.nim @@ -0,0 +1,25 @@ +discard """ + output: '''3 +4 +5 +6 +7''' + sortoutput: true +""" + +import threadpool, os + +proc p(x: int) = + os.sleep(100 - x*10) + echo x + +proc testFor(a, b: int; foo: var openArray[int]) = + parallel: + for i in max(a, 0) .. min(b, foo.high): + spawn p(foo[i]) + +var arr = [0, 1, 2, 3, 4, 5, 6, 7] + +testFor(3, 10, arr) + + diff --git a/tests/parallel/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim new file mode 100644 index 000000000..baf0dc24a --- /dev/null +++ b/tests/parallel/tgc_unsafe.nim @@ -0,0 +1,32 @@ +discard """ + errormsg: "'consumer' is not GC-safe" + line: 19 +""" + +# bug #2257 +import threadpool + +type StringChannel = Channel[string] +var channels: array[1..3, StringChannel] + +type + MyObject[T] = object + x: T + +var global: MyObject[string] +var globalB: MyObject[float] + +proc consumer(ix : int) {.thread.} = + echo channels[ix].recv() ###### not GC-safe: 'channels' + echo global + echo globalB + +proc main = + for ix in 1..3: channels[ix].open() + for ix in 1..3: spawn consumer(ix) + for ix in 1..3: channels[ix].send("test") + sync() + for ix in 1..3: channels[ix].close() + +when true: + main() diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim new file mode 100644 index 000000000..7d98dafcb --- /dev/null +++ b/tests/parallel/tgc_unsafe2.nim @@ -0,0 +1,38 @@ +discard """ + errormsg: "'consumer' is not GC-safe as it calls 'track'" + nimout: '''tgc_unsafe2.nim(21, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2] +tgc_unsafe2.nim(25, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2] +tgc_unsafe2.nim(27, 6) Error: 'consumer' is not GC-safe as it calls 'track' +''' +""" + +import threadpool + +type StringChannel = Channel[string] +var channels: array[1..3, StringChannel] + +type + MyObject[T] = object + x: T + +var global: MyObject[string] +var globalB: MyObject[float] + +proc trick(ix: int) = + echo global.x + echo channels[ix].recv() + +proc track(ix: int) = trick(ix) + +proc consumer(ix: int) {.thread.} = + track(ix) + +proc main = + for ix in 1..3: channels[ix].open() + for ix in 1..3: spawn consumer(ix) + for ix in 1..3: channels[ix].send("test") + sync() + for ix in 1..3: channels[ix].close() + +when true: + main() diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim new file mode 100644 index 000000000..f4c92319b --- /dev/null +++ b/tests/parallel/tguard1.nim @@ -0,0 +1,41 @@ +discard """ +output: "90" +""" + + +when false: + template lock(a, b: ptr Lock; body: stmt) = + if cast[int](a) < cast[int](b): + pthread_mutex_lock(a) + pthread_mutex_lock(b) + else: + pthread_mutex_lock(b) + pthread_mutex_lock(a) + {.locks: [a, b].}: + try: + body + finally: + pthread_mutex_unlock(a) + pthread_mutex_unlock(b) + +type + ProtectedCounter[T] = object + i {.guard: L.}: T + L: int + +var + c: ProtectedCounter[int] + +c.i = 89 + +template atomicRead(L, x): untyped = + {.locks: [L].}: + x + +proc main = + {.locks: [c.L].}: + inc c.i + discard + echo(atomicRead(c.L, c.i)) + +main() diff --git a/tests/parallel/tguard2.nim b/tests/parallel/tguard2.nim new file mode 100644 index 000000000..661893bb5 --- /dev/null +++ b/tests/parallel/tguard2.nim @@ -0,0 +1,27 @@ +discard """ + errormsg: "unguarded access: c.i" + line: 25 +""" + +type + ProtectedCounter[T] = object + i {.guard: L.}: T + L: int + +var + c: ProtectedCounter[int] + +c.i = 89 + +template atomicRead(L, x): untyped = + {.locks: [L].}: + x + +proc main = + {.locks: [c.L].}: + inc c.i + discard + echo(atomicRead(c.L, c.i)) + echo c.i + +main() diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim new file mode 100644 index 000000000..8dc93c33f --- /dev/null +++ b/tests/parallel/tinvalid_array_bounds.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--mm:refc" + errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)" + line: 21 +""" + +import threadpool + +proc f(a: openArray[int]) = + for x in a: echo x + +proc f(a: int) = echo a + +proc main() = + var a: array[0..30, int] + parallel: + spawn f(a[0..15]) + spawn f(a[16..30]) + var i = 0 + while i <= 30: + spawn f(a[i]) + spawn f(a[i+1]) + inc i + #inc i # inc i, 2 would be correct here + +main() diff --git a/tests/parallel/tinvalid_counter_usage.nim b/tests/parallel/tinvalid_counter_usage.nim new file mode 100644 index 000000000..c6303c651 --- /dev/null +++ b/tests/parallel/tinvalid_counter_usage.nim @@ -0,0 +1,26 @@ +discard """ + errormsg: "invalid usage of counter after increment" + line: 21 +""" + +import threadpool + +proc f(a: openArray[int]) = + for x in a: echo x + +proc f(a: int) = echo a + +proc main() = + var a: array[0..30, int] + parallel: + spawn f(a[0..15]) + spawn f(a[16..30]) + var i = 0 + while i <= 30: + inc i + spawn f(a[i]) + inc i + #spawn f(a[i+1]) + #inc i # inc i, 2 would be correct here + +main() diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim new file mode 100644 index 000000000..853ffc443 --- /dev/null +++ b/tests/parallel/tlet_spawn.nim @@ -0,0 +1,28 @@ +discard """ +output: ''' +done999 999 +''' +""" + +import std/[threadpool, os] + +proc foo(): int = 999 + +# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()': + +proc main = + parallel: + let f = spawn foo() + let b = spawn foo() + echo "done", f, " ", b + +main() + +# bug #13781 +proc thread(): string = + os.sleep(1000) + return "ok" + +var fv = spawn thread() +sync() +doAssert ^fv == "ok" diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim new file mode 100644 index 000000000..ea77936ad --- /dev/null +++ b/tests/parallel/tmissing_deepcopy.nim @@ -0,0 +1,42 @@ +discard """ + matrix: "--mm:refc" + ccodeCheck: "@'genericDeepCopy(' .*" + action: compile +""" + +# bug #2286 + +import threadPool + +type + Person = ref object + name: string + friend: Person + +var + people: seq[Person] = @[] + +proc newPerson(name:string): Person = + result.new() + result.name = name + +proc greet(p:Person) = + p.friend.name &= "-MUT" # this line crashes the program + echo "Person {", + " name:", p.name, "(", cast[int](addr p.name),"),", + " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }" + +proc setup = + for i in 0 ..< 10: + people.add newPerson("Person" & $(i + 1)) + for i in 0 ..< 10: + people[i].friend = people[9-i] + +proc update = + parallel: + for i in 0 .. people.high: + spawn people[i].greet() + +when true: + setup() + update() diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim new file mode 100644 index 000000000..51762187d --- /dev/null +++ b/tests/parallel/tnon_disjoint_slice1.nim @@ -0,0 +1,26 @@ +discard """ + matrix: "--mm:refc" + errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)" + line: 21 +""" + +import threadpool + +proc f(a: openArray[int]) = + for x in a: echo x + +proc f(a: int) = echo a + +proc main() = + var a: array[0..30, int] + parallel: + #spawn f(a[0..15]) + #spawn f(a[16..30]) + var i = 0 + while i <= 29: + spawn f(a[i]) + spawn f(a[i+1]) + inc i + #inc i # inc i, 2 would be correct here + +main() diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim new file mode 100644 index 000000000..cf1bc9336 --- /dev/null +++ b/tests/parallel/tparfind.nim @@ -0,0 +1,29 @@ +discard """ + matrix: "--mm:refc" + output: "500" +""" + +import threadpool, sequtils + +{.experimental: "parallel".} + +proc linearFind(a: openArray[int]; x, offset: int): int = + for i, y in a: + if y == x: return i+offset + result = -1 + +proc parFind(a: seq[int]; x: int): int = + var results: array[4, int] + parallel: + if a.len >= 4: + let chunk = a.len div 4 + results[0] = spawn linearFind(a[0 ..< chunk], x, 0) + results[1] = spawn linearFind(a[chunk ..< chunk*2], x, chunk) + results[2] = spawn linearFind(a[chunk*2 ..< chunk*3], x, chunk*2) + results[3] = spawn linearFind(a[chunk*3 ..< a.len], x, chunk*3) + result = max(results) + + +let data = toSeq(0..1000) +echo parFind(data, 500) + diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim new file mode 100644 index 000000000..cd965d585 --- /dev/null +++ b/tests/parallel/tpi.nim @@ -0,0 +1,27 @@ +discard """ + matrix: "--mm:refc" + output: '''3.141792613595791 +3.141792613595791''' +""" + +import strutils, math, threadpool + +proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1) + +proc piU(n: int): float = + var ch = newSeq[FlowVar[float]](n+1) + for k in 0..ch.high: + ch[k] = spawn term(float(k)) + for k in 0..ch.high: + result += ^ch[k] + +proc piS(n: int): float = + var ch = newSeq[float](n+1) + parallel: + for k in 0..ch.high: + ch[k] = spawn term(float(k)) + for k in 0..ch.high: + result += ch[k] + +echo formatFloat(piU(5000)) +echo formatFloat(piS(5000)) diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim new file mode 100644 index 000000000..ae02c16e5 --- /dev/null +++ b/tests/parallel/tptr_to_ref.nim @@ -0,0 +1,71 @@ +# bug #2854 + +# Test case for the compiler correctly detecting if a type used by a shared +# global is gcsafe. + +import locks, threadpool, osproc + +const MAX_WORKERS = 50 + +type + Killer* = object + lock: Lock + bailed {.guard: lock.}: bool + processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process] + +# Hold a lock for a statement. +template hold(lock: Lock, body: untyped) = + lock.acquire + defer: lock.release + {.locks: [lock].}: + body + +# Return an initialized Killer. +proc initKiller*(): Killer = + initLock(result.lock) + result.lock.hold: + result.bailed = false + for i, _ in result.processes: + result.processes[i] = nil + +# Global Killer instance. +var killer = initKiller() + +# remember that a process has been launched, killing it if we have bailed. +proc launched*(process: ptr Process): int {.gcsafe.} = + result = killer.processes.high + 1 + killer.lock.hold: + if killer.bailed: + process[].terminate() + else: + for i, _ in killer.processes: + if killer.processes[i] == nil: + killer.processes[i] = process + result = i + assert(result <= killer.processes.high) + + +# A process has been finished with - remove the process from death row. +# Return true if the process was still present, which will be the +# case unless we have bailed. +proc completed*(index: int): bool {.gcsafe.} = + result = true + if index <= killer.processes.high: + killer.lock.hold: + result = false + if killer.processes[index] != nil: + result = true + killer.processes[index] = nil + + +# Terminate all the processes killer knows about, doing nothing if +# already bailed. +proc bail(): bool {.gcsafe.} = + killer.lock.hold: + result = not killer.bailed + if not killer.bailed: + killer.bailed = true + for i, process in killer.processes: + if process != nil: + process[].terminate + killer.processes[i] = nil diff --git a/tests/parallel/treadafterwrite.nim b/tests/parallel/treadafterwrite.nim new file mode 100644 index 000000000..12eb31402 --- /dev/null +++ b/tests/parallel/treadafterwrite.nim @@ -0,0 +1,31 @@ +discard """ + errormsg: "'foo' not disjoint from 'foo'" + line: 23 + disabled: "true" +""" + +# bug #1597 + +import strutils, math, threadpool + +type + BoxedFloat = object + value: float + +proc term(k: float): ptr BoxedFloat = + var temp = 4 * math.pow(-1, k) / (2*k + 1) + result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat))) + result.value = temp + +proc pi(n: int): float = + var ch = newSeq[ptr BoxedFloat](n+1) + parallel: + for k in 0..ch.high: + let foo = (spawn term(float(k))) + assert foo != nil + for k in 0..ch.high: + var temp = ch[k][].value + result += temp + deallocShared(ch[k]) + +echo formatFloat(pi(5000)) diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim new file mode 100644 index 000000000..9f4a2e06e --- /dev/null +++ b/tests/parallel/tsendtwice.nim @@ -0,0 +1,65 @@ +discard """ + matrix: "--mm:refc" +""" + +# bug #4776 + +import tables, algorithm + +type + Base* = ref object of RootObj + someSeq: seq[int] + baseData: array[40000, byte] + Derived* = ref object of Base + data: array[40000, byte] + +type + ThreadPool = ref object + threads: seq[ptr Thread[ThreadArg]] + channels: seq[ThreadArg] + TableChannel = Channel[TableRef[string, Base]] + ThreadArg = ptr TableChannel + +var globalTable {.threadvar.}: TableRef[string, Base] +globalTable = newTable[string, Base]() +let d = new(Derived) +globalTable.add("ob", d) +globalTable.add("ob2", d) +globalTable.add("ob3", d) + +proc `<`(x, y: seq[int]): bool = x.len < y.len +proc kvs(t: TableRef[string, Base]): seq[(string, seq[int])] = + for k, v in t.pairs: result.add (k, v.someSeq) + result.sort + +proc testThread(channel: ptr TableChannel) {.thread.} = + globalTable = channel[].recv() + var myObj: Base + deepCopy(myObj, globalTable["ob"]) + myObj.someSeq = newSeq[int](100) + let table = channel[].recv() # same table + assert(table.contains("ob")) # fails! + assert(table.contains("ob2")) # fails! + assert(table.contains("ob3")) # fails! + assert table.kvs == globalTable.kvs # Last to see above spot checks first + +var channel: TableChannel + +proc newThreadPool(threadCount: int) = #: ThreadPool = + #new(result) + #result.threads = newSeq[ptr Thread[ThreadArg]](threadCount) + #var channel = cast[ptr TableChannel](allocShared0(sizeof(TableChannel))) + channel.open() + channel.send(globalTable) + channel.send(globalTable) + #createThread(threadPtr[], testThread, addr channel) + testThread(addr channel) + #result.threads[i] = threadPtr + +proc stop(p: ThreadPool) = + for t in p.threads: + joinThread(t[]) + dealloc(t) + + +newThreadPool(1)#.stop() diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim new file mode 100644 index 000000000..ab292f935 --- /dev/null +++ b/tests/parallel/tsimple_array_checks.nim @@ -0,0 +1,75 @@ +discard """ +sortoutput: true +output: ''' +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +Hello 1 +Hello 2 +Hello 3 +Hello 4 +Hello 5 +Hello 6 +''' +""" + +# bug #2287 + +import threadPool + +# If `nums` is an array instead of seq, +# NONE of the iteration ways below work (including high / len-1) +let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +proc log(n:int) = + echo n + +proc main = + parallel: + for n in nums: # Error: cannot prove: i <= len(nums) + -1 + spawn log(n) + #for i in 0 ..< nums.len: # Error: cannot prove: i <= len(nums) + -1 + #for i in 0 .. nums.len-1: # WORKS! + #for i in 0 ..< nums.len: # WORKS! + # spawn log(nums[i]) + +# Array needs explicit size to work, probably related to issue #2287 +#const a: array[0..5, int] = [1,2,3,4,5,6] + +#const a = [1,2,3,4,5,6] # Doesn't work +const a = @[1,2,3,4,5,6] # Doesn't work +proc f(n: int) = echo "Hello ", n + +proc maino = + parallel: + # while loop doesn't work: + var i = 0 + while i < a.high: + #for i in countup(0, a.high-1, 2): + spawn f(a[i]) + spawn f(a[i+1]) + i += 2 + +maino() # Doesn't work outside a proc + +when true: + main() + +block two: + proc f(a: openArray[int]) = + discard + + proc main() = + var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9] + parallel: + spawn f(a[0..2]) + + + main() \ No newline at end of file diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim new file mode 100644 index 000000000..b7ecd1264 --- /dev/null +++ b/tests/parallel/tsysspawn.nim @@ -0,0 +1,64 @@ +discard """ + output: '''4 +8 +(a: 1) +2 +2 +''' + matrix: "--mm:refc" +""" + +import threadpool + +var + x, y = 0 + +proc p1 = + for i in 0 .. 10_000: + discard + + atomicInc x + +proc p2 = + for i in 0 .. 10_000: + discard + + atomicInc y, 2 + +for i in 0.. 3: + spawn(p1()) + spawn(p2()) + +sync() + +echo x +echo y + + +#-------------------------------------------------------- +# issue #14014 + +import threadpool + +type A = object + a: int + +proc f(t: typedesc): t = + t(a:1) + +let r = spawn f(A) +echo ^r + +proc f2(x: static[int]): int = + x + +let r2 = spawn f2(2) +echo ^r2 + +type statint = static[int] + +proc f3(x: statint): int = + x + +let r3 = spawn f3(2) +echo ^r3 diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim new file mode 100644 index 000000000..a8f1ed401 --- /dev/null +++ b/tests/parallel/tsysspawnbadarg.nim @@ -0,0 +1,9 @@ +discard """ + errormsg: "'spawn' takes a call expression" + line: 9 + cmd: "nim $target --threads:on $options $file" +""" + +import threadpool + +let foo = spawn(1) diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim new file mode 100644 index 000000000..64f835a1b --- /dev/null +++ b/tests/parallel/tuseafterdef.nim @@ -0,0 +1,34 @@ +discard """ + matrix: "--mm:refc" + disabled: true + errormsg: "(k)..(k) not disjoint from (k)..(k)" + line: 24 + action: compile +""" + +# bug #1597 + +import strutils, math, threadpool + +type + BoxedFloat = object + value: float + +proc term(k: float): ptr BoxedFloat = + var temp = 4 * math.pow(-1, k) / (2*k + 1) + result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat))) + result.value = temp + +proc pi(n: int): float = + var ch = newSeq[ptr BoxedFloat](n+1) + parallel: + for k in 0..ch.high: + ch[k] = (spawn term(float(k))) + assert ch[k] != nil + for k in 0..ch.high: + var temp = ch[k][].value + result += temp + deallocShared(ch[k]) + + +echo formatFloat(pi(5000)) diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim new file mode 100644 index 000000000..d57c5f40f --- /dev/null +++ b/tests/parallel/twaitany.nim @@ -0,0 +1,34 @@ +discard """ + matrix: "--mm:refc" + output: '''true''' +""" + +# bug #7638 +import threadpool, os + +proc timer(d: int): int = + #echo fmt"sleeping {d}" + sleep(d) + #echo fmt"done {d}" + return d + +var durations = [1000, 1500, 2000] +var tasks: seq[FlowVarBase] = @[] +var results: seq[int] = @[] + +for i in 0 .. durations.high: + tasks.add spawn timer(durations[i]) + +var index = blockUntilAny(tasks) +while index != -1: + results.add ^cast[FlowVar[int]](tasks[index]) + tasks.del(index) + #echo repr results + index = blockUntilAny(tasks) + +doAssert results.len == 3 +doAssert 1000 in results +doAssert 1500 in results +doAssert 2000 in results +sync() +echo "true" |