Ich habe ein Programm, das ich parallelisieren möchte (vollständige einfügen mit ausführbaren Code here).Parallel Haskell - GHC GC'ing Funken
Ich habe profiliert und festgestellt, dass die meiste Zeit in findNearest
verbracht wird, die im Wesentlichen eine einfache foldr
über eine große Data.Map
ist.
findNearest :: RGB -> M.Map k RGB -> (k, Word32)
findNearest rgb m0 =
M.foldrWithKey' minDistance (k0, distance rgb r0) m0
where (k0, r0) = M.findMin m0
minDistance k r [email protected](_, d1) =
-- Euclidean distance in RGB-space
let d0 = distance rgb r
in if d0 < d1 then (k, d0) else x
parFindNearest
soll Map
findNearest
parallel über Teilbäume des größeren auszuführen.
Leider GHC GC meine meisten Funken, bevor sie in nützliche Parallelität umgewandelt werden.
Hier ist das Ergebnis mit ghc -O2 -threaded
von Kompilieren und Ausführen mit +RTS -s -N2
839,892,616 bytes allocated in the heap
123,999,464 bytes copied during GC
5,320,184 bytes maximum residency (19 sample(s))
3,214,200 bytes maximum slop
16 MB total memory in use (0 MB lost due to fragmentation)
Tot time (elapsed) Avg pause Max pause
Gen 0 1550 colls, 1550 par 0.23s 0.11s 0.0001s 0.0004s
Gen 1 19 colls, 18 par 0.11s 0.06s 0.0030s 0.0052s
Parallel GC work balance: 16.48% (serial 0%, perfect 100%)
TASKS: 6 (1 bound, 5 peak workers (5 total), using -N2)
SPARKS: 215623 (1318 converted, 0 overflowed, 0 dud, 198111 GC'd, 16194 fizzled)
INIT time 0.00s ( 0.00s elapsed)
MUT time 3.72s ( 3.66s elapsed)
GC time 0.34s ( 0.17s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 4.07s ( 3.84s elapsed)
Alloc rate 225,726,318 bytes per MUT second
Productivity 91.6% of total user, 97.1% of total elapsed
gc_alloc_block_sync: 9862
whitehole_spin: 0
gen[0].sync: 0
gen[1].sync: 2103
Wie Sie sehen können, ist die Mehrheit der Funken GC'd oder im Sande verlaufen, bevor umgewandelt wird. Ich habe versucht, mit unterschiedlicher Strenge zu experimentieren, findNearest
einen kundenspezifischen strikten Paardatentyp anstelle eines Tupels zurückzugeben, oder rdeepseq von Control.Parallel.Strategies
verwendend, aber meine Funken werden noch GC'd.
würde Ich mag
wissen- warum werden meine Funken GC'd vor umgewandelt werden?
- Wie kann ich mein Programm ändern, um die Parallelität zu nutzen?
http://www.haskell.org/haskellwiki/ThreadScope kann helfen. –
1. 'splitRoot' generiert normalerweise eine Liste mit drei Elementen, dem linken Baum, dem Stamm und dem rechten Baum. Sie verwenden also 'parMap' in einer _very_ kleinen Liste. Die Elemente selbst sind ziemlich groß, aber andererseits ist 'findNearest' nicht selbst parallel. 2. Ein entflammter Ausdruck wird GC'd, wenn er nicht verwendet wird. Vielleicht verwendest du das Ergebnis doch nicht? – Zeta
@Zeta: Ja, die Größe der Liste ist klein (nur 3 Elemente), aber die Größe der 'Map' ist groß (65k ~ 250k Elemente), so dass sie sogar in zwei teilbare Teilbäume aufgeteilt werden kann. – cdk