2012-03-15 13 views
15

का सही उपयोग यहां एक मूल मोनैड प्रश्न है, रेपा से संबंधित नहीं है, साथ ही कई रिपा-विशिष्ट प्रश्न भी हैं।रेपा 3 प्रदर्शन और 'अब'

मैं रिपै 3 का उपयोग कर लाइब्रेरी पर काम कर रहा हूं। मुझे कुशल समांतर कोड प्राप्त करने में परेशानी हो रही है। अगर मैं अपने कार्यों को देरी से सरणी देता हूं, तो मुझे 8 कोर तक बहुत अच्छी तरह से स्केल कोड मिल जाता है। यह कोड जीएचसी प्रोफाइलर प्रति 20 जीबी मेमोरी लेता है, और मूल हास्केल अनबॉक्स किए गए वैक्टर की तुलना में परिमाण के कई आदेश धीमा करता है।

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

रेपा-एल्गोरिदम में एफएफटी उदाहरण कोड के आधार पर, ऐसा लगता है कि सही दृष्टिकोण हमेशा प्रकट सरणी को वापस करना है। क्या कभी ऐसा कोई मामला है जहां मुझे देरी वाले सरणी वापस करनी चाहिए?

एफएफटी कोड भी 'अब' फ़ंक्शन का भरपूर उपयोग करता है। हालांकि, मैं एक प्रकार त्रुटि मिलती है जब मैं अपने कोड में उपयोग करने का प्रयास करें:

type Arr t r = Array t DIM1 r 
data CycRingRepa m r = CRTBasis (Arr U r) 
        | PowBasis (Arr U r) 

fromArray :: forall m r t. (BaseRing m r, Unbox r, Repr t r) => Arr t r -> CycRingRepa m r 
fromArray = 
    let mval = reflectNum (Proxy::Proxy m) 
    in \x -> 
     let sh:.n = extent x 
     in assert (mval == 2*n) PowBasis $ now $ computeUnboxedP $ bitrev x 

कोड के बिना 'अब' ठीक संकलित करता है। 'अब' के साथ, मैं निम्नलिखित त्रुटि मिलती है:

Couldn't match type r' with Array U (Z :. Int) r' `r' is a rigid type variable bound by the type signature for fromArray :: (BaseRing m r, Unbox r, Repr t r) => Arr t r -> CycRingRepa m r at C:\Users\crockeea\Documents\Code\LatticeLib\CycRingRepa.hs:50:1 Expected type: CycRingRepa m r Actual type: CycRingRepa m (Array U DIM1 r)

मैं नहीं लगताthis मेरी समस्या है। यह मददगार होगा अगर कोई समझा सकता है कि मोनाड 'अब' में कैसे काम करता है। मेरे सबसे अच्छे अनुमान से, मोनड 'एआर यू (एआर यू आर)' बना रहा है। मैं एक 'एआर यू आर' की उम्मीद कर रहा हूं, जो तब डेटा कन्स्ट्रक्टर पैटर्न से मेल खाएगा। क्या चल रहा है और मैं इसे कैसे ठीक करूं?

प्रकार हस्ताक्षर कर रहे हैं:

computeUnboxedP :: Fill r1 U sh e => Array r1 sh e -> Array U sh e 
now :: (Shape sh, Repr r e, Monad m) => Array r sh e -> m (Array r sh e) 

यह जब यह उचित है उपयोग करने के लिए 'अब' का एक बेहतर विचार है करने के लिए उपयोगी होगा।

कुछ अन्य रेपा प्रश्न: क्या मुझे स्पष्ट रूप से computeUnboxedP (जैसा कि एफएफटी उदाहरण कोड में) कहा जाना चाहिए, या क्या मुझे अधिक सामान्य computeP का उपयोग करना चाहिए (क्योंकि अनबॉक्स भाग मेरे डेटा प्रकार से अनुमानित है)? क्या मुझे डेटा प्रकार CycRingRepa में देरी या प्रकट सरणी स्टोर करना चाहिए? आखिरकार मैं इस कोड को हास्केल इंटीग्रर्स के साथ काम करने के लिए भी पसंद करूंगा। क्या मुझे ऐसे नए कोड लिखने की आवश्यकता होगी जो यू सरणी के अलावा कुछ और उपयोग करे, या क्या मैं पॉलिमॉर्फिक कोड लिख सकता हूं जो यू बॉक्स को अनबॉक्स प्रकार और इंटीग्रर्स/बॉक्स किए गए प्रकारों के लिए कुछ अन्य सरणी बनाता है?

मुझे एहसास है कि यहां बहुत सारे प्रश्न हैं, और मैं किसी भी/सभी उत्तरों की सराहना करता हूं!

उत्तर

2

रेपा 3.1 अब now के स्पष्टीकरण के उपयोग की आवश्यकता नहीं है। समांतर गणना फ़ंक्शन सभी monadic हैं, और स्वचालित रूप से deepSeqArray उनके परिणामों पर लागू होते हैं। repa-examples पैकेज में मैट्रिक्स का एक नया कार्यान्वयन भी गुणा करता है जो उनके उपयोग को प्रदर्शित करता है।

8

यहाँ now के लिए स्रोत कोड है:

now arr = do 
    arr `deepSeqArray` return() 
    return arr 

तो यह वास्तव में सिर्फ deepSeqArray के monadic संस्करण है। आप इनमें से किसी एक का उपयोग थैंक पर लटकने के बजाए मूल्यांकन को मजबूर करने के लिए कर सकते हैं। computeP कहा जाता है जब यह "evalulation" मजबूर "गणना" से अलग है।

आपके कोड में, now लागू नहीं होता है, क्योंकि आप एक मोनैड में नहीं हैं। लेकिन इस संदर्भ में deepSeqArray या तो मदद नहीं करेगा।

x :: Array U Int Double 
x = ... 

y :: Array U Int Double 
y = computeUnboxedP $ map f x 

के बाद से yx को संदर्भित करता है, हम यह सुनिश्चित x गणना करने के लिए y शुरू करने से पहले की जाती है होना चाहते हैं: इस स्थिति पर विचार करें। यदि नहीं, तो उपलब्ध काम धागे के गिरोह के बीच सही ढंग से वितरित नहीं किया जाएगा। इस बाहर काम करने के लिए, यह लिखने के लिए y

रूप
y = deepSeqArray x . computeUnboxedP $ map f x 

अब, एक देरी सरणी के लिए, हम

deepSeqArray (ADelayed sh f) y = sh `deepSeq` f `seq` y 

बल्कि सभी तत्वों की गणना की तुलना में बेहतर है, यह सिर्फ यकीन है कि आकार है बनाता है गणना की, और f कमजोर-सामान्य सामान्य रूप में कम कर देता है।

मैनिफेस्ट बनाम देरी वाले सरणी के लिए, निश्चित रूप से समय देरी वाले सरणी बेहतर हैं।

multiplyMM arr brr 
= [arr, brr] `deepSeqArrays` 
    A.sumP (A.zipWith (*) arrRepl brrRepl) 
where trr    = computeUnboxedP $ transpose2D brr 
     arrRepl   = trr `deepSeqArray` A.extend (Z :. All :. colsB :. All) arr 
     brrRepl   = trr `deepSeqArray` A.extend (Z :. rowsA :. All :. All) trr 
     (Z :. _  :. rowsA) = extent arr 
     (Z :. colsB :. _ ) = extent brr 

यहाँ "विस्तार" नए आयाम के कुछ सेट के पार मूल्यों को कॉपी करके एक नई सरणी उत्पन्न करता है। विशेष रूप से, इसका मतलब है कि

arrRepl ! (Z :. i :. j :. k) == arrRepl ! (Z :. i :. j' :. k) 

शुक्र है, extend एक देरी सरणी, पैदा करता है क्योंकि यह यह सब नकल की मुसीबत के माध्यम से जाने के लिए बर्बादी होगी।

विलंबित एरे भी संलयन की संभावना को अनुमति देते हैं, जो सरणी प्रकट होने पर असंभव है।

अंत में, computeUnboxedP एक विशेष प्रकार के साथ computeP है। computeUnboxedP देने से स्पष्ट रूप से जीएचसी को बेहतर अनुकूलित करने की अनुमति मिल सकती है, और कोड को थोड़ा स्पष्ट बनाता है।

संबंधित मुद्दे