2012-07-24 7 views
8

私はJavaが安全な言語だと知っていますが、行列の計算が必要な場合は、もっと速く試すことができますか?Javaでのコードの挿入/アセンブリのインライン化?

私はC++、Digital-Marsコンパイラ、FASMで__asm {}を学んでいます。私はJavaで同じことをしたい。関数内でアセンブリコードをインライン化するにはどうすればよいですか?これも可能ですか?このような

サムシング(ベクトル化されたループは、CPUのAVXのサポートを使用して、分岐せずに値を配列のすべての要素をクランプする):

JavaAsmBlock(
    # get pointers into registers somehow 
    # and tell Java which registers the asm clobbers somehow 
    vbroadcastss twenty_five(%rip), %ymm0 
    xor %edx,%edx 
.Lloop:       # do { 
    vmovups (%rsi, %rdx, 4), %ymm1 
    vcmpltps %ymm1, %ymm0, %ymm2 
    vblendvps %ymm2, %ymm0, %ymm1, %ymm1 
    vmovups %ymm1, (%rdi, %rdx, 4) 
    # TODO: unroll the loop a bit, and maybe use aligned loads/stores in the main loop 
    add   $32, %rdx 
    cmp   %rcx, %rdx 
    jb  .Lloop     # } while(idx < count) 
); 

System.out.println(var[0]); 

私は、コード・インジェクターを使用する必要はありません。私はインテルまたはAT & Tスタイルのx86命令を見たいと思っています。

+0

あなたがそのようなASM書いている場合は(代わりに 'SHRのAl 4によって16ビットレジスタをと' div'を使用して、2 ')、[間違いなく* * Cコンパイラができたものよりも速くなることはないだろうあなたのために作る。](https://stackoverflow.com/questions/40354978/why-is-this-c-code-faster-than-my-hand-written-assembly-for-testing-the-collat​​/40355466# 40355466)、CまたはC++でJNIを使​​用するだけです。 ASMは、現在のCPUのマイクロアーキテクチャをチューニングする方法を知っている場合にのみ、パフォーマンスに役立ちます。これは便利な質問ですが、例は大部分の人が* asmを使用すべきでない理由の例です。 –

+0

あなたは正しいです。同時に2つのこと。私は、その時点で十分な経験があれば、AVXのドットプロダクトのようなものを適切な命令の順序で追加します。 –

+0

質問を編集して、何か近代的なものを使うことができます。 BMI2の 'pdep'のように、Javaの組み込み関数がありません。理想的には、あなたがCコンパイラを簡単に手に入れることができないようなものを考え出すことができます。 –

答えて

13

Javaコードとその基礎となるハードウェアの間に抽象レイヤーがあり、この種のことを原則不可能にします。同じバイトコードを異なるプロセッサーや異なるアーキテクチャーで実行できるため、技術的には、コードが基盤となるマシンでどのように表現されているかを知ることはできません。

あなたは正式にになります。は、Javaコードからネイティブコードを呼び出すためにJava Native Interface(JNI)を使用しています。呼び出しのオーバーヘッドは相当なもので、Javaとのデータ共有はかなり高価なので、ネイティブコードのかなりのサイズのチャンクにのみ使用してください。

理論上、このような拡張は可能です。特定のプラットフォームをターゲットとし、アセンブリのエスケープを許可するJavaコンパイラを想像することができます。コンパイラはABIを公開しなければならないので、呼び出し規約を知ることができます。しかし、私はそのことを知らない。しかし、Javaをネイティブコードに直接コンパイルするのはseveralcompilersavailableです。そのうちの1人が私の知らないうちにこのようなものをサポートする可能性があります。

最後に、全く別のレベルに、JVMのバイトコードアセンブラがあり、Jasmin.のようなバイトコードのアセンブラは、あなたが直接JVMをターゲットに「機械コード」を書くことができます、そして時にはすることができますjavacコンパイラより良いコードを書くことができます生成する。どんな場合でも、遊ぶのは楽しいです。

+0

●バイトコード・アセンブラも試してみる –

+2

先行するJavaからネイティブ・コード・コンパイラまで、[Excelsior JET](http://www.excelsiorjet.com)のみがJNIを実装しています。[GCJ](http:// gcc .gnu.org/java /)は、JNIと[CNI](http://gcc.gnu.org/onlinedocs/gcj/About-CNI.html)という独自のインターフェースの両方をサポートしています。 –

2

Javaから直接アセンブリを呼び出すことはできません。しかし、JNI経由でCコードを呼び出すことができ、そこからアセンブリを呼び出すことができます。

This article shows how.

+0

非常にいいです。私はそれを試みます。私はデジタル火星コンパイラを使用しています。 __asmで可能だと思いますか? Nwm私は自分自身を試してみます。ありがとう –

+0

私が覚えている限り、あなたは好きなCコンパイラを使うことができます。 javaは単にプラットフォームabiを使用します。 –

+0

C ABIの後に続く関数をC関数と同じように呼び出すことができます。基本的には、JNIと互換性を持たせるためにC関数内で何をしていても、asmで行うことができます。 –

1

あなたはJNIまたはJNAを使用して、Javaからネイティブ関数を呼び出します。代わりに、バイトコードをInputStreamとしてJavaクラスを作成します。

1

Aparapiもご覧ください。

+0

はGPUの並列プログラミングではありませんか? –

+3

はい。行列計算をより速く行う方法を尋ねなかったのですか? –

2

Machine Level Java技術を使用してJavaからアセンブリを呼び出すことは可能です。これは、Javaで書かれたアセンブリコードを透過的にパックしますが、最も使用されているアセンブリ構文とよく似ています。次に、同じクラスで定義したネイティブメソッドを呼び出すだけで、アセンブリが記述されます。したがって、常にJava環境内に留まり、Java IDEからいくつかのアセンブリツールに切り替えてからJavaに戻る必要はありません。

+0

ドキュメントの欠如を示唆しているAPIのようです。詳細をお知らせください。 –

+0

jniよりもAPI /インターフェイス待ち時間が短いですか? –

5

Javaコードでアセンブリを直接インライン化することはできません。それにもかかわらず、他のいくつかの答えによって主張されているものとは対照的に、中間的なC(またはC++)層を経由せずに便利にアセンブリを呼び出すことは可能です。

チュートリアル

は、次のJavaクラスを考えてみましょう:

public class MyJNIClass { 

    public native void printVersion(); 

} 

主なアイデアは、JNIの命名規則を使用してシンボルを宣言することです。この場合、アセンブリコードで使用する変更された名前はJava_MyJNIClass_printVersionです。このシンボルは、例えば、FASMでpublicディレクティブまたはNASMでglobalディレクティブを使用して達成することができる他の翻訳単位、から見えなければなりません。

は、ターゲットアーキテクチャ(引数は、他のメモリ構造などで、スタック上、レジスタに渡されることもある)の呼び出し規約を使用してアセンブリコードを記述します。アセンブリ関数に渡される最初の引数は、JNIEnvへのポインタで、それ自体がJNI関数テーブルへのポインタです。これを使用してJNI関数を呼び出します。例えば、NASMを用いたとx86_64を標的:JNI機能のため

global Java_MyJNIClass_printVersion 

section .text 

Java_MyJNIClass_printVersion: 
    mov rax, [rdi] 
    call [rax + 8*4] ; pointer size in x86_64 * index of GetVersion 
    ... 

インデックスはJava documentationに見られます。 JNI関数テーブルは基本的にポインタの配列なので、これらのインデックスに対象アーキテクチャのポインタのサイズを掛けることを忘れないでください。

あなたのアセンブリ関数に渡された二番目の引数は、呼び出し元のJavaクラスまたはオブジェクトへの参照です。後続の引数はすべてネイティブJavaメソッドのパラメータです。

最後に、コードをアセンブルしてオブジェクトファイルを生成し、そのオブジェクトファイルから共有ライブラリを作成します(GCCはこの最後のステップをgcc -shared -o ...のようなコマンドで実行できます)。

は私がfully runnable example on GitHubを作成している例

を実行すると、見て、より良い理解を得るためにそれで遊んで気軽に。

+0

これはJNI C++よりもさらに深刻ですか? –

+0

これは、CまたはC++と同じJNI実装を使用していますが、下位レベルからはそうです。 ;-) – Pyves

+1

あなたは 'mov rax、[rdi]'/'call [rax + 8 * 4]'と書くことができました。 x86アドレッシングモードは余分な命令より効率的です。メモリ間接呼び出しはload + callより高速ではありませんが、速度が遅くなく、コードサイズとデコード帯域幅が節約されます。 (実際にはhttp://agner.org/optimize/によると、AMDでは2μop以上であり、DirectPathではなくVectorPath(マイクロコード化)を意味するため、AMDでは速度が遅くなる可能性があります。 、[rdi] '/' mov rax、[rax + 8 * 4] '/' call rax'まだADD命令はない、それはいつも悪い) –

関連する問題