2016-03-28 37 views
13

Próbowałem uruchomiony pierwszy przykład tutaj: http://chimera.labs.oreilly.com/books/1230000000929/ch03.htmlCzęste GC zapobiegania iskry z pracujących równolegle

Kod: https://github.com/simonmar/parconc-examples/blob/master/strat.hs

import Control.Parallel 
import Control.Parallel.Strategies (rpar, Strategy, using) 
import Text.Printf 
import System.Environment 

-- <<fib 
fib :: Integer -> Integer 
fib 0 = 1 
fib 1 = 1 
fib n = fib (n-1) + fib (n-2) 
-- >> 

main = print pair 
where 
    pair = 
-- <<pair 
    (fib 35, fib 36) `using` parPair 
-- >> 

-- <<parPair 
parPair :: Strategy (a,b) 
parPair (a,b) = do 
    a' <- rpar a 
    b' <- rpar b 
    return (a',b') 
-- >> 

I został zbudowany przy użyciu GHC 7.10.2 (na OSX, z wielordzeniowych maszyna) za pomocą następującego polecenia:

ghc -O2 strat.hs -threaded -rtsopts -eventlog 

i uruchomić za pomocą:

./strat +RTS -N2 -l -s 

Spodziewałem się 2 fibs obliczenia mają być prowadzone równolegle (poprzednie przykłady rozdział działało zgodnie z oczekiwaniami, więc nie ma problemów przy instalacji), a ja nie otrzymuję żadnych przyspieszenie w ogóle, jak widać tutaj:

% ./strat +RTS -N2 -l -s 
(14930352,24157817) 
    3,127,178,800 bytes allocated in the heap 
     6,323,360 bytes copied during GC 
      70,000 bytes maximum residency (2 sample(s)) 
      31,576 bytes maximum slop 
       2 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  5963 colls, 5963 par 0.179s 0.074s  0.0000s 0.0001s 
    Gen 1   2 colls,  1 par 0.000s 0.000s  0.0001s 0.0001s 

    Parallel GC work balance: 2.34% (serial 0%, perfect 100%) 

    TASKS: 6 (1 bound, 5 peak workers (5 total), using -N2) 

    SPARKS: 2 (0 converted, 0 overflowed, 0 dud, 1 GC'd, 1 fizzled) 

    INIT time 0.000s ( 0.001s elapsed) 
    MUT  time 1.809s ( 1.870s elapsed) 
    GC  time 0.180s ( 0.074s elapsed) 
    EXIT time 0.000s ( 0.000s elapsed) 
    Total time 1.991s ( 1.945s elapsed) 

    Alloc rate 1,728,514,772 bytes per MUT second 

    Productivity 91.0% of total user, 93.1% of total elapsed 

gc_alloc_block_sync: 238 
whitehole_spin: 0 
gen[0].sync: 0 
gen[1].sync: 0 

-N1 otrzymuje podobne wyniki (pomijane).

# kolekcje GC wydawały się podejrzane, jak wskazali inni w # początkujących haskell, więc próbowałem dodać -A16M podczas uruchamiania. Wyniki wyglądały znacznie bardziej zgodnie z oczekiwaniami:

% ./strat +RTS -N2 -l -s -A16M 
(14930352,24157817) 
    3,127,179,920 bytes allocated in the heap 
     260,960 bytes copied during GC 
      69,984 bytes maximum residency (2 sample(s)) 
      28,320 bytes maximum slop 
       33 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  115 colls, 115 par 0.105s 0.002s  0.0000s 0.0003s 
    Gen 1   2 colls,  1 par 0.000s 0.000s  0.0002s 0.0002s 

    Parallel GC work balance: 71.25% (serial 0%, perfect 100%) 

    TASKS: 6 (1 bound, 5 peak workers (5 total), using -N2) 

    SPARKS: 2 (1 converted, 0 overflowed, 0 dud, 0 GC'd, 1 fizzled) 

    INIT time 0.001s ( 0.001s elapsed) 
    MUT  time 1.579s ( 1.087s elapsed) 
    GC  time 0.106s ( 0.002s elapsed) 
    EXIT time 0.000s ( 0.000s elapsed) 
    Total time 1.686s ( 1.091s elapsed) 

    Alloc rate 1,980,993,138 bytes per MUT second 

    Productivity 93.7% of total user, 144.8% of total elapsed 

gc_alloc_block_sync: 27 
whitehole_spin: 0 
gen[0].sync: 0 
gen[1].sync: 0 

Pytanie brzmi: dlaczego to zachowanie? Nawet przy częstym GC wciąż intuicyjnie oczekuję, że 2 iskry będą działały równolegle w pozostałych 90% czasu pracy.

+2

Jeśli nie otrzymasz satysfakcjonującej odpowiedzi, rozważ otwarcie biletu na ghc trac. Zwłaszcza biorąc pod uwagę przykład z własnej książki Simona, jestem pewien, że byliby zainteresowani wiedzą o tym, jeśli jest to regresja. – jberryman

Odpowiedz

2

Tak, to w rzeczywistości błąd w GHC 8.0.1 i wcześniejszych wersjach (pracuję nad naprawieniem wersji 8.0.2). Problem polega na tym, że wyrażenia fib 35 i fib 36 są stałe, więc GHC podnosi je do najwyższego poziomu jako CAF, a RTS błędnie założył, że CAF były nieosiągalne, a zatem śmieci zbierały iskry.

można obejść poprzez wyrażenia nie stała przez przekazanie parametrów w wierszu poleceń:

main = do 
    [a,b] <- map read <$> getArgs 
    let pair = (fib a, fib b) `using` parPair 
    print pair 

a następnie uruchomić program z ./strat 35 36.

+1

Czy mógłbyś to trochę rozwinąć? Mam podobny problem z moim algorytmem 'mergeSort' i nie mogę wymyślić, jak to zrobić. Powinienem też wspomnieć, że pomimo tego, że 3 iskry wypalają się z 4, nadal widzę równoległość, a kod działa również znacznie szybciej. Jakieś wskazówki, dlaczego? – Anabra