我制作了小型C模块以提高性能,但GHC并没有内联外部功能,而且调用成本消除了加速。
例如,test.h
:
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 }
制作:
$ gcc -O2 -c test.c
$ ghc -O3 test.o Test.hs
$ ghc --make -O3 test.o Main
$ objdump -d Main > Main.as
最后,在Main.as
callq <inc>
我有inc
条指令,而不是理想的{{1}}。
答案 0 :(得分:9)
GHC不会通过其asm后端或LLVM后端内联C代码。通常情况下,如果你打电话的东西真的花了很多钱,你只会因为性能原因打电话给C。增加一个int并不是一件事,因为我们已经有了这个原则。
现在,如果你通过C调用,你可能会让GCC内联(检查生成的程序集)。
但是,现在您可以做一些事情来降低通话费用:
foreign import ccall unsafe "test.h inc" c_inc :: CInt -> CInt
inc = fromIntegral . c_inc . fromIntegral
为inc
提供类型签名。你在这里支付宝贵的周期转换为整数。
将调用标记为“不安全”,这样就可以在调用之前将运行时添加为书签。
测量FFI呼叫开销 - 它应该在纳秒内。但是,如果您发现它仍然过于昂贵,可以write a new primop and jump to it directly.但最好先提供criterion个数字。