2013-01-07 25 views
6

Tôi đã thực hiện mô-đun C nhỏ để cải thiện hiệu suất, nhưng GHC không trực tiếp chức năng ngoại tuyến, và chi phí cuộc gọi loại bỏ gia tốc. Ví dụ, test.h:Làm cách nào để buộc GHC thực hiện các cuộc gọi FFI nội tuyến?

int inc (int x); 

test.c:

#include "test.h" 
int inc(int x) {return x + 1;} 

Test.hc:

{-# LANGUAGE ForeignFunctionInterface #-} 
module Test (inc) where 
import Foreign 
import Foreign.C 
foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt 
inc = fromIntegral . c_inc . fromIntegral 
{-# INLINE c_inC#-} 
{-# INLINE inC#-} 

Main.hs:

import System.Environment 
import Test 
main = do {args <- getArgs; putStrLn . show . inc . read . head $ args } 

Làm:

$ gcc -O2 -c test.c 
$ ghc -O3 test.o Test.hs 
$ ghc --make -O3 test.o Main 
$ objdump -d Main > Main.as 

Cuối cùng, trong Main.as Tôi có callq <inc> hướng dẫn thay vì mong muốn inc 's.

+3

Bạn mong đợi ghc để inline một hàm C trong mã được tạo ra của nó? Điều này có thể làm việc nếu bạn sử dụng tùy chọn -via-C, nếu không nó sẽ vô vọng (vì nó sẽ yêu cầu ghc đọc mã C và tạo mã cho nó). – augustss

+2

Không thể khi không có tối ưu hóa thời gian liên kết. Một cách tiếp cận (hacky) để thử là biên dịch cả bit Haskell và C thành LLVM, kết hợp các tệp .bc với 'llvm-link', tối ưu hóa bằng' opt' và sau đó phát ra mã thực thi với 'llc'. –

+0

@MikhailGlushenkov, bạn có thể viết một bản phác thảo tạo chuỗi lệnh không? Tôi không thể tìm ra cách để lấy các tệp '.bc' từ mã haskell. – leventov

Trả lời

9

GHC sẽ không trực tiếp mã C qua chương trình phụ trợ asm hoặc chương trình phụ trợ LLVM. Thông thường bạn sẽ chỉ gọi vào C vì lý do hiệu suất nếu điều bạn đang gọi thực sự là chi phí rất nhiều. Gia tăng một int không phải là một điều như vậy, như chúng tôi đã có primops cho điều đó.

Bây giờ, nếu bạn gọi qua C, bạn có thể nhận được GCC để nội tuyến (kiểm tra lắp ráp được tạo ra).

Bây giờ, tuy nhiên, có một số điều bạn có thể làm đã để giảm thiểu chi phí cuộc gọi:

foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt 

inc = fromIntegral . c_inc . fromIntegral 

Cung cấp chữ ký kiểu cho inc. Bạn đang trả tiền chu kỳ quý giá chuyển đổi sang Integer ở đây.

Đánh dấu cuộc gọi là "không an toàn", như bạn đã làm, để thời gian chạy không được đánh dấu trước cuộc gọi.

Đo chi phí cuộc gọi FFI - nó phải ở trong nano giây. Tuy nhiên, nếu bạn thấy nó vẫn quá đắt, bạn có thể write a new primop and jump to it directly. Nhưng trước hết bạn nên có số criterion của mình.

+0

Trên thực tế, "inc" của tôi là tập hợp các chức năng tối thiểu SSE không có nhánh: https://gist.github.com/4476908 – leventov

+0

Tôi hiểu rồi - bạn thực sự muốn có các bước đầu mới. Bạn đang sao chép một số thứ của http://hackage.haskell.org/trac/ghc/ticket/3557? –

+0

Nói chung là không, nhưng có lẽ những hướng dẫn tối thiểu này được đặc biệt cân nhắc trong vé, tôi chưa nghiên cứu chi tiết. – leventov

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