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ます。ここで整数に変換する貴重なサイクルを支払っています。

呼び出しの前にランタイムがブックマークされないように、呼び出しを「安全でない」とマークします。

FFI 呼び出しのオーバーヘッドを測定します - ナノ秒単位である必要があります。ただし、それでも高すぎる場合は、新しい primop を作成して直接ジャンプすることができます。ただし、最初に基準番号を取得することをお勧めします。

于 2013-01-07T17:21:22.220 に答える