Using Nim 0.17.
Afer reading the Nim manual on Parallel programming, and how to use spawn and parallel I can't get the following code to compile.
proc residue_sieve(r: int, Kn: int) =
let row = r * pcnt # set address to ith row in next[]
let seg_rti: int = r * KB # start of seg mem for this restrack
for j, prime in primes: # for each prime <= sqrt(N) for restrack
if next[row+j] < uint(Kn): # if 1st mult resgroup index <= seg size
var k: int = int(next[row+j]) # get its resgroup value
while k < Kn: # for each primenth byte < segment size
seg[seg_rti + k] += 1'u8 # set ith residue in segment as nonprime
k += prime # compute next prime multiple resgroup
next[row+j] = uint(k - Kn) # 1st resgroup in next eligible segment
else: next[row+j] -= uint(Kn) # if 1st mult resgroup index > seg size
proc segsieve(Kn: int) = # for Kn resgroups in segment
for b in 0 .. <B: # for every byte in the segment
seg[b] = 0 # set every byte bit to prime (0)
for r in 0 .. <rescnt: # for each ith (of 8) residues for P5
spawn residue_sieve(r, Kn) # perform sieve for each separate restrack
sync()
I use import threadpool and compile with the --threads:on directive, but get this error.
[jzakiya@jabari-pc nim]$ nim c --cc:clang --d:release --threads:on ssozp5x.nim
Hint: used config file '/etc/nim.cfg' [Conf]
Hint: system [Processing]
Hint: ssozp5x [Processing]
Hint: math [Processing]
Hint: strutils [Processing]
Hint: parseutils [Processing]
Hint: algorithm [Processing]
Hint: typetraits [Processing]
Hint: threadpool [Processing]
Hint: cpuinfo [Processing]
Hint: os [Processing]
Hint: times [Processing]
Hint: posix [Processing]
Hint: ospaths [Processing]
Hint: linux [Processing]
Hint: cpuload [Processing]
ssozp5x.nim(127, 24) Error: 'spawn' takes a GC safe call expression
[jzakiya@jabari-pc nim]$
After readind the docs, I don't know what a GC (garbage collected) safe call expression is, or how to make one meet it. Can someone explain how to get this code to compile?
GC unsafe means you're using a mutable variable from outside of thread scope. Very likely you're using a global variable or such which not local to that invoked thread.
For safer solution, change your code to remove any instance of mutable shared variables.
For unsafe and not recommended solution, use --threadAnalysis:off when you compile your code. Just aware that you'll frequently find segfault if you do this, or worse, you get race-conditioned data.
Compiling with --threadAnalysis:off did allow the program to compile and run with no segfaults, and it produces the correct results, but it's 2x slower than the serial version.
In the code snippet, the next, seg, and primes arrays (seqs), and the constant rescnt are global parameters. primes is only being read from. Each thread of residue_sieve is using independent memory chunks of seg to read/write to. The problem may be with next which is read/written to in each thread, though never from the same location for any thread (where it is read/written to for each thread is differennt).
Is there detailed documentation of some non-trivial example to show how to actually create running parallel code?
If I need to re-architect the algorithm I first want to really understand the details of what needs to be done before I undertake that task.