2013-06-11 6 views
7

Ich habe eine Haskell-Funktion I mit genauen Zwischenergebnissen bewerten will:parBuffer Auswertung nicht geben erwartete Beschleunigung

f 0 x = 0 
f n x = let tmp = f (n-1) x in 
     tmp + (x-tmp^2)/2 

Wegen der (^ 2) die Komplexität exponentiell in n wächst. Da ich eine Handlung machen möchte und die Berechnungen für zwei verschiedene x völlig unabhängig sind, hätte ich eine fast optimale Beschleunigung von der parallelen Auswertung erwartet. Mein Code dafür:

import Data.Ratio 
import Control.Parallel.Strategies 

f 0 x = 0 
f n x = let tmp = f (n-1) x in 
     tmp + (x-tmp^2)/2 

main = do 
     it <- readLn 
     let fn = fromRational . f it 
      values = map fn [0,1%2..10] :: [Double] 
      computed = values `using` parBuffer 16 rseq 
     mapM_ (putStrLn . show) computed 

Aber zu meiner Überraschung das wirklich nicht Maßstab (auf meinem Dual-Core i3 mit HT):

$ ghc -threaded -O f.hs 
[1 of 1] Compiling Main    (f.hs, f.o) 
Linking f ... 
$ time echo 20 | (./f +RTS -N1 > /dev/null) 

real 0m4.760s 
user 0m4.736s 
sys  0m0.016s 
$ time echo 20 | (./f +RTS -N2 > /dev/null) 

real 0m4.041s 
user 0m5.416s 
sys  0m2.548s 
$ time echo 20 | (./f +RTS -N3 > /dev/null) 

real 0m4.884s 
user 0m10.936s 
sys  0m3.464s 
$ time echo 20 | (./f +RTS -N4 > /dev/null) 

real 0m5.536s 
user 0m17.028s 
sys  0m3.888s 

Was mache ich hier falsch? Es scheint, dass es ziemlich viel Zeit in Sperren (sys?) Verbringt, anstatt nützliche Arbeit zu leisten.

+0

Es scheint, Sie brauchen 'parList' dann' parBuffer' – Ankur

Antwort

6

Ich denke, da die Gesamtlaufzeit relativ klein ist, leiden Sie sehr unter anfänglicher Größenänderung des Heapspeichers während der Speicherbereinigung. Sie können versuchen, den anfänglichen Zuweisungsbereich größer zu machen, indem Sie +RTS -A100M übergeben.

+0

Danke, Beschleunigung mit Threads <= Kerne ist jetzt perfekt, und bleibt stabil für weitere Threads. – Tobias

+0

Verwenden Sie Threadscope, um zu sehen, was auf Ihren Kernen passiert. –