Tính biến đổi của Tự động hóa trong GHC


392

Từ các tài liệu cho GHC 7.6:

[Y] ou thường không cần đến pragma ĐẶC BIỆT ngay từ đầu. Khi biên dịch mô-đun M, trình tối ưu hóa của GHC (với -O) sẽ tự động xem xét từng hàm quá tải cấp cao nhất được khai báo trong M và chuyên về nó cho các loại khác nhau mà nó được gọi trong M. Trình tối ưu hóa cũng xem xét từng chức năng bị quá tải INLINEABLE, và chuyên về nó cho các loại khác nhau mà nó được gọi là M.

Ngoài ra, được cung cấp một pragma ĐẶC BIỆT cho một hàm f, GHC sẽ tự động tạo các chuyên môn hóa cho bất kỳ hàm quá tải loại lớp nào được gọi bởi f, nếu chúng nằm trong cùng một mô-đun như pragma ĐẶC BIỆT, hoặc nếu chúng là TUYỆT VỜI; và cứ thế, quá cảnh.

Vì vậy, GHC nên tự động chuyên môn hóa một số / hầu hết / tất cả (?) Hàm được đánh dấu INLINABLE mà không có pragma và nếu tôi sử dụng một pragma rõ ràng, thì chuyên môn hóa là bắc cầu. Câu hỏi của tôi là: là tự động quá trình chuyên môn hóa?

Cụ thể, đây là một ví dụ nhỏ:

Chính.hs:

import Data.Vector.Unboxed as U
import Foo

main =
    let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
        (Bar (Qux ans)) = iterate (plus y) y !! 100
    in putStr $ show $ foldl1' (*) ans

Foo.hs:

module Foo (Qux(..), Foo(..), plus) where

import Data.Vector.Unboxed as U

newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
           | Baz !t

instance (Num r, Unbox r) => Num (Qux r) where
    {-# INLINABLE (+) #-}
    (Qux x) + (Qux y) = Qux $ U.zipWith (+) x y

{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2

GHC chuyên các cuộc gọi đến plus, nhưng không chuyên (+)trong Qux Numví dụ mà giết hiệu suất.

Tuy nhiên, một pragma rõ ràng

{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}

kết quả trong bắc cầu chuyên môn như các tài liệu cho thấy, vì vậy (+)chuyên và mã là 30x nhanh hơn (cả biên soạn với -O2). Đây có phải là hành vi dự kiến? Tôi chỉ nên mong đợi (+)được chuyên môn hóa quá mức với một pragma rõ ràng?


CẬP NHẬT

Các tài liệu cho 7.8.2 không thay đổi và hành vi là như nhau, vì vậy câu hỏi này vẫn có liên quan.


33
Tôi không biết câu trả lời nhưng có vẻ như nó có thể liên quan đến: ghc.haskell.org/trac/ghc/ticket/5928 Có thể đáng để mở một vé mới hoặc thêm thông tin của bạn vào đó nếu bạn nghĩ rằng nó có thể liên quan đến 5928
jberryman

6
@jberryman Dường như có hai sự khác biệt giữa các vé và câu hỏi của tôi: 1) Trong vé, tương đương với plusđã không đánh dấu là INLINABLE và 2) simonpj chỉ ra rằng có một số nội tuyến xảy ra với mã vé, nhưng cốt lõi từ ví dụ của tôi cho thấy rằng không có chức năng nào được nội tuyến (đặc biệt, tôi không thể thoát khỏi hàm tạo thứ hai Foo, nếu không thì nội dung được GHC nội tuyến).
crockeea

5
à được rồi. Điều gì xảy ra khi bạn xác định plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2, để LHS được áp dụng đầy đủ tại trang web cuộc gọi? Liệu nó có được nội tuyến và sau đó chuyên môn hóa đá trong?
jberryman

3
@jberryman Hài hước bạn nên hỏi. Tôi đã đi xuống con đường đó với câu hỏi này dẫn đến báo cáo này . Ban đầu tôi có cuộc gọi để plusáp dụng đầy đủ cụ thể do các liên kết đó, nhưng thực tế tôi đã ít chuyên môn hóa hơn : cuộc gọi đến pluscũng không chuyên biệt. Tôi không có lời giải thích cho điều đó, nhưng đã có ý định để nó cho một câu hỏi khác, hoặc hy vọng rằng nó sẽ được giải quyết trong một câu trả lời cho câu hỏi này.
crockeea

11
Từ ghc.haskell.org/trac/ghc/wiki/ReportABug : "Nếu nghi ngờ, chỉ cần báo cáo lỗi của bạn." Bạn không nên cảm thấy tồi tệ, đặc biệt là vì có đủ số lượng người bán hàng thực sự có kinh nghiệm ở đây không biết cách trả lời câu hỏi của bạn. Các trường hợp thử nghiệm như thế này có lẽ thực sự có giá trị đối với các nhà phát triển GHC. Dù sao chúc may mắn! Cập nhật câu hỏi nếu bạn nộp vé
jberryman

Câu trả lời:


4

Câu trả lời ngắn:

Những điểm chính của câu hỏi, như tôi hiểu, là như sau:

  • "là tự động chuyên môn hóa bắc cầu?"
  • Tôi có nên chỉ mong đợi (+) được chuyên môn hóa quá mức với một pragma rõ ràng?
  • (có ý định rõ ràng) Đây có phải là lỗi của GHC không? Có phù hợp với các tài liệu?

AFAIK, câu trả lời là Không, chủ yếu là có nhưng có những cách khác và Không.

Mã hóa nội tuyến và chuyên môn hóa ứng dụng là sự đánh đổi giữa tốc độ (thời gian thực hiện) và kích thước mã. Mức mặc định được tăng tốc mà không làm phồng mã. Việc chọn một mức độ toàn diện hơn được để lại theo ý của lập trình viên thông qua SPECIALISEpragma.

Giải trình:

Trình tối ưu hóa cũng xem xét từng hàm quá tải INLINEABLE đã nhập và chuyên về nó cho các loại khác nhau mà nó được gọi trong M.

Giả sử flà một hàm có kiểu bao gồm một biến kiểu abị ràng buộc bởi một lớp kiểuC a . GHC theo mặc định chuyên fđối với một ứng dụng loại (thay thế bằng acho t) nếu fđược gọi với loại ứng dụng trong mã nguồn của (a) bất kỳ chức năng trong cùng một module, hoặc (b) nếu fđược đánh dấu INLINABLE, sau đó bất kỳ mô-đun khác mà nhập khẩu f từ B. Do đó, chuyên môn hóa tự động không mang tính bắc cầu, nó chỉ chạm vào các INLINABLEchức năng được nhập và được gọi trong mã nguồn của A.

Trong ví dụ của bạn, nếu bạn viết lại ví dụ Numnhư sau:

instance (Num r, Unbox r) => Num (Qux r) where
    (+) = quxAdd

quxAdd (Qux x) (Qux y) = Qux $ U.zipWith (+) x y
  • quxAddkhông được nhập khẩu cụ thể bởi Main. Mainnhập từ điển ví dụ của Num (Qux Int)và từ điển này chứa quxAddtrong bản ghi cho (+). Tuy nhiên, mặc dù từ điển được nhập, nhưng nội dung được sử dụng trong từ điển thì không.
  • plus không gọi quxAdd , nó sử dụng chức năng được lưu trữ cho (+)bản ghi trong từ điển thể hiện của Num t. Từ điển này được đặt tại trang web cuộc gọi (in Main) bởi trình biên dịch.
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.