4

メモリとエラー管理をユーザーから隠すために、FFI インターフェイスを介して Haskell から PETScライブラリ(のサブセット) を利用できるようにしたいと考えています。

  • 以下に示すコマンドで共有ライブラリを使用して PETSc 3.5.3 をビルドすると、テスト スイートが正常に実行されます。
  • ヘッダーのインポート、タイプ、および 2 つの外部関数インターフェイスの例を含む .hsc ファイル #2 を準備しました
  • ビルドを自動化する Makefile #3 を準備しました。make test1ロードされたモジュールで GHCi を渡し、起動します。

ライブラリは、MPI と完全に分散されたデータ構造によって有効化された並列操作に優れているため、ほとんどの操作 (すべてのデータ アセンブリ、計算、および割り当て解除はライブラリ プリミティブによって行われる必要があります) の間、Haskell で大量のデータ トラフィックを期待する必要はありませんが、"データ準備完了」。PETSc 関連の Haskell 関数は、純粋性を保証できないため、主に IO モナドに値を持ちます (たとえば、返される C エラー コードは、プログラムの外部の理由により異なる場合があります)。

  • unsafePerformIOallocaメモリとエラー管理をラップする必要があります。この考え方は正しいでしょうか?悪いアイデア
  • GHC でコンパイルされたバイナリは で実行できますmpirunか?はい

私はすべての提案と発言を受け入れます。前もって感謝します

-- 注記: GHC に実行可能なバイナリを生成してもらいたい: mpirunGHC コマンド ラインからリンカーにオプションを-optlフラグ (参照here ) で渡すことができるため、次のような組み合わせが提案されていghc -optl-static -lmpichます。これについては、試してみることができ次第、追加します。

1) 構成コマンド:

$ ./configure --with-cc=gcc --with-cxx=g++ --with-fc=gfortran --with-shared-libraries=1 --download-mpich --download-fblaslapack

2) PETSC.hsc

{-# LANGUAGE CPP, ForeignFunctionInterface, EmptyDataDecls #-}
module PETSc where

import Foreign
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String

#include <petscksp.h>
#include <petscsys.h>

newtype PetscErrCode = PetscErrCode {unPetscErrCode :: CInt} deriving (Eq, Show)
newtype PetscInt = PetscInt {unPetscInt :: CInt} deriving (Eq, Show)

data Petsc
-- PetscErrorCode PetscInitialize(int *argc,char ***args,const char file[],const char help[])
foreign import ccall unsafe "petscsys.h PetscInitialize"
  c_petscInitialize :: Ptr CInt -> Ptr (Ptr CString) -> CString -> CString -> IO PetscErrCode

-- PetscErrorCode PetscFinalize(void)
foreign import ccall unsafe "petscsys.h PetscFinalize"
  c_petscFinalize :: IO PetscErrCode

3) メイクファイル

PETSC_DIR_ARCH = ${PETSC_DIR}/arch-darwin-c-debug

PETSc.hs: 
    hsc2hs PETSc.hsc -I ${PETSC_DIR}/include -I ${PETSC_DIR_ARCH}/include

test1: PETSc.hs 
    ghci -dynamic PETSc.hs -L${PETSC_DIR_ARCH}/lib
4

1 に答える 1

2

野心的!私は hsc2hs の代わりに C2HS を使用したくなるでしょう。(私は C2HS のメンテナーなので、私の言うことは何でも聞いてください!)

PetscInitialize例として、次のPetscFinalizeようにバインドできます。

-- This is in PETSc.chs
module PETSc (initialize, finalize) where

import Foreign
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String
import System.Environment (getArgs)

#include <petscksp.h>
#include <petscsys.h>

-- Marshalling helpers for PETSc error codes.

newtype ErrCode = ErrCode { unErrCode :: Int }
                deriving (Eq, Show)

convErrCode :: CInt -> ErrCode
convErrCode = ErrCode . fromIntegral

{#typedef PetscErrorCode CInt#}
{#default out `ErrCode' [PetscErrorCode] convErrCode#}


-- Marshalling helpers for "char ***" argument to PetscInitialize.

withCStrings :: [String] -> ([CString] -> IO a) -> IO a
withCStrings ss f = case ss of
  [] -> f []
  (s:ss') -> withCString s $ \cs -> do
    withCStrings ss' $ \css -> f (cs:css)

withCStringArray :: [String] -> (Ptr CString -> IO a) -> IO a
withCStringArray ss f = withCStrings ss $ \css -> withArray css f

withCStringArrayPtr :: [String] -> (Ptr (Ptr CString) -> IO a) -> IO a
withCStringArrayPtr ss f = withCStringArray ss $ \css -> with css f


-- Low-level function hooks.

{#fun PetscInitialize as internal_initialize
    {`Int', withCStringArrayPtr* `[String]', `String', `String'}
    -> `ErrCode'#}
{#fun PetscFinalize as finalize {} -> `ErrCode'#}


-- Better API for initialization.

initialize :: String -> String -> IO ErrCode
initialize file help = do
  args <- getArgs
  internal_initialize (length args) args file help

char ***への引数のマーシャリングを管理するのPetscInitializeは少し厄介なので、これは実際には C2HS で行うのはかなり難しい例ですが、アイデアは理解できます。他のほとんどのマーシャリング ケースは、はるかに簡単です。ポインターと配列の処理は、C 文字列のマーシャリングと同様に非常に簡単です。(C2HS を使用する場合は、喜んで質問にお答えします。)

これを取得したら、次のように呼び出すことができます。

-- This is Tst.hs or something...
module Main where

import PETSc

main :: IO ()
main = do
  res1 <- initialize "" ""
  print res1
  res2 <- finalize
  print res2

まだあまり役に立ちませんが、始めましょう。次のようにコンパイルします。

c2hs -C -I/opt/petsc/arch-linux2-cxx-opt/include PETSc.chs
ghc --make Tst.hs PETSc.hs -L/opt/petsc/arch-linux2-cxx-opt/lib/ -lpetsc

(必要に応じてパスを調整します、obvs)。

他の質問に答えるには:

  • unsafePerformIO呼び出している関数が「事実上純粋」であることが本当に確実でない限り、使用しないでください -PetscInitialize確かにその条件を満たしていません。モナドにすべてを直接入れたくない場合は、PETScモナドを一種の制限されたラッパーとして書くことができますが、PETSc に関して行っていることのほとんどは実際にはモナドの中にあります。 API 関数を呼び出して内部 PETSc 状態のビットを設定する必要があり、Haskell 関数の型でその有効性を捉える必要があります。IOIOIO

  • GHC で生成されたバイナリを で実行するmpirunことは問題になりません。

また、メイクファイルを作成することもありません。Cabal を使用すれば、これらすべてを問題なく実行できるはずです。

于 2015-03-29T16:56:42.997 に答える