2016-03-28 16 views
13

ho provato a fare funzionare il primo esempio qui: http://chimera.labs.oreilly.com/books/1230000000929/ch03.htmlGC frequente prevenire scintille l'esecuzione in parallelo

Codice: 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') 
-- >> 

Ho costruito utilizzando GHC 7.10.2 (su OSX, con un multicore della macchina) utilizzando il seguente comando:

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

ed eseguire utilizzando:

./strat +RTS -N2 -l -s 

Mi aspettavo il 2 fibs calcoli da eseguire in parallelo (esempi precedenti capitoli ha funzionato come previsto, in modo che nessun problemi di installazione), e non si sentiva alcun aumento di velocità a tutti, come si vede qui:

% ./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 ottiene risultati simili (omissis).

Il numero di raccolte GC sembrava sospetto, come indicato da altri in # haskell-principianti, quindi ho provato ad aggiungere -A16M durante l'esecuzione. I risultati sembravano molto più in linea con le aspettative:

% ./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 

La domanda è: perché questo è il comportamento? Anche con i comuni GC, mi aspetto ancora intuitivamente che le 2 scintille funzionino in parallelo nell'altro 90% del tempo di esecuzione.

+2

Se non si ottiene una risposta soddisfacente, prendere in considerazione l'apertura di un biglietto sul ghc trac. Soprattutto considerando che l'esempio è tratto dal libro di Simon, sono sicuro che sarebbe interessato a saperlo se si tratta di una regressione. – jberryman

risposta

2

Sì, questo è in realtà un bug in GHC 8.0.1 e precedenti (sto lavorando per risolverlo per 8.0.2). Il problema è che le espressioni fib 35 e fib 36 sono costanti e quindi GHC le alza al livello più alto come CAF e l'RTS presupponeva erroneamente che i CAF fossero irraggiungibili e quindi raccoglievano le scintille.

È possibile lavorare intorno ad esso, rendendo le espressioni non costante passando i parametri sulla riga di comando:

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

e quindi eseguire il programma con ./strat 35 36.

+1

Potresti approfondire un po ', per favore? Ho un problema simile con il mio algoritmo 'mergeSort', e non riesco a capire come farlo funzionare. Inoltre dovrei menzionare che nonostante il fatto che 3 scintille si trasformino in 4, continuo a vedere la parallelizzazione, e il codice gira anche molto più velocemente. Qualche indizio perché? – Anabra