Bir ışın izleyiciyi paralelleştirmeye çalışıyorum. Bu, çok uzun bir küçük hesaplama listesine sahip olduğum anlamına geliyor. Vanilya programı belirli bir sahnede 67,98 saniye ve 13 MB toplam bellek kullanımı ve% 99,2 verimlilikle çalışır.
İlk denememde parBuffer
arabellek boyutu 50 olan paralel stratejiyi kullandım. parBuffer
Listede yalnızca kıvılcımlar tüketildiği kadar hızlı yürüdüğü ve listenin omurgasını parList
çok fazla bellek kullanan gibi zorlamadığı için seçtim. liste çok uzun olduğu için. İle -N2
100,46 saniye ve 14 MB toplam bellek kullanımı ve% 97,8 verimlilikle çalıştı. Kıvılcım bilgileri:SPARKS: 480000 (476469 converted, 0 overflowed, 0 dud, 161 GC'd, 3370 fizzled)
Kabarık kıvılcımların büyük oranı, kıvılcımların tanecikliğinin çok küçük olduğunu gösteriyor, bu yüzden daha parListChunk
sonra listeyi parçalara bölen ve her parça için bir kıvılcım oluşturan stratejiyi kullanmayı denedim . Bir yığın boyutu ile en iyi sonuçları aldım 0.25 * imageWidth
. Program 93,43 saniye ve 236 MB toplam bellek kullanımı ve% 97,3 verimlilikle çalıştı. Kıvılcım bilgiler şunlardır: SPARKS: 2400 (2400 converted, 0 overflowed, 0 dud, 0 GC'd, 0 fizzled)
. Çok daha fazla hafıza kullanımının parListChunk
listenin omurgasını zorladığına inanıyorum .
Sonra, listeyi tembel bir şekilde parçalara ayıran ve ardından parçalara parBuffer
aktarıp sonuçları birleştiren kendi stratejimi yazmaya çalıştım .
concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map colorPixel pixels))
Bu, 95,99 saniye ve 22 MB toplam bellek kullanımı ve% 98,8 üretkenlikle çalıştı. Bu, tüm kıvılcımların dönüştürüldüğü ve bellek kullanımının çok daha düşük olduğu, ancak hızın iyileştirilmediği anlamında başarılı oldu. İşte olay günlüğü profilinin bir kısmının görüntüsü.
Gördüğünüz gibi yığın taşmaları nedeniyle iş parçacıkları durduruluyor. +RTS -M1G
Varsayılan yığın boyutunu 1 Gb'ye kadar artıran eklemeyi denedim . Sonuçlar değişmedi. Haskell ana iş parçacığının, yığın taşması durumunda yığından bellek kullanacağını okudum, bu yüzden varsayılan yığın boyutunu da artırmayı denedim, +RTS -M1G -K1G
ancak bunun da bir etkisi olmadı.
Deneyebileceğim başka bir şey var mı? Gerekirse bellek kullanımı veya olay günlüğü için daha ayrıntılı profil oluşturma bilgileri gönderebilirim, hepsini dahil etmedim çünkü çok fazla bilgi var ve hepsinin dahil edilmesi gerektiğini düşünmedim.
DÜZENLEME: Haskell RTS çok çekirdekli desteği hakkında okuyordum ve her çekirdek için bir HEC (Haskell Yürütme Bağlamı) olduğundan bahsediyor. Her HEC, diğer şeylerin yanı sıra, bir Tahsis Alanını (tek bir paylaşılan yığının parçası olan) içerir. Herhangi bir HEC'nin Tahsis Alanı tükendiğinde, bir çöp toplama işlemi gerçekleştirilmelidir. Görünüşe göre onu kontrol etmek için bir RTS seçeneği , -A. -A32M'yi denedim ama fark görmedim.
DÜZENLEME2: İşte bu soruya adanmış bir github deposuna bağlantı . Profil oluşturma sonuçlarını profil oluşturma klasörüne ekledim.
DÜZENLEME3: İşte ilgili kod biti:
render :: [([(Float,Float)],[(Float,Float)])] -> World -> [Color]
render grids world = cs where
ps = [ (i,j) | j <- reverse [0..wImgHt world - 1] , i <- [0..wImgWd world - 1] ]
cs = map (colorPixel world) (zip ps grids)
--cs = withStrategy (parListChunk (round (wImgWd world)) rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = withStrategy (parBuffer 16 rdeepseq) (map (colorPixel world) (zip ps grids))
--cs = concat $ withStrategy (parBuffer 40 rdeepseq) (chunksOf 100 (map (colorPixel world) (zip ps grids)))
Izgaraları, önceden hesaplanabilir ve colorPixel.The türü tarafından kullanılan rasgele mantarlar olan colorPixel
geçerli:
colorPixel :: World -> ((Float,Float),([(Float,Float)],[(Float,Float)])) -> Color
Strategy
. Daha iyi bir kelime seçmeliydin. Ayrıca, yığın taşması sorunu parListChunk
ve ile birlikte ortaya çıkar parBuffer
.
concat $ withStrategy …
?6008010
Düzenlemenize en yakın işlem olan bu davranışı içinde yeniden oluşturamıyorum.