Code-Injektion/Montage inlining in Java?
Ich weiß, Java ist eine sichere Sprache, aber bei matrix-Berechnungen erforderlich sind, kann ich versuchen, etwas schneller?
Ich Lerne __asm{} in C++, Digital Mars-compiler und FASM. Ich möchte das gleiche zu tun in Java. Wie kann ich den inline Assembler codes in Funktionen? Ist das überhaupt möglich?
So etwas (ein Vektorgrafik-Schleife Klammer, die alle Elemente eines Arrays zu einem Wert ohne Verzweigung, mit AVX-Unterstützung von CPU):
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 # TODO: use vminps instead
vmovups %ymm1, (%rdi, %rdx, 4)
# TODO: unroll the loop a bit, and maybe handle unaligned output specially if that's common
add $32, %rdx
cmp %rcx, %rdx
jb .Lloop # } while(idx < count)
vzeroupper
);
System.out.println(var[0]);
Ich nicht wollen, verwenden Sie einen code-injector. Ich möchte, um zu sehen, die auf Intel-oder AT&T Stil x86-Anweisungen.
- Wenn Sie asm schreiben, wie das (16-bit-Register und mit
div
von 4 statt einershr al, 2
), it definitiv nicht dabei, schneller zu sein als das, was ein C-compiler machen könnte für Sie., so sollten Sie nur verwenden JNI mit C oder C++. ASM ist nur sinnvoll, wenn Leistung, wenn Sie wissen, wie die Melodie für die Mikroarchitektur des aktuellen CPUs. Dies ist eine sinnvolle Frage, aber das Beispiel ist ein Beispiel, warum die meisten Menschen nicht verwenden, asm. - Du hast Recht. Zwei Dinge zur gleichen Zeit. Ich würde hinzufügen, so etwas wie eine AVX-dot-Produkt mit der richtigen Reihenfolge von Anweisungen, die, wenn ich hatte genug Erfahrungen in dieser Zeit.
- Sie Bearbeiten die Frage etwas zu benutzen moderne. Wie vielleicht BMI2
pdep
, die keine Java-immanent. Im Idealfall könnte man sich was einfallen lassen, Sie konnte nicht einfach wie leicht erhalten Sie einen C-compiler zu Strahlen für Sie, obwohl. - Ich hatte Intels opencl-c-compiler erstellen Sie eine astfreie "vektorisiert Klemme 25.0 f" Verfahren und stellen nur ein Teil der hier(codeshare.io/29pqeB). Würden Sie mir, es zu betrachten? Sollte ich hinzufügen, vollständigen code, oder ist es umleiten Grundgedanke der Frage nach irgendwo anders?
- Ich fixierte Ihre asm beinhalten die aktuelle Schleife, anstatt nur den Schleifen-overhead, aber keine Niederlassung. Und optimiert und es etwas, was Sie wirklich wollen, zu verwenden für hohe Leistung. Sie verwendet eine signierte 32-bit-Schleifenzähler in einer Weise, dass der compiler gezwungen zu Unterschreiben-erweitern Sie es innerhalb der Schleife bei jeder iteration.
- Ich danke Ihnen sehr. Eigentlich habe ich das nicht gesagt-compiler darüber, wie viele(die sollte Vielfaches von 8 und große) Elemente verarbeitet werden sollen. Es hat gewählt, es irgendwie mit Annahme der Prozessor ist ein Intel und Elemente sind weniger als 4G? Ich bin mit fx8150.
- Nun, die einzige Quelle, die Sie enthalten, wurde eine Funktion für die 8 Schwimmer aus dem Speicher. Es ist bis zu Sie, um es in einer Schleife. Und was macht Sie denken, dass Sie beschlossen, zu optimieren speziell für die Intel? Splitting-256b-stores ist gut für Pfahlramme, auch wenn Sie ausgerichtet ist, weil der CPU-performance-bug oder etwas mit AVX-Shops. Wenn tuning speziell für Pfahlramme, vielleicht nur mithilfe von XMM-Anleitung wäre noch besser gewesen, aber das compiler-Ausgabe wäre ok. Eh, das asm in der Frage ist jetzt eine gute Allgemeine Beispiel nicht ablenken Leser mit jeder uarch tuning.
- Es war eine Warnung in der Dokumentation, dass es ist optimiert für Intel nur, aber der erzeugte code ist so schnell, wie ich brauche, zumindest. Dies ist ein "code-generator"-add-on für visual studio von Intel.
- Die codeshare-link hat eine
.ident "clang version 3.6.2 "
Linie. Also vermutlich bist du mit einem alten clang version. - Ich wusste nicht, Intel war mit clang für opencl-compiler 🙂 Vielleicht ist es besser als gcc-6.x, die widerstanden zu kompilieren, wie ich muss(unter linux zumindest, aber jetzt bin ich auf windows).
- Oder ist das Geräusch bereits in windows(irgendwie vorinstalliert mit windows) und verwendet es, genau wie ubuntu hatte gcc standardmäßig?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist ein Abstraktions-layer zwischen Ihrem Java-code und der zugrunde liegenden hardware, die diese Art der Sache grundsätzlich unmöglich; Sie technisch nicht wissen kann, wie der code dargestellt wird auf der zugrunde liegenden Maschine, da der gleiche bytecode kann auf verschiedenen Prozessoren und unterschiedlichen Architekturen.
Was Sie offiziell kann tun ist, verwenden Sie die Java Native Interface (JNI) zu nennen, native code aus Java-code. Der Aufruf-overhead ist wesentlich, und gemeinsame Nutzung von Daten mit Java ist ziemlich teuer, so sollte dies nur verwendet werden, für die decent-sized chunks von nativen code.
In der Theorie, wie eine Erweiterung sollte möglich sein. Man kann sich vorstellen, einen Java-compiler, die gezielt eine bestimmte Plattform und erlaubt die Montage entweicht. Der compiler hätte die Veröffentlichung Ihrer ABI, so würden Sie wissen, die Aufrufkonventionen. Ich bin mir nicht bewusst, dass es jedoch tun. Aber es gibt mehrere Compiler verfügbar kompilieren von Java direkt in systemeigenen code; es ist möglich, einer von Ihnen unterstützt so etwas ohne mein wissen, oder könnte erweitert werden, um so zu tun.
Schließlich, auf einer anderen Ebene zusammen, es gibt bytecode-Assembler für die JVM, wie Jasmin. Eine bytecode-assembler können Sie schreiben "Computer-code", der auf das JVM direkt, und manchmal kann man besseren code zu schreiben, als die
javac
compiler generieren kann. Es macht Spaß mit zu spielen, in jedem Fall.Get*Critical
Funktionen operieren direkt auf dem zugrunde liegenden array).Können Sie direkt von inline-assembly in Ihrem Java-code. Dennoch, im Gegensatz zu dem, was behauptet wird, von einigen anderen Antworten, die bequem aufrufen Montage ohne Umweg über Zwischenhändler C (oder C++) - Ebene ist möglich.
Schnelldurchgang
Betrachten Sie die folgende Java-Klasse:
Die Idee dabei ist, deklarieren Sie ein symbol mit Hilfe der JNI naming convention. In diesem Fall, der verstümmelte name zu verwenden, in deinem Assembler-code ist
Java_MyJNIClass_printVersion
. Dieses symbol muss sichtbar sein, aus anderen übersetzungseinheiten, die beispielsweise dadurch erzielt werden, dass diepublic
Richtlinie in FASM oder dieglobal
Richtlinie in NASM. Wenn Sie auf macOS, prepend einen zusätzlichen Unterstrich vor dem Namen.Schreiben Sie Ihren Assembler-code, der mit dem Aufruf-Konventionen der angestrebten Architektur (Argumente können in Registern übergeben werden, auf dem stack, in andere Speicher-Strukturen, etc.). Die ersten argument übergeben Sie Ihre assembly-Funktion ist ein Zeiger auf
JNIEnv
, die selbst einen Zeiger auf die JNI-Funktion-Tabelle. Es verwenden, um Anrufe zu tätigen, um JNI-Funktionen. Zum Beispiel der NASM-und targeting-x86_64:Indizes für die JNI-Funktionen finden Sie in der Java-Dokumentation. Als die JNI-Funktion-Tabelle ist im Grunde ein array von Zeigern, vergessen Sie nicht, vermehren sich diese Indizes durch die Größe eines Zeigers in der gezielten Architektur.
Dem zweiten argument übergeben Sie Ihre assembly-Funktion ist eine Referenz auf das aufrufende Java-Klasse oder ein Objekt. Alle nachfolgenden Argumente sind die Parameter der nativen Java-Methode.
Schließlich, stellen Sie Ihre code zu generieren, eine Objekt-Datei, und erstellen Sie dann eine shared library, die das Objekt Datei. GCC und Clang können führen Sie diesen letzten Schritt mit einem Befehl ähnlich
gcc/clang -shared -o ...
.Zusätzliche Ressourcen
Einer umfassenderen Komplettlösung ist verfügbar in dieser Artikel DZone. Ich habe auch eine voll lauffähigen Beispiel auf GitHub, fühlen Sie sich frei, um einen Blick zu nehmen und spielen, um mit ihm auch zu einem besseren Verständnis.
mov rax, [rdi]
/call [rax + 8*4]
. x86-Adressierungsmodi sind effizienter als extra-Anweisungen. Speicher-indirekten Aufruf ist nicht schneller als laden + nennen, aber es ist nicht langsamer und spart code-Größe und-Dekodierung Bandbreite. (Hmm, eigentlich laut agner.org/optimize, es könnte langsamer auf AMD, da es mehr als 2 uops und das bedeutet, dass VectorPath (microcoded), nicht DirectPath. Wenn die Optimierung für AMD, vielleichtmov rax, [rdi]
/mov rax, [rax + 8*4]
/call rax
. Noch kein ADD-Anweisung, die immer schlimmer)Ist es möglich, die assembly aufrufen von Java mit der Maschine Java Technologie. Es transparent packs Ihre Assembler-code, der in Java geschrieben, aber sehr ähnlich zu den am häufigsten verwendeten assembly-syntax, in eine native Bibliothek. Und weiter, Sie einfach nur aufrufen müssen, die eine native-Methode, definieren Sie in der gleichen Klasse, wo Ihre Versammlung ist geschrieben. Also, Sie bleiben immer innerhalb der Java-Umgebung und haben keine Notwendigkeit zum Umstieg von Java IDE, um einige Montage-Werkzeuge und dann wieder zurück zu Java.
Du per JNI oder JNA und rufen Sie Ihren systemeigenen Funktionen von Java. Oder als alternative, Sie haben bytecode als InputStream und machen Sie eine Java-Klasse heraus.
Möglicherweise möchten Sie auch einen Blick auf Aparapi.
Kann man nicht nennen assembly direkt aus Java. Aber Sie können den Aufruf von C-code über JNI, und von dort aus können Sie die assembly aufrufen.
Dieser Artikel zeigt, wie.