2014-07-03 30 views
7

我正在嘗試將並行性添加到將.bmp轉換爲灰度.bmp的程序。並行代碼的性能通常會降低2-4倍。我正在調整parBuffer/chunking大小,但似乎無法推理它。尋找指導。惰性IO +並行性:將圖像轉換爲灰度

這裏使用的整個源文件:http://lpaste.net/106832

我們使用Codec.BMPtype RGBA = (Word8, Word8, Word8, Word8)代表像素的流中讀取。要轉換爲灰度,只需在所有像素上映射「亮度」變換即可。

串行實現是字面上:

toGray :: [RGBA] -> [RGBA] 
toGray x = map luma x 

的測試輸入的.bmp是5184 X 3456(71.7 MB)。

串行實現以〜10s,〜550ns /像素運行。 Threadscope看上去幹淨:

serial

這是爲什麼這麼快?我想它有一些懶惰的ByteString(即使Codec.BMP使用嚴格的ByteString - 是否存在隱式轉換?)和融合。

增加並行

第一次嘗試增加並行是通過parList。好傢伙。該程序使用〜4-5GB的內存和系統開始交換。

然後,我閱讀了Simon Marlow的O'Reilly書中的「用parBuffer並行化懶惰流」部分,並嘗試使用大尺寸的parBuffer。這仍然沒有產生理想的表現。火花的大小非常小。

然後我試圖通過分塊懶列表,然後用parBuffer堅持爲並行,以增加火花大小:

toGrayPar :: [RGBA] -> [RGBA] 
toGrayPar x = concat $ (withStrategy (parBuffer 500 rpar) . map (map luma)) 
         (chunk 8000 x) 

chunk :: Int -> [a] -> [[a]] 
chunk n [] = [] 
chunk n xs = as : chunk n bs where 
    (as,bs) = splitAt (fromIntegral n) xs 

但是,這仍然無法取得令人滿意的表現:

18,934,235,760 bytes allocated in the heap 
    15,274,565,976 bytes copied during GC 
    639,588,840 bytes maximum residency (27 sample(s)) 
    238,163,792 bytes maximum slop 
      1910 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  35277 colls, 35277 par 19.62s 14.75s  0.0004s 0.0234s 
    Gen 1  27 colls, 26 par 13.47s 7.40s  0.2741s 0.5764s 

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

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

    SPARKS: 4480 (2240 converted, 0 overflowed, 0 dud, 2 GC'd, 2238 fizzled) 

    INIT time 0.00s ( 0.01s elapsed) 
    MUT  time 14.31s (14.75s elapsed) 
    GC  time 33.09s (22.15s elapsed) 
    EXIT time 0.01s ( 0.12s elapsed) 
    Total time 47.41s (37.02s elapsed) 

    Alloc rate 1,323,504,434 bytes per MUT second 

    Productivity 30.2% of total user, 38.7% of total elapsed 

gc_alloc_block_sync: 7433188 
whitehole_spin: 0 
gen[0].sync: 0 
gen[1].sync: 1017408 

par1

我該如何更好地推斷這裏發生的事情?

+0

您是否確定了合理的基線時間?只需計算'[RGBA]'的長度需要多長時間?由於您的其他評論表明這個值正在使用惰性IO進行流式處理,所以IO時間總是會主宰任何處理您的操作,並行與否。那麼多少運行時間只是IO和解析? – Carl

+0

我可以嘗試查看IO和Codec.BMP解析需要多長時間。我正在使用的基線是需要約10秒的連續實施。我認爲這足以用來比較並行實施所需的30-40s。 – brooksbp

回答

0

你有一個大的RGBA像素列表。你爲什麼不用parListChunk合理的塊大小?

+0

這似乎更多的是評論而不是答案,它不能解決OP的問題,而只是提出一些建議。 – bheklilr

+0

parListChunk強制佔用大量內存的[5184 x 3456]圖像的脊椎。我試圖避免這一點,仍然使用懶惰的IO。 – brooksbp