Angenommen, der Engpass meines Java-Programms besteht in einigen engen Schleifen, um eine Reihe von Vektorpunktprodukten zu berechnen. Ja, ich habe ein Profil erstellt, ja, es ist der Engpass, ja, es ist signifikant, ja, so ist der Algorithmus, ja, ich habe Proguard ausgeführt, um den Bytecode zu optimieren usw.
Die Arbeit besteht im Wesentlichen aus Punktprodukten. Wie in habe ich zwei float[50]
und ich muss die Summe der paarweisen Produkte berechnen. Ich weiß, dass Prozessorbefehlssätze existieren, um diese Art von Operationen schnell und in großen Mengen auszuführen, wie z. B. SSE oder MMX.
Ja, ich kann wahrscheinlich darauf zugreifen, indem ich nativen Code in JNI schreibe. Der JNI-Anruf erweist sich als ziemlich teuer.
Ich weiß, dass Sie nicht garantieren können, was eine JIT kompiliert oder nicht kompiliert. Hat jemand jemals von einem JIT-Generierungscode gehört, der diese Anweisungen verwendet? Und wenn ja, gibt es irgendetwas an dem Java-Code, das dazu beiträgt, ihn auf diese Weise kompilierbar zu machen?
Wahrscheinlich ein "Nein"; es lohnt sich zu fragen.
quelle
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation
. Sie benötigen ein Programm, das die vektorisierbare Methode so oft ausführt, dass sie "heiß" wird.Antworten:
Grundsätzlich möchten Sie, dass Ihr Code schneller ausgeführt wird. JNI ist die Antwort. Ich weiß, dass du gesagt hast, dass es bei dir nicht funktioniert hat, aber ich möchte dir zeigen, dass du falsch liegst.
Hier ist
Dot.java
:und
Dot.h
:Mit diesem Befehl können wir das mit JavaCPP kompilieren und ausführen :
Mit einer Intel (R) Core (TM) i7-7700HQ-CPU bei 2,80 GHz, Fedora 30, GCC 9.1.1 und OpenJDK 8 oder 11 erhalte ich diese Art von Ausgabe:
Oder ungefähr 2,4 mal schneller. Wir müssen direkte NIO-Puffer anstelle von Arrays verwenden, aber HotSpot kann genauso schnell wie Arrays auf direkte NIO-Puffer zugreifen . Andererseits führt das manuelle Abrollen der Schleife in diesem Fall nicht zu einer messbaren Leistungssteigerung.
quelle
Um einige der hier von anderen geäußerten Skepsis anzusprechen, schlage ich jedem vor, der sich selbst oder anderen beweisen möchte, die folgende Methode anzuwenden:
Beispiel:
Das Ergebnis mit und ohne Flag (auf dem aktuellen Haswell-Laptop Oracle JDK 8u60): -XX: + UseSuperWord: 475,073 ± 44,579 ns / op (Nanosekunden pro op) -XX: -UseSuperWord: 3376,364 ± 233,211 ns / op
Die Assembly für die Hot-Loop ist ein bisschen viel zu formatieren und hier zu bleiben, aber hier ist ein Ausschnitt (hsdis.so kann einige der AVX2-Vektoranweisungen nicht formatieren, daher habe ich -XX: UseAVX = 1 ausgeführt): -XX: + UseSuperWord (mit '-prof perfasm: intelSyntax = true')
Viel Spaß beim Stürmen der Burg!
quelle
In HotSpot-Versionen, die mit Java 7u40 beginnen, bietet der Server-Compiler Unterstützung für die automatische Vektorisierung. Laut JDK-6340864
Dies scheint jedoch nur für "einfache Schleifen" zu gelten - zumindest für den Moment. Beispielsweise kann das Akkumulieren eines Arrays noch nicht vektorisiert werden. JDK-7192383
quelle
Hier ist ein schöner Artikel über das Experimentieren mit Java- und SIMD-Anweisungen, den mein Freund geschrieben hat: http://prestodb.rocks/code/simd/
Das allgemeine Ergebnis ist, dass Sie davon ausgehen können, dass JIT in 1.8 einige SSE-Operationen verwendet (und in 1.9 weitere). Sie sollten jedoch nicht viel erwarten und müssen vorsichtig sein.
quelle
Sie können den OpenCl-Kernel schreiben, um die Datenverarbeitung durchzuführen, und ihn unter Java http://www.jocl.org/ ausführen .
Code kann auf CPU und / oder GPU ausgeführt werden, und die OpenCL-Sprache unterstützt auch Vektortypen, sodass Sie z. B. SSE3 / 4-Anweisungen explizit nutzen können sollten.
quelle
Schauen Sie sich den Leistungsvergleich zwischen Java und JNI an, um eine optimale Implementierung von rechnergestützten Mikrokernen zu erhalten . Sie zeigen, dass der Java HotSpot VM-Server-Compiler die automatische Vektorisierung mithilfe der Super-Word-Level-Parallelität unterstützt, die auf einfache Fälle von Parallelität innerhalb der Schleife beschränkt ist. In diesem Artikel erfahren Sie auch, ob Ihre Datengröße groß genug ist, um eine JNI-Route zu rechtfertigen.
quelle
Ich vermute, Sie haben diese Frage geschrieben, bevor Sie von netlib-java erfahren haben.
quelle
Ich glaube nicht, dass die meisten VMs jemals intelligent genug für diese Art von Optimierungen sind. Um fair zu sein, sind die meisten Optimierungen viel einfacher, z. B. Verschieben statt Multiplizieren bei einer Zweierpotenz. Das Mono-Projekt führte einen eigenen Vektor und andere Methoden mit nativen Backings ein, um die Leistung zu verbessern.
quelle