我有一段代碼,使用sequence
從一個概率分佈重複抽樣。道德上,它是這樣的:分析一個Haskell程序
sampleMean :: MonadRandom m => Int -> m Float -> m Float
sampleMean n dist = do
xs <- sequence (replicate n dist)
return (sum xs)
除了它有點複雜。我感興趣的實際代碼是功能likelihoodWeighting
在this Github repo。
我注意到運行時間與n
呈非線性關係。特別是,一旦n
超過了某個值,它就達到了內存限制,並且運行時間爆炸了。我不確定,但我認爲這是因爲sequence
正在建立一個長長的thunk列表,直到撥打sum
纔得到評估。
一旦我獲得了大約100,000個樣本,程序就會慢慢爬行。我想優化它(我的感覺是1000萬個樣本不應該成爲問題),所以我決定對它進行描述 - 但是我對理解profiler的輸出有點麻煩。
剖析
我在與10萬個樣本運行我的功能的文件main.hs
創建的短期可執行文件。這裏是做的輸出
$ ghc -O2 -rtsopts main.hs
$ ./main +RTS -s
我注意到的第一件事 - 它分配近1.5 GB的堆,並花60%的時間在垃圾回收上。這通常表明懶惰太多了嗎?
1,377,538,232 bytes allocated in the heap
1,195,050,032 bytes copied during GC
169,411,368 bytes maximum residency (12 sample(s))
7,360,232 bytes maximum slop
423 MB total memory in use (0 MB lost due to fragmentation)
Generation 0: 2574 collections, 0 parallel, 2.40s, 2.43s elapsed
Generation 1: 12 collections, 0 parallel, 1.07s, 1.28s elapsed
INIT time 0.00s ( 0.00s elapsed)
MUT time 1.92s ( 1.94s elapsed)
GC time 3.47s ( 3.70s elapsed)
RP time 0.00s ( 0.00s elapsed)
PROF time 0.23s ( 0.23s elapsed)
EXIT time 0.00s ( 0.00s elapsed)
Total time 5.63s ( 5.87s elapsed)
%GC time 61.8% (63.1% elapsed)
Alloc rate 716,368,278 bytes per MUT second
Productivity 34.2% of total user, 32.7% of total elapsed
下面是
$ ./main +RTS -p
結果我第一次跑這一點,事實證明,有被重複調用一個函數,它原來我可以memoize的它,這加快東西增加了2倍。然而,它沒有解決空間泄漏問題。
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 1 0 0.0 0.0 100.0 100.0
main Main 434 4 0.0 0.0 100.0 100.0
likelihoodWeighting AI.Probability.Bayes 445 1 0.0 0.3 100.0 100.0
distributionLW AI.Probability.Bayes 448 1 0.0 2.6 0.0 2.6
getSampleLW AI.Probability.Bayes 446 100000 20.0 50.4 100.0 97.1
bnProb AI.Probability.Bayes 458 400000 0.0 0.0 0.0 0.0
bnCond AI.Probability.Bayes 457 400000 6.7 0.8 6.7 0.8
bnVals AI.Probability.Bayes 455 400000 20.0 6.3 26.7 7.1
bnParents AI.Probability.Bayes 456 400000 6.7 0.8 6.7 0.8
bnSubRef AI.Probability.Bayes 454 800000 13.3 13.5 13.3 13.5
weightedSample AI.Probability.Bayes 447 100000 26.7 23.9 33.3 25.3
bnProb AI.Probability.Bayes 453 100000 0.0 0.0 0.0 0.0
bnCond AI.Probability.Bayes 452 100000 0.0 0.2 0.0 0.2
bnVals AI.Probability.Bayes 450 100000 0.0 0.3 6.7 0.5
bnParents AI.Probability.Bayes 451 100000 6.7 0.2 6.7 0.2
bnSubRef AI.Probability.Bayes 449 200000 0.0 0.7 0.0 0.7
這是一個堆配置文件。我不知道爲什麼它聲稱運行時間是1.8秒 - 這個運行大約需要6秒。
誰能幫我解釋Profiler的輸出 - 即以標識瓶頸,並提供如何加快速度的建議?
嘗試使用'replicateM n'而不是'序列。replicate n' – dflemstr 2012-07-21 18:10:37
運行時間沒有變化 - 可能並不奇怪,因爲'replicateM n' [定義爲](http://www.haskell.org/ghc/docs/latest/html/libraries/base/src /Control-Monad.html#replicateM)'序列。複製n'。 – 2012-07-21 18:15:31
'length xs'總是'n',不是嗎?所以用'n'替換'(length xs)',然後'xs'不必在任何時候完全駐留在內存中。 – dave4420 2012-07-21 18:29:28