2012-05-15 18 views
5

मुझे State मोनैड में चल रहे सिमुलेशन में स्मृति उपयोग और जीसी समय को कम करने के तरीके को समझने में कुछ परेशानी हो रही है। वर्तमान में मुझे स्टैक स्पेस ओवरफ़्लो से बचने के लिए संकलित कोड +RTS -K100M के साथ चलाने के लिए है, और जीसी आंकड़े बहुत भयानक हैं (नीचे देखें)।सिमुलेशन में मेमोरी आवंटन/जीसी को नियंत्रित करना?

यहां कोड के प्रासंगिक स्निपेट हैं। पूरा, काम कर रहा है (जीएचसी 7.4.1) कोड http://hpaste.org/68527 पर पाया जा सकता है।

-- Lone algebraic data type holding the simulation configuration. 
data SimConfig = SimConfig { 
     numDimensions :: !Int   -- strict 
    , numWalkers :: !Int   -- strict 
    , simArray  :: IntMap [Double] -- strict spine 
    , logP   :: Seq Double  -- strict spine 
    , logL   :: Seq Double  -- strict spine 
    , pairStream :: [(Int, Int)] -- lazy (infinite) list of random vals 
    , doubleStream :: [Double]  -- lazy (infinite) list of random vals 
    } deriving Show 

-- The transition kernel for the simulation. 
simKernel :: State SimConfig() 
simKernel = do 
    config <- get 
    let arr = simArray  config 
    let n  = numWalkers config 
    let d  = numDimensions config 
    let rstm0 = pairStream config 
    let rstm1 = doubleStream config 
    let lp = logP   config 
    let ll = logL   config 

    let (a, b) = head rstm0       -- uses random stream  
    let z0 = head . map affineTransform $ take 1 rstm1 -- uses random stream 
      where affineTransform a = 0.5 * (a + 1)^2 


    let proposal = zipWith (+) r1 r2 
      where r1 = map (*z0)  $ fromJust (IntMap.lookup a arr) 
        r2 = map (*(1-z0)) $ fromJust (IntMap.lookup b arr) 

    let logA = if val > 0 then 0 else val 
      where val = logP_proposal + logL_proposal - (lp `index` (a - 1)) - (ll `index` (a - 1)) + ((fromIntegral n - 1) * log z0) 
        logP_proposal = logPrior proposal 
        logL_proposal = logLikelihood proposal 

    let cVal  = (rstm1 !! 1) <= exp logA   -- uses random stream 

    let newConfig = SimConfig { simArray = if cVal 
              then IntMap.update (\_ -> Just proposal) a arr 
              else arr 
           , numWalkers = n 
           , numDimensions = d 
           , pairStream = drop 1 rstm0 
           , doubleStream = drop 2 rstm1 
           , logP = if cVal 
             then Seq.update (a - 1) (logPrior proposal) lp 
             else lp 
           , logL = if cVal 
             then Seq.update (a - 1) (logLikelihood proposal) ll 
             else ll 
           } 

    put newConfig 

main = do 
    -- (some stuff omitted) 
    let sim = logL $ (`execState` initConfig) . replicateM 100000 $ simKernel 
    print sim 

ढेर के संदर्भ में, एक प्रोफ़ाइल संकेत है कि System.Random काम करता है, (,) के अलावा, स्मृति अपराधियों रहे हैं लगता है। मैं सीधे एक छवि शामिल नहीं कर सकता, लेकिन आप यहां एक हीप प्रोफाइल देख सकते हैं: http://i.imgur.com/5LKxX.png

मुझे नहीं पता कि उन चीजों की उपस्थिति को और कैसे कम किया जाए। यादृच्छिक विविधता State मोनैड के बाहर उत्पन्न होती है (प्रत्येक पुनरावृत्ति पर जेनरेटर को विभाजित करने से बचने के लिए), और मेरा मानना ​​है कि के अंदर केवल के अंदर एक ही उदाहरण आलसी सूची (pairStream) से एक जोड़ी को सिमुलेशन कॉन्फ़िगरेशन में शामिल करते समय उत्पन्न होता है।

जीसी सहित आँकड़े,, इस प्रकार हैं:

1,220,911,360 bytes allocated in the heap 
    787,192,920 bytes copied during GC 
    186,821,752 bytes maximum residency (10 sample(s)) 
     1,030,400 bytes maximum slop 
      449 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  2159 colls,  0 par 0.80s 0.81s  0.0004s 0.0283s 
    Gen 1  10 colls,  0 par 0.96s 1.09s  0.1094s 0.4354s 

    INIT time 0.00s ( 0.00s elapsed) 
    MUT  time 0.95s ( 0.97s elapsed) 
    GC  time 1.76s ( 1.91s elapsed) 
    EXIT time 0.00s ( 0.00s elapsed) 
    Total time 2.72s ( 2.88s elapsed) 

    %GC  time  64.9% (66.2% elapsed) 

    Alloc rate 1,278,074,521 bytes per MUT second 

    Productivity 35.1% of total user, 33.1% of total elapsed 

और फिर, मैं आदेश भी सिमुलेशन चलाने के लिए अधिकतम ढेर आकार तक सामने लाना है। मुझे पता है कि कहीं कहीं बड़ा थंक बिल्डिंग होना चाहिए .. लेकिन मुझे पता नहीं लगा सकता है कि कहां?

मैं इस तरह की समस्या में ढेर/ढेर आवंटन और जीसी को कैसे सुधार सकता हूं? मैं कैसे पहचान सकता हूं कि एक थंक कहां बना सकता है? क्या State मोनैड का उपयोग यहां गुमराह है?

-

अद्यतन:

मैं जब -fprof-auto साथ संकलन प्रोफाइलर के उत्पादन से अधिक देखने के लिए उपेक्षित। यहाँ है कि उत्पादन का प्रमुख होता है:

COST CENTRE      MODULE        no.  entries %time %alloc %time %alloc 

MAIN        MAIN        58   0 0.0 0.0 100.0 100.0 
main        Main        117   0 0.0 0.0 100.0 100.0 
    main.randomList     Main        147   1 62.0 55.5 62.0 55.5 
    main.arr      Main        142   1 0.0 0.0  0.0 0.0 
    streamToAssocList    Main        143   1 0.0 0.0  0.0 0.0 
    streamToAssocList.go   Main        146   5 0.0 0.0  0.0 0.0 
    main.pairList     Main        137   1 0.0 0.0  9.5 16.5 
    consPairStream     Main        138   1 0.7 0.9  9.5 16.5 
    consPairStream.ys    Main        140   1 4.3 7.8  4.3 7.8 
    consPairStream.xs    Main        139   1 4.5 7.8  4.5 7.8 
    main.initConfig     Main        122   1 0.0 0.0  0.0 0.0 
    logLikelihood     Main        163   0 0.0 0.0  0.0 0.0 
    logPrior      Main        161   5 0.0 0.0  0.0 0.0 
    main.sim      Main        118   1 1.0 2.2 28.6 28.1 
    simKernel      Main        120   0 4.8 5.1 27.6 25.8 

मुझे यकीन है कि कैसे वास्तव में इस व्याख्या करने के लिए नहीं कर रहा हूँ, लेकिन यादृच्छिक युगल के आलसी धारा, randomList, मुझे wince बना देता है। मुझे नहीं पता कि यह कैसे सुधार किया जा सकता है।

+0

मैं System.Random.MWC जनरेटर पर स्विच किया और देखा होगा प्रदर्शन में एक त्वरित बढ़ावा। मुझे अभी भी रनटाइम पर + आरटीएस-के 100 एम का उपयोग करना है, हालांकि, मुझे लगता है कि एक बड़ा हिस्सा अभी भी कहीं भी बना रहा है। कोड का एक अपडेटेड स्नैपशॉट यहां है: http://hpaste.org/68532, और एक बेहतर ढेर प्रोफ़ाइल यहां है: http://i.imgur.com/YzoNE.png। – jtobin

+0

मुझे लगता है कि आप 'ghc -O2' का भी उपयोग कर रहे हैं? –

+0

दाएं; 'ghc --make -O2 blah.hs -fllvm -funbox-hard-field -rtsopts' के साथ संकलित। – jtobin

उत्तर

3

मैंने एक कामकाजी उदाहरण के साथ hpaste अद्यतन किया है। यह अपराधियों की तरह लग रहा है:

  • तीन SimConfig क्षेत्रों में गुम कठोरता एनोटेशन: simArray, logP और logL
 
    data SimConfig = SimConfig { 
      numDimensions :: !Int   -- strict 
     , numWalkers :: !Int   -- strict 
     , simArray  :: !(IntMap [Double]) -- strict spine 
     , logP   :: !(Seq Double)  -- strict spine 
     , logL   :: !(Seq Double)  -- strict spine 
     , pairStream :: [(Int, Int)] -- lazy 
     , doubleStream :: [Double]  -- lazy 
     } deriving Show 
  • newConfig कारण State होने के simKernel पाश में मूल्यांकन नहीं किया गया आलसी। एक और विकल्प सख्त State मोनैड का उपयोग करना होगा।

    put $! newConfig 
    
  • execState ... replicateM भी Thunks बनाता है।मैं मूल रूप से एक foldl' के साथ इस जगह ली और गुना में execState ले जाया गया, लेकिन मैं replicateM_ में अदला-बदली लगता होगा पढ़ने के लिए बराबर है और आसान है:

    let sim = logL $ execState (replicateM_ epochs simKernel) initConfig 
    -- sim = logL $ foldl' (const . execState simKernel) initConfig [1..epochs] 
    

और mapM .. replicate करने के लिए कुछ कॉल replicateM साथ प्रतिस्थापित किया गया है । consPairList में विशेष रूप से उल्लेखनीय है जहां यह स्मृति उपयोग को काफी कम करता है। अभी भी सुधार के लिए जगह है लेकिन सबसे कम लटकते फल में असुरक्षित इंटरलेवस्ट शामिल है ... इसलिए मैंने रोका।

मुझे पता नहीं है, तो उत्पादन परिणाम आप क्या चाहते हैं:

 
fromList [-4.287033457733427,-1.8000404912760795,-5.581988678626085,-0.9362372340483293,-5.267791907985331] 

लेकिन यहाँ आँकड़े हैं:

 
    268,004,448 bytes allocated in the heap 
     70,753,952 bytes copied during GC 
     16,014,224 bytes maximum residency (7 sample(s)) 
     1,372,456 bytes maximum slop 
       40 MB total memory in use (0 MB lost due to fragmentation) 

            Tot time (elapsed) Avg pause Max pause 
    Gen 0  490 colls,  0 par 0.05s 0.05s  0.0001s 0.0012s 
    Gen 1   7 colls,  0 par 0.04s 0.05s  0.0076s 0.0209s 

    INIT time 0.00s ( 0.00s elapsed) 
    MUT  time 0.12s ( 0.12s elapsed) 
    GC  time 0.09s ( 0.10s elapsed) 
    EXIT time 0.00s ( 0.00s elapsed) 
    Total time 0.21s ( 0.22s elapsed) 

    %GC  time  42.2% (45.1% elapsed) 

    Alloc rate 2,241,514,569 bytes per MUT second 

    Productivity 57.8% of total user, 53.7% of total elapsed 
+0

वाह। अकेले एडीटी रिकॉर्ड प्रकारों में सख्तता एनोटेशन जोड़ना स्मृति उपयोग * कमजोर * बनाता है। मुझे लगता है कि मैंने 'सख्त-पंक्तिबद्ध' डेटा संरचना के अर्थ को गलत समझा, क्योंकि मैंने सख्तता एनोटेशन जोड़ने की भी कोशिश नहीं की थी। मुझे लगता है कि मुझे यह समझने में काफी समय लगेगा कि मुझे 'execState' को फोल्ड करना चाहिए। महान सामान, धन्यवाद। – jtobin

+1

@jtobin मूल्य की अभी भी डब्ल्यूएचएनएफ को मूल्यांकन करने की आवश्यकता है, भले ही इसकी आंतरिक कठोरता गारंटी हो। मैंने 'execlate' कॉल को' foldl'' के बजाय 'replicateM_' का उपयोग करके, अधिक स्पष्ट होने के लिए भी अपडेट किया है। यदि आप 'रनस्टेट (प्रतिकृति एम 10 (रिटर्न()) के परिणाम देखते हैं)() 'बनाम जीएचसीआई में' प्रतिकृति एम_' संस्करण 'यह स्पष्ट होना चाहिए कि यह आवश्यक क्यों है। –