2012-03-15 4 views
15

Repa와 관련이없는 기본적인 모나드 질문과 여러 Repa 관련 질문이 있습니다.Repa 3 성능 및 'now'의 올바른 사용

저는 Repa3을 사용하는 라이브러리 작업을하고 있습니다. 효율적인 병렬 코드를 가져 오는 데 문제가 있습니다. 필자의 함수가 지연 배열을 반환하게되면, 최대 8 코어까지 확장 될 정도로 느린 코드가 발생합니다. 이 코드는 GHC 프로파일 러 당 20GB 이상의 메모리를 사용하며 기본 Haskell unboxed 벡터보다 몇 배 더 느리게 실행됩니다. 내가 할 경우

는 다른 방법으로, 내 모든 기능은 박스 없음 매니페스트 배열 하스켈은 언 박싱 사용하는 것보다 여전히 느린 내가 얻을 훨씬 빠른 코드 ((여전히 나는 '지도'를 수행 할 때, 예를 들어, 함수 내에서 융합을 사용하려고 시도) 반환 벡터)는 전혀 확장되지 않으며 실제로 더 많은 코어로 약간 느려지는 경향이 있습니다.

Repa-Algorithms의 FFT 예제 코드에 따르면 올바른 방법은 항상 매니페스트 배열을 반환하는 것입니다. 지연 배열을 반환해야하는 경우가 있습니까?

FFT 코드는 'now'기능을 많이 사용합니다. 그러나 내 코드에서 사용할 때 형식 오류가 발생합니다.

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 

코드가 'now'없이 잘 컴파일됩니다. 하지 this 내 문제라고 생각

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)

내가 할 다음 '지금'으로, 나는 다음과 같은 오류가 발생합니다. Monad가 '지금'에서 어떻게 작동하는지 설명 할 수 있다면 도움이 될 것입니다. 나의 가장 좋은 평가에 의하면 모나드는 'Arr U (Arr U r)'을 만드는 것으로 보인다. 나는 'Arr U r'을 기대하고 있는데, 이것은 데이터 생성자 패턴과 일치 할 것이다. 무슨 일이 일어나고 있으며 어떻게 해결할 수 있습니까?

유형 서명은 다음과 같습니다

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) 

이 '지금'을 사용하는 것이 적절한 경우의 더 나은 생각을 가지고 도움이 될 것입니다.

몇 가지 다른 Repa 질문 : computeUnboxedP (FFT 예제 코드에서와 같이)를 명시 적으로 호출해야합니까? 아니면 일반 데이터를 사용해야합니까? (데이터 유형에 따라 unbox 부분이 유추되기 때문에)? CycRingRepa 데이터 유형에 지연 배열 또는 명시 적 배열을 저장해야합니까? 결국이 코드를 Haskell Integer와 함께 사용하길 바란다. U 배열 이외의 다른 것을 사용하는 새로운 코드를 작성해야합니까? 아니면 Unbox 유형에 대한 U 배열과 Integers/boxed 유형에 대한 다른 배열을 만드는 다형 코드를 작성할 수 있습니까?

여기에 많은 질문이 있다는 것을 알고 있으며, 모든 답변에 감사드립니다!

답변

2

바디 수리 3.1은 더 이상 now의 EXPLICT 사용을 필요로하지 않습니다. 병렬 계산 기능은 모두 모나드이며 결과에 deepSeqArray을 자동으로 적용합니다. repa-examples 패키지는 사용을 보여줍니다 행렬 곱셈의 새로운 구현이 포함되어 있습니다.

8

여기 now의 소스 코드입니다 :

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

그래서 정말 deepSeqArray 단지 모나드 버전이다. 썽크에 매달리는 대신 평가를 강요하기 위해 이들 중 하나를 사용할 수 있습니다. 이 "평가"는 computeP이 호출 될 때 강제되는 "계산"과 다릅니다.

코드에서 now은 모나드가 아니기 때문에 적용되지 않습니다. 그러나이 문맥에서는 deepSeqArray도 도움이되지 않습니다.yx을 의미

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

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

때문에, 우리는 xy을 계산을 시작하기 전에 계산되어 있는지 확인하고 싶습니다 :이 상황을 생각해 보자. 그렇지 않으면 사용 가능한 작업이 스레드 그룹간에 올바르게 배포되지 않습니다. 이 밖으로 작동하도록하기 위해서는 y 이제

y = deepSeqArray x . computeUnboxedP $ map f x 

로, 지연 배열, 우리는 오히려 모든 요소를 ​​계산보다

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

을 작성하는 것이 좋습니다, 이것은 단지 모양이 확인합니다 계산하고, f을 weak head normal form으로 줄입니다. 지연 어레이 VS 매니페스트위한

같이, 확실히 존재 시간 지연 배열이 바람직하다.

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이 지연 배열을 생산하는 것을 의미한다.

지연된 배열은 배열이 명백한 경우 불가능 융합의 possiblity를들을 수 있습니다.

마지막으로, computeUnboxedPcomputeP 전문 유형입니다. 명시 적으로 computeUnboxedP을주는 것은 GHC 더 최적화 할 수 있도록, 조금 더 명확한 코드를 수 있습니다.