我制作了小型C模块以提高性能,但GHC并没有内联外部功能,而且调用成本消除了加速.例如,test.h:
int inc (int x);
Run Code Online (Sandbox Code Playgroud)
test.c:
#include "test.h"
int inc(int x) {return x + 1;}
Run Code Online (Sandbox Code Playgroud)
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 #-}
Run Code Online (Sandbox Code Playgroud)
Main.hs:
import System.Environment
import Test
main = do {args <- getArgs; putStrLn . show . inc . read . head $ args }
Run Code Online (Sandbox Code Playgroud)
制造:
$ gcc -O2 -c test.c
$ ghc -O3 test.o Test.hs
$ ghc --make -O3 test.o Main
$ objdump -d Main > Main.as
Run Code Online (Sandbox Code Playgroud)
最后,在Main.as我有callq <inc>指示而不是理想inc的指令.
GHC不会通过其asm后端或LLVM后端内联C代码.通常情况下,如果你打电话的东西真的花了很多钱,你只会因为性能原因打电话给C.增加一个int不是这样的事情,因为我们已经有了这个原则.
现在,如果你通过C调用,你可能会得到GCC内联的东西(检查生成的程序集).
但是,现在您已经可以做一些事情来降低通话费用:
foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt
inc = fromIntegral . c_inc . fromIntegral
Run Code Online (Sandbox Code Playgroud)
提供类型签名inc.你在这里支付宝贵的周期转换为整数.
将调用标记为"不安全",以便在调用之前不对运行时添加书签.
测量FFI呼叫开销 - 它应该在纳秒内.但是,如果你发现它仍然太昂贵,你可以写一个新的primop并直接跳转到它.但你最好首先得到你的标准数字.