Chuyên môn hóa với các ràng buộc


156

Tôi đang gặp vấn đề khi GHC chuyên môn hóa một chức năng với ràng buộc lớp. Tôi có một ví dụ rất nhỏ của vấn đề của tôi ở đây: Foo.hsMain.hs . Hai tệp biên dịch (GHC 7.6.2, ghc -O3 Main) và chạy.

LƯU Ý: Foo.hs thực sự bị tước bỏ. Nếu bạn muốn xem tại sao cần phải có ràng buộc, bạn có thể xem thêm một chút mã ở đây . Nếu tôi đặt mã trong một tệp duy nhất hoặc thực hiện nhiều thay đổi nhỏ khác, GHC chỉ cần thực hiện cuộc gọi đến plusFastCyc. Điều này sẽ không xảy ra trong mã thực bởi vì plusFastCycGHC quá lớn để nội tuyến, ngay cả khi được đánh dấu INLINE. Vấn đề là chuyên môn hóa cuộc gọi đến plusFastCyc, không phải nội tuyến. plusFastCycđược gọi ở nhiều nơi trong mã thực, do đó, việc sao chép một hàm lớn như vậy sẽ không được mong muốn ngay cả khi tôi có thể buộc GHC thực hiện.

Mã quan tâm là plusFastCyctrong Foo.hs, được sao chép ở đây:

{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc :: 
         forall m . (Factored m Int) => 
              (FastCyc (VT U.Vector m) Int) -> 
                   (FastCyc (VT U.Vector m) Int) -> 
                        (FastCyc (VT U.Vector m) Int) #-}

-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc :: 
--          FastCyc (VT U.Vector M) Int -> 
--               FastCyc (VT U.Vector M) Int -> 
--                    FastCyc (VT U.Vector M) Int #-}

plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2

Các Main.hstập tin có hai tài xế: vtTest, chạy trong ~ 3 giây, và fcTest, chạy trong ~ 83 giây khi biên soạn với O3 bằng cách sử dụng forall'd chuyên môn hóa.

Các chương trình cốt lõi rằng đối với vtTestkiểm tra, mã bổ sung đang được chuyên để Unboxedvectơ qua Ints, vv, trong khi mã vector chung được sử dụng cho fcTest. Trên dòng 10, bạn có thể thấy GHC viết một phiên bản chuyên biệt plusFastCyc, so với phiên bản chung trên dòng 167. Quy tắc dành cho chuyên môn hóa là trên dòng 225. Tôi tin rằng quy tắc này sẽ kích hoạt trên dòng 270. ( main6các cuộc gọi iterate main8 y, vì vậy main8là nơi nào plusFastCycnên chuyên ngành.)

Mục tiêu của tôi là làm fcTestnhanh như vtTestchuyên plusFastCyc. Tôi đã tìm thấy hai cách để làm điều này:

  1. Cuộc gọi giải thích inlinetừ GHC.Extstrong fcTest.
  2. Loại bỏ các Factored m Intràng buộc trên plusFastCyc.

Tùy chọn 1 là không thỏa đáng vì trong cơ sở mã thực tế plusFastCyclà một hoạt động được sử dụng thường xuyên và một chức năng rất lớn, do đó không nên nội tuyến trong mỗi lần sử dụng. Thay vào đó, GHC nên gọi một phiên bản chuyên biệt của plusFastCyc. Tùy chọn 2 không thực sự là một tùy chọn vì tôi cần sự ràng buộc trong mã thực.

Tôi đã thử một loạt các lựa chọn sử dụng (và không sử dụng) INLINE, INLINABLESPECIALIZE, nhưng không có vẻ làm việc. ( EDIT : Tôi có thể đã loại bỏ quá nhiều plusFastCycđể làm cho ví dụ của mình trở nên nhỏ, do đó INLINEcó thể khiến hàm bị nội tuyến. Điều này không xảy ra trong mã thực của tôi vì plusFastCycquá lớn.) Trong ví dụ cụ thể này, tôi không nhận được bất kỳ match_co: needs more caseshoặc RULE: LHS too complicated to desugar(và ở đây ) cảnh báo, mặc dù tôi đã nhận được nhiều match_cocảnh báo trước khi giảm thiểu ví dụ. Có lẽ, "vấn đề" là sự Factored m Intràng buộc trong quy tắc; nếu tôi thay đổi ràng buộc đó, hãy fcTestchạy nhanh như vtTest.

Tôi có đang làm điều gì đó mà GHC không thích? Tại sao GHC không chuyên plusFastCyc, và làm cách nào để tạo ra nó?

CẬP NHẬT

Vấn đề vẫn tồn tại trong GHC 7.8.2, vì vậy câu hỏi này vẫn có liên quan.


3
Tôi chỉ cố gắng chuyên cho một cụ thể m , cụ thể là M. Điều này đã hoàn thành công việc, nhưng tôi không thể chuyên cho các loại bóng cụ thể trong chương trình thực khi chúng được thống nhất.
crockeea

Tôi cũng đã gửi báo cáo lỗi GHC ghc.haskell.org/trac/ghc/ticket/8668 nhưng vấn đề vẫn còn mở. Quá trình báo cáo lỗi đã giúp tôi dọn dẹp câu hỏi một chút, vì vậy hy vọng nó sẽ dễ dàng hơn để tìm hiểu những gì đang xảy ra.
crockeea

@monojohnny Xin lỗi khi nghe điều đó, tôi tin rằng bạn có thể gắn cờ như vậy. Tôi nghĩ rằng tôi đang yêu cầu GHC làm điều gì đó khá hợp lý và nó sẽ không làm điều đó. Tôi không chắc liệu mình có làm sai hay không, nếu đây là một sự bình dị với trình biên dịch có thể có cách giải quyết. Tôi đã thấy các cách giải quyết về chuyên môn hóa và các quy tắc trong một số thư viện cụ thể về hack mà thoát khỏi tôi vào lúc này, vì vậy tôi hy vọng ai đó trong cộng đồng có nhiều kinh nghiệm về GHC hơn tôi có thể biết cách đạt được chuyên môn hóa.
crockeea

1
Tôi xin lỗi vì những giai điệu của nhận xét của tôi - nó không phải đóng góp hết sức mình vào trang web này - có thực sự là không có gì sai trái với bài viết của bạn (Đó là tôi thiếu hiểu biết đó là nguồn gốc của ít phiền toái của tôi, tôi đoán!)
monojohnny

@monojohnny Lời xin lỗi được chấp nhận, nhưng thật tệ khi downvote bị khóa ngay bây giờ ;-)
crockeea

Câu trả lời:


5

GHC cũng cung cấp tùy chọn cho SPECIALIZEkhai báo thể hiện loại lớp. Tôi đã thử điều này với mã (mở rộng) của Foo.hs, bằng cách đặt như sau:

instance (Num r, V.Vector v r, Factored m r) => Num (VT v m r) where 
    {-# SPECIALIZE instance ( Factored m Int => Num (VT U.Vector m Int)) #-}
    VT x + VT y = VT $ V.zipWith (+) x y

Thay đổi này, mặc dù, không đạt được tốc độ mong muốn. Điều gì đã đạt được sự cải thiện hiệu suất đó là thêm thủ công chuyên biệt cho loại VT U.Vector m Intcó cùng định nghĩa hàm, như sau:

instance (Factored m Int) => Num (VT U.Vector m Int) where 
    VT x + VT y = VT $ V.zipWith (+) x y

Điều này đòi hỏi phải thêm OverlappingInstancesFlexibleInstancesvào LANGUAGE.

Thật thú vị, trong chương trình ví dụ, việc tăng tốc thu được với thể hiện chồng chéo vẫn còn ngay cả khi bạn loại bỏ mọi SPECIALIZEINLINABLEpragma.


Chắc chắn là không tối ưu, nhưng đó là giải pháp đầu tiên thực sự hoàn thành mục tiêu, vì vậy tôi đoán tôi sẽ thực hiện ngay bây giờ ...
crockeea
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.