How to force GHC to inline FFI calls?

天大地大妈咪最大 提交于 2019-12-22 05:26:11

问题


I made small C module to improve performance, but GHC doesn't inline foreign functions, and calls cost eliminates the acceleration. For example, 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 }

Making:

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

Finally, in Main.as I have callq <inc> instructions instead of desirable inc's.


回答1:


GHC won't inline C code via its asm backend or LLVM backend. Typically you're only going to call into C for performance reasons if the thing you are calling really costs a lot. Incrementing an int isn't such a thing, as we already have primops for that.

Now, if you call via C you may get GCC to inline things (check the generated assembly).

Now, however, there's some things you can do already to minimize the call cost:

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

inc = fromIntegral . c_inc . fromIntegral

Provide a type signature for inc. You're paying precious cycles converting to Integer here.

Mark the call as "unsafe", as you do, so that the runtime is not bookmarked prior to the call.

Measure the FFI call overhead - it should be in the nanoseconds. However, if you find it still too expensive, you can write a new primop and jump to it directly. But you better have your criterion numbers first.



来源:https://stackoverflow.com/questions/14199402/how-to-force-ghc-to-inline-ffi-calls

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!