2011-03-15 17 views
21

Haskell'de basit bir bellek içi db işlevi gören bir sunucu işlemim var. İstemci işlemleri bağlanabilir, ardından veri ekleyebilir ve alabilir. Servis beklediğimden daha fazla bellek kullanıyor ve ben neden işe yaramaya çalışıyorum.ghc yığın profilerının çıktısını nasıl yorumlamalıyım?

Sahip olduğum en temel ölçü linux "top". İşlemi başlattığımda ~ 27MB'lık bir "VIRT" görüntü boyutu görüyorum. 60.000 veri öğesi eklemek için bir istemci çalıştırdıktan sonra ~ 124MB boyutunda bir görüntü boyutu görüyorum. GC istatistiklerini (+ RTS -S) yakalamak için işlemi çalıştırılıyor

, ben

Alloc Copied  Live GC GC  TOT  TOT Page Flts 
bytes  bytes  bytes user elap user elap 
28296  8388  9172 0.00 0.00 0.00 0.32 0 0 (Gen: 1) 

ve canlı bayt

... 
    532940  14964 63672180 0.00 0.00 23.50 31.95 0 0 (Gen: 0) 
    532316  7704 63668672 0.00 0.00 23.50 31.95 0 0 (Gen: 0) 
    530512  9648 63677028 0.00 0.00 23.50 31.95 0 0 (Gen: 0) 
    531936  10796 63686488 0.00 0.00 23.51 31.96 0 0 (Gen: 0) 
    423260 10047016 63680532 0.03 0.03 23.53 31.99 0 0 (Gen: 1) 
    531864  6996 63693396 0.00 0.00 23.55 32.01 0 0 (Gen: 0) 
    531852  9160 63703536 0.00 0.00 23.55 32.01 0 0 (Gen: 0) 
    531888  9572 63711876 0.00 0.00 23.55 32.01 0 0 (Gen: 0) 
    531928  9716 63720128 0.00 0.00 23.55 32.01 0 0 (Gen: 0) 
    531856  9640 63728052 0.00 0.00 23.55 32.02 0 0 (Gen: 0) 
    529632  9280 63735824 0.00 0.00 23.56 32.02 0 0 (Gen: 0) 
    527948  8304 63742524 0.00 0.00 23.56 32.02 0 0 (Gen: 0) 
    528248  7152 63749180 0.00 0.00 23.56 32.02 0 0 (Gen: 0) 
    528240  6384 63756176 0.00 0.00 23.56 32.02 0 0 (Gen: 0) 
    341100 10050336 63731152 0.03 0.03 23.58 32.35 0 0 (Gen: 1) 
    5080 10049728 63705868 0.03 0.03 23.61 32.70 0 0 (Gen: 1) 

Bu kadar sorunsuz büyüdüğünü görmek 60k öğe ekleme başlangıçta bkz bana yığının ~ 63MB canlı verilere sahip olduğunu söylüyor. Bu kuyu

Yani bu 63MB uyduruyor ne işe yığın profilleyici teşebbüs vb yığın alanı, kod alanı, GC yükü eklemek zaman, üstten sayılarla tutarlı olabilir. Sonuçlar kafa karıştırıcı. "-h + RTS" ile Koşu ve oluşturulan hp dosyasına bakan, son ve en büyük anlık vardır:

containers-0.3.0.0:Data.Map.Bin 1820400 
bytestring-0.9.1.7:Data.ByteString.Internal.PS 1336160 
main:KV.Store.Memory.KeyTree 831972 
main:KV.Types.KF_1 750328 
base:GHC.ForeignPtr.PlainPtr 534464 
base:Data.Maybe.Just 494832 
THUNK 587140 

anlık diğer sayıların tamamı bundan daha küçüktür. GC istatistik gösterildiği gibi

enter image description here

neden bu canlı bayt niteliğinde olan grafik çıkışı yansıtılan ~ 6MB olarak yüksek bellek kullanımı, bu verir kadar ekleme? Veri yapılarımın 63MB'yi nasıl gerektirdiğini görmek serttir ve profiler değiller. Hafıza nereye gidiyor?

Bu konuyla ilgili ipuçları veya işaretçiler için teşekkür ederiz.

Tim

+2

Dahil ettiğiniz imgur.com resim bağlantısı bozuk görünüyor. – Heatsink

+0

Araç çubuğunda StackOverflow'un "image" bağlantısı üzerinden bir görüntü eklerseniz (veya Ctrl-G yazın), kırılma olasılığı daha düşüktür. – ShreevatsaR

cevap

1

Sen mesela, ne olup bittiğini grafik bir görünümünü elde etmek hp2ps, kullanmalıdır. Ham hp dosyasına bakmak zordur.

+2

Teşekkürler - hp2ps kullandım. Yeni bir yığın taşması kullanıcısı olarak, sonuçta ortaya çıkan görüntüyü yapıştırma iznim olmadı :-(. Ancak hp dosyasından yapıştırılan satırlar, hp2s tarafından gösterilen grafik görünümü yansıtır. – timbod

+0

@timbod: Artık, görüntü, muhtemelen yararlı olacaktır –

1

Varsayılan olarak profildeki her şey dahil değildir, örneğin iş parçacığı ve yığınlar. +RTS -xT ile deneyin.

+0

Ben + RTS -h -S -xt ile denedim.Bu hala profilde gösterildiği gibi tepe veri karşısında canlı bayt sayısı (63MB) önemli ölçüde farklı sonuçlar verir. (Yaklaşık 6MB) Bu nedenle hala belleğin nasıl kullanıldığıyla ilgili bir kayıp yaşıyorum. – timbod

3

Bir teorim var. Benim teorim senin programın ByteStrings gibi bir çok şey kullanıyor. Benim teorim, ByteStrings'un ana içeriğinin malloc olduğundan, profil oluştururken görüntülenmemeleridir. Böylelikle, yığın grafiğinizde görünecek şekilde yığınınızın en büyük içeriği olmadan yığıntan çıkabilirsiniz. ByteStrings alt dizelerini yakaladığınızda, daha da kötüsü, varsayılan olarak işaretçiyi özgün olarak ayrılmış bellek bloğuna saklar. Bu nedenle, yalnızca ByteString numaralı küçük bir parçayı depolamaya çalışıyor olsanız bile, orijinal olarak ayrılan tüm ByteString'u tutabilirsiniz ve bu, yığın profilinizde görünmez.

Bu benim kuramım zaten. GHC'nin yığın profilerinin nasıl çalıştığı konusunda veya gerçekte ne olduğunu bilmek için ByteStrings'un nasıl uygulandığı konusunda yeterli gerçekleri bilmiyorum.Belki bir başkası kurabilir ve teorimi onaylayabilir veya tartışabilir.

Edit2: tibbe, ByteString s tarafından kullanılan arabelleğin sabitlendiğini not eder. Bu nedenle, çok sayıda küçük Bytestring s tahsis ediyorsanız/ayırıyorsanız, yığınınızı parçalara ayırarak, kullanılabilir bölümün yarısının kaldırılmamış olduğu anlamına gelir.

Düzenleme: JaffaCake bazen yığın profilleyicisinin ByteStrings tarafından ayrılan belleği göstermeyeceğini söyler.