0

JNA を使用して C ライブラリーを Java コードにバインドしようとしていますが、パフォーマンスが非常に低下します。

ここにCヘッダーファイルがあります

struct facet_fin_s {
 int facet;
 int fin;
};
typedef struct facet_fin_s facet_fin_t;

struct tab_facet_fin_s {
 facet_fin_s *data;
 int length;
};
typedef struct tab_facet_fin_s tab_facet_fin_t;

struct facet_s{
 int number_of_fins;
 tab_facet_fin_s tab_facet_fin;
};
typedef struct facet_s facet_t;

extern "C" __declspec(dllexport) void getFins(facet_t* const );

ここにCファイルがあります

void getFins(facet_t* const facet)
{
    facet->number_of_fins = 258246;
    facet->tab_facet_fin.length = facet->number_of_fins;
    facet->tab_facet_fin.data = (facet_fin_s*)malloc(sizeof(facet_fin_s) * facet->tab_facet_fin.length);
    memset(facet->tab_facet_fin.data, 0, sizeof(facet_fin_s) * facet->tab_facet_fin.length);

    int loop = 0;
    for (loop=0; loop<facet->tab_facet_fin.length; loop++)
    {
        facet_fin_s fin;
        fin.facet = loop;
        fin.fin = loop;
        facet->tab_facet_fin.data[loop] = fin;
    }
}

そして最後にJavaでの私のテスト

facet_s retFacet = new facet_s();

TestJNABindingLibrary.getFins(retFacet);

Structure facetFin[] = retFacet.tab_facet_fin.data.toArray(retFacet.tab_facet_fin.length);

for (int i = 0; i < facetFin.length; i++)
{
    System.out.println(((facet_fin_s)facetFin[i]).fin);
    System.out.println(((facet_fin_s)facetFin[i]).facet);
}

関数 getFins によって返される結果は正しいですが、操作は非常に遅いです。retFacet.tab_facet_fin.data で「toArray」を呼び出すのに 38 秒かかることがわかりました。

JNA は、Java 構造をネイティブ構造と同期してデータをコピーするのに時間がかかりすぎていると思います。

Byte 配列と ByteBuffer をコピーせずにメモリに直接アクセスしようとしましたが、これらのメソッドは構造体ではなくプリミティブ オブジェクトに便利です。また、データに簡単にアクセスするためにポインターをいじってみましたが、成功しませんでした。

私の目標は、パフォーマンスを向上させながら、Java コードを明確で操作しやすい状態に保つ方法を見つけることです (プロジェクトにはこれらの関数がたくさんあります)。JNA でそれを達成する方法はありますか? (私はすでにJNI、SWIG、およびBridJを検討しています..)。いくつかのコードは大歓迎です ;-)

ありがとう

編集

これは、自動同期を無効にしてフィールドを読み取ろうとする私の試みです

facet_s retFacet = new facet_s();
retFacet.setAutoSynch(false);
TestJNABindingLibrary.getFins(retFacet);
facet_fin_s[] fins = (facet_fin_s[])retFacet.tab_facet_fin.readField("data");

残念ながらfinsnull

編集2

テクノメイジは、私がtab_facet_fin最初に読まなければならないと言った。しかし、結果を配列として取得することはまだできません。

tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
facet_fin_s[] fins = (facet_fin_s[])tab.readField("data");

キャスト例外を発生させます。このフィールドを簡単に読み取る方法はありますか?

編集3

テクノメイジのおかげで、readField攻略を一通りやってみました。dataが であるかであるPointerかに応じて、データを取得する方法は 2 つありますStructure.ByReference

ここに共通部分があります(各JavaクラスはsetAutoSynch(false)コンストラクターで呼び出します)

facet_s retFacet = new facet_s();
TestJNABindingLibrary.getFins(retFacet);

それからPointerケース

int length = (int)retFacet.readField("number_of_fins");
tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
int[] data = new int[length*2];
tab.data.read(0, data, 0, data.length);
for (int i = 0; i < data.length; i++)
{
   System.out.println(data[i]);
}

またはStructure.ByReferenceケース。

tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
facet_fin_s s = (facet_fin_s)tab.readField("data");
facet_fin_s[] data = (facet_fin_s[])s.toArray(length);
for (int i = 0; i < data.length; i++)
{
   System.out.println(data[i].fin);
   System.out.println(data[i].facet);
}

今私の意見:

  • このreadField戦略は、パフォーマンスを最適化し、無駄なコピーを避けるための良い方法かもしれません。これは良いトリックかもしれませんが、構造体には読み取りたいデータしかないため、ここでは関係ありません。プロジェクトの他の構造体に読み取りたくないデータが含まれている場合は、それを決定的に使用します。

  • Pointer ケース: 残念ながら、JNAerator は my dataasStructure.ByReferenceと notを自動的に生成しますPointer。しかし、これらを取得したとしましょうPointer。次に、データ内の int 値に非常に高速にアクセスできます。私が間違っていなければ、この方法は を呼び出すのとまったく同じPointer.getIntArrayです。ここに 2 つの問題があります。facet_fin_sまず、 Java でクラスを作成する利点を完全に失います。データの解析方法は問題ありませんが、あまり便利ではありません。次に、構造体facet_fin_sが他のタイプのメンバーを持っている場合 (これは、バインドしようとしているライブラリの一部の構造体の場合です)、この戦略は無関係です。

  • Structure.ByReference の場合: ここでの良い点は、データを の配列として取得することですfacet_fin_s。これは、コードの可読性にとって良い点です。残念ながら、Structure.toArrayデータにアクセスするためにこれを使用する必要があるため、最初の問題に戻ります。この関数は、ネイティブ メモリから Java メモリへのメモリのコピーを作成します。大量のデータの場合、この関数は非常に遅くなります。

JavaまたはCコードを完全に書き直すことなく、ネイティブメモリデータを非常に高速に読み取り、元の「アーキテクチャ」を維持する方法は本当にありますか?

  • C 構造体を表す Java クラスを使い続ける
  • JNAerator のみを使用できるように、Java または C で多くのツールまたはクラスを書き直すことはできるだけ避けてください。
  • ネイティブ メモリへの高速で読み取り可能なアクセス、またはネイティブ メモリから Java メモリへの高速コピー

私はJNAの限界に直面していると思います...

4

1 に答える 1