I will have to preface that this is happens with benchy specifically, when the calling proc is called normally it doesn't happen.
Using windows 11 nim 2.2.2
So I am trying advent of code day 8, and tried to parallel solve part 2 (which turned out much slower :D).
type
Coord = object
x, y: int
Freq = char
GroupedAntennas = Table[Freq, seq[Coord]]
GuardedSeq = object
v: seq[Coord]
l: Lock
template guardedSeqAdd(loc: Coord, guardedSeq: ref GuardedSeq)=
withLock(guardedSeq.l):
guardedSeq.v.add(loc)
func threadworker(locs: ptr seq[Coord], loc: Coord,grid: Coord, guardedSeq: ref GuardedSeq)=
# func threadworker(locs: ptr seq[Coord], loc: Coord,grid: Coord, guardedSeq: ptr GuardedSeq)=
var antinode, nextNode, nextNode2, tempNode: Coord
for otherLoc in locs[]:
if otherLoc == loc: continue
guardedSeqAdd(otherLoc, guardedSeq)
antinode = getAntinode(loc, otherLoc)
nextNode = otherLoc
nextNode2 = antinode
while true:
if inGrid(nextNode2, grid):
guardedSeqAdd(nextNode2, guardedSeq)
tempNode = nextNode2
nextNode2 = getAntinode(nextNode, nextNode2)
nextNode = tempNode
else: break
proc getAllAntinodes2multi(antennas: GroupedAntennas, grid: Coord): HashSet[Coord] =
var guardedSeq = new GuardedSeq
# var guardedSeq = GuardedSeq()
guardedSeq.l.initLock()
for locs in antennas.values:
let locsPtr = locs.addr
for loc in locs:
spawn threadworker(locs.addr, loc, grid, guardedSeq)
# spawn threadworker(locs.addr, loc, grid, guardedSeq.addr)
sync()
withLock(guardedSeq.l):
return toHashSet(guardedSeq.v)
When guardedSeq (seq of int with lock) is made as a reference and passed to threadworker, benchy gets sigsegv. When it is created as a value object and its address is passed (and the threadworker signature corrected), it works perfectly I have verified that the ref guardedSeq is initiated at the beginning, and works for some iterations before crashing. Printing the (guardedSeq/counter) in the either loop also prevents the crashes so maybe there is a race condition (in the runtime of ref or benchy)
https://github.com/enaaab460/day8 is the entire folder, src/lib has all the functions, src/main works normally, src/bench and src/bench2 don't work when ref is used
building using -d:release
refs output:
min time avg time std dv runs name
0.076 ms 0.095 ms ±0.020 x1000 level1
0.230 ms 0.257 ms ±0.043 x1000 level2
SIGSEGV: Illegal storage access. (Attempt to read from nil?)
ptr output:
min time avg time std dv runs name
0.074 ms 0.086 ms ±0.014 x1000 level1
0.222 ms 0.254 ms ±0.040 x1000 level2
1.792 ms 24.430 ms ±43.252 x206 level2 multicore
Malebolgia doesn't accept ref arguments (or whatever Error: 'toTask'ed function cannot have a parameter of nnkRefTy kind means)
Weave worked once in the 5 times I ran src/bench.
Returning the results from threadworker and adding them after the loop is faster (3ms), so I will abandon the guardedseq idea, but maybe it is worth looking into the cause of the crash.
I also don't understand how it is still much slower than the single threaded version.
but maybe it is worth looking into the cause of the crash.
No, it's well known that ref doesn't work across threads unless you use mm:atomicArc.