2012-03-15 24 views
15

Có một câu hỏi đơn giản cơ bản ở đây, không liên quan đến Repa, cộng với một số câu hỏi cụ thể về Repa.Hiệu năng Repa 3 và sử dụng chính xác 'now'

Tôi đang làm việc trên thư viện bằng Repa3. Tôi gặp sự cố khi nhận mã song song hiệu quả. Nếu tôi thực hiện các chức năng của mình trả về các mảng bị trì hoãn, tôi nhận được mã chậm quá mức có thể lên tới 8 lõi. Mã này chiếm hơn 20GB bộ nhớ cho mỗi trình lược tả GHC, và chạy một số đơn đặt hàng có cường độ chậm hơn so với các vectơ không có hộp Haskell cơ bản. Ngoài ra, nếu tôi thực hiện tất cả các chức năng của mình trả về các bảng kê khai không được hộp (vẫn cố gắng sử dụng sự kết hợp trong các hàm, ví dụ khi tôi thực hiện 'bản đồ'), tôi nhận được mã MUCH nhanh hơn (vẫn chậm hơn sử dụng Haskell unboxed). vectơ) không quy mô chút nào và trên thực tế có xu hướng chậm hơn một chút với nhiều lõi hơn.

Dựa trên mã ví dụ FFT trong thuật toán Repa, có vẻ như cách tiếp cận đúng là luôn trả về các mảng biểu hiện. Có bao giờ một trường hợp tôi phải trả lại mảng bị trễ không?

Mã FFT cũng sử dụng nhiều chức năng 'hiện hành'. Tuy nhiên, tôi gặp phải lỗi loại khi tôi cố gắng sử dụng nó trong mã của mình:

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 

Mã biên dịch không có 'bây giờ'. Với sự 'bây giờ', tôi nhận được lỗi sau:

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)

tôi không nghĩthis là vấn đề của tôi. Sẽ rất hữu ích nếu ai đó có thể giải thích cách Monad hoạt động trong 'bây giờ'. Theo ước tính tốt nhất của tôi, monad dường như đang tạo ra một 'Arr U (Arr U r)'. Tôi đang mong đợi một 'Arr U r', mà sau đó sẽ phù hợp với mô hình xây dựng dữ liệu. Điều gì đang xảy ra và làm cách nào để khắc phục sự cố này?

Chữ ký loại là:

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) 

Nó sẽ rất hữu ích để có một ý tưởng tốt hơn khi nó là thích hợp để sử dụng 'doanh nghiệp'.

Một vài câu hỏi khác về Repa: Tôi có nên gọi hàm computeUnboxedP (như trong mã ví dụ FFT) hay tôi nên sử dụng tính toán tổng quát hơn (vì phần unbox được suy ra theo kiểu dữ liệu của tôi)? Tôi có nên lưu trữ các mảng bị trễ hoặc biểu hiện trong kiểu dữ liệu CycRingRepa không? Cuối cùng tôi cũng muốn mã này hoạt động với các số nguyên Haskell. Điều này đòi hỏi tôi phải viết mã mới sử dụng một cái gì đó khác hơn là mảng U, hoặc tôi có thể viết mã đa hình tạo ra các mảng U cho các loại unbox và một số mảng khác cho các kiểu Integers/boxed?

Tôi nhận thấy có rất nhiều câu hỏi ở đây và tôi đánh giá cao bất kỳ/tất cả câu trả lời!

Trả lời

2

Repa 3.1 không còn yêu cầu sử dụng explict của now. Các hàm tính toán song song đều là monadic và tự động áp dụng deepSeqArray cho kết quả của chúng. Gói repa-examples cũng chứa một bản thực thi ma trận nhân mới thể hiện việc sử dụng chúng.

8

Dưới đây là các mã nguồn cho now:

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

Vì vậy, nó thực sự chỉ là một phiên bản monadic của deepSeqArray. Bạn có thể sử dụng một trong hai cách này để buộc đánh giá, thay vì treo trên một đoạn. "Đánh giá" này khác với "tính toán" bắt buộc khi gọi computeP.

Trong mã của bạn, now không áp dụng, vì bạn không ở trong một đơn nguyên. Nhưng trong bối cảnh này, deepSeqArray cũng không giúp được gì.Hãy xem xét tình huống này:

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

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

Kể từ y đề cập đến x, chúng tôi muốn chắc chắn x được tính trước khi bắt đầu để tính toán y. Nếu không, công việc có sẵn sẽ không được phân phối chính xác giữa các chuỗi chủ đề. Để có được điều này để làm việc ra, nó tốt hơn để viết y như

y = deepSeqArray x . computeUnboxedP $ map f x 

Bây giờ, đối với một mảng chậm, chúng tôi có

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

Thay vì tính toán tất cả các yếu tố, điều này chỉ làm cho chắc chắn hình dạng là được tính toán và giảm f thành biểu mẫu chuẩn yếu.

Đối với mảng biểu hiện so với mảng bị trì hoãn, chắc chắn có thời gian trễ mảng tốt hơn.

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 

Tại đây "mở rộng" tạo mảng mới bằng cách sao chép các giá trị trên một số kích thước mới. Đặc biệt, điều này có nghĩa rằng

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

Rất may, extend tạo ra một mảng chậm, vì nó sẽ là một sự lãng phí phải đi qua những rắc rối của tất cả các sao chép này.

Mảng trễ cũng cho phép khả năng hợp nhất, điều này là không thể nếu mảng được biểu hiện.

Cuối cùng, computeUnboxedP chỉ là computeP với loại chuyên biệt. Việc cung cấp computeUnboxedP rõ ràng có thể cho phép GHC tối ưu hóa tốt hơn và làm cho mã này rõ ràng hơn một chút.

Các vấn đề liên quan