6

我做了小 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的。

4

1 回答 1

9

GHC 不会通过其 asm 后端或 LLVM 后端内联 C 代码。通常,如果您调用的东西确实花费很多,您只会出于性能原因调用 C。增加一个 int 不是这样的事情,因为我们已经有了 primops 。

现在,如果您通过 C 调用,您可能会让 GCC 内联(检查生成的程序集)。

但是,现在您可以做一些事情来最小化通话成本:

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

inc = fromIntegral . c_inc . fromIntegral

inc. 您在这里为转换为 Integer 付出了宝贵的周期。

像您一样将调用标记为“不安全”,以便在调用之前不会为运行时添加书签。

测量 FFI 调用开销 - 它应该以纳秒为单位。但是,如果您觉得它仍然太贵,您可以编写一个新的 primop 并直接跳转到它。但你最好先有你的标准数字。

于 2013-01-07T17:21:22.220 回答