簡體   English   中英

可變,(可能是並行)Haskell代碼和性能調優

[英]Mutable, (possibly parallel) Haskell code and performance tuning

我現在已經實現了另一個 SHA3​​候選者,即Grøstl。 這仍然在進行中(非常如此),但目前224位版本通過了所有KAT。 所以現在我想知道性能(再次: - >)。 這次的不同之處在於,我選擇更接近地鏡像(優化的)C實現 ,即我創建了一個從C到Haskell的端口。 優化的C版本使用表查找來實現該算法。 此外,代碼主要基於更新包含64位字的數組。 因此,我選擇在Haskell中使用可變的無盒載體。

我的Grøstl代碼可以在這里找到: https//github.com/hakoja/SHA3/blob/master/Data/Digest/GroestlMutable.hs

該算法的簡短描述:它是一個Merkle-Damgård構造,只要有512位的消息塊,就迭代一個壓縮函數(在我的代碼中為f512M )。 壓縮函數非常簡單:它只運行兩個不同的獨立512位排列PQ (我的代碼中的permPpermQ )並組合它們的輸出。 它的這些排列是由查找表實現的。

Q1)困擾我的第一件事是使用可變向量使我的代碼看起來非常難看。 這是我第一次在Haskell中編寫任何主要的可變代碼,所以我真的不知道如何改進它。 關於如何更好地構建monadic代碼的任何提示都將受到歡迎。

Q2)第二是表現。 實際上它並不太糟糕,因為目前Haskell代碼只慢了3倍。 使用GHC-7.2.1並編譯如下:

ghc -O2 -Odph -fllvm -optlo-O3 -optlo-loop-reduce -optlo-loop-deletion

Haskell代碼使用60秒。 輸入約為1GB,而C版本使用21-22s。 但有一些我覺得奇怪的事情:

(1)如果我嘗試內聯rnd512QM ,代碼需要4倍,但如果我內聯rnd512PM沒有任何反應! 為什么會這樣? 這兩個功能幾乎相同!

(2)這可能更難。 我一直在嘗試並行執行兩個排列。 但目前無濟於事。 這是我嘗試過的一個例子:

f512 h m = V.force outP `par` (V.force outQ `pseq` (V.zipWith3 xor3 h outP outQ))
   where xor3 x1 x2 x3 = x1 `xor` x2 `xor` x3
         inP = V.zipWith xor h m
         outP = permP inP
         outQ = permQ m

在檢查運行時統計信息並使用ThreadScope時,我注意到創建了正確數量的SPARKS,但幾乎沒有實際轉換為有用的並行工作。 因此,我在加速方面一無所獲。 我的問題變成了:

  1. P和Q函數是否太小而運行時無法並行運行?
  2. 如果沒有,我使用parpseq (可能還有Vector.Unboxed.force)是錯誤的嗎?
  3. 轉換到策略會獲得任何收益嗎? 那我該怎么做呢?

非常感謝您的參與。

編輯:

很抱歉沒有提供任何真正的基准測試。 回購中的測試代碼僅供我自己使用。 對於那些想要測試代碼的人,你需要編譯main.hs ,然后運行它:

./main“algorithm”“testvariant”“字節對齊”

例如:

./main groestl short224錯誤

要么

./main groestl e False

e代表“極端”。這是NIST KATS提供的非常長的消息)。

我檢查了回購,但沒有簡單的基准來運行和玩,所以我的想法只是從眼睛的代碼。 編號與您的問題無關。

1)我很確定force沒有做你想要的 - 它實際上強制了底層矢量的副本。

2)我認為使用unsafeThaw和unsafeFreeze有點奇怪。 我只是將f512M放入ST monad並完成它。 然后運行它是這樣的:

otherwise = \msg -> truncate G224 . outputTransformation . runST $ foldM f512M h0_224 (parseMessage dataBitLen 512 msg)

3) V.foldM'有點傻 - 你可以在列表上使用正常(嚴格)foldM - 在第二個參數中折疊向量似乎不買任何東西。

4)我對columnM的劉海和unsafeReads表示懷疑。

也...

a)我懷疑xoring未裝箱的矢量可能比zipWith更低的級別zipWith ,利用Data.Vector內部。

b)但是,最好不要這樣做,因為它可能會干擾矢量融合。

c)在檢查時, extractByte看起來效率不高? 而不是使用fromIntegral來截斷,可以使用modquot然后使用單個fromIntegral直接轉到Int。

  1. 確保使用-threaded -rtsopts進行編譯並使用+RTS -N2執行。 沒有它,您將不會有多個OS線程來執行計算。

  2. 嘗試激發其他地方引用的計算,否則可能會收集它們:

_

f512 h m = outP `par` (outQ `pseq` (V.zipWith3 xor3 h outP outQ))
   where xor3 x1 x2 x3 = x1 `xor` x2 `xor` x3
         inP = V.zipWith xor h m
         outP = V.force $ permP inP
         outQ = V.force $ permQ m

_

3)如果你把事情parseBlock了,那么parseBlock接受嚴格的字節parseBlock (或者在需要的時候使用chunk和pack lazy)然后你可以使用Data.Vector.Storable並且可能避免一些復制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM