Wie wird JIT-kompilierter Code in JVM angezeigt?

82

Gibt es eine Möglichkeit, den von der JIT erzeugten nativen Code in einer JVM anzuzeigen?

alsor.net
quelle
Möchten Sie wirklich den JIT-kompilierten (nativen) Code oder nur den Byte-Code sehen? Ich frage, weil das Stellen dieser Frage hier zu einigen Zweifeln führt, wenn Sie wirklich nativen Code sehen möchten ... Und leider kenne ich ein solches Tool auch nicht.
Gimpf
3
Ich möchte exakten JIT-kompilierten nativen Code sehen. Natürlich ist es nicht etwas, was ich tun muss, um meine Arbeit zu erledigen, sondern eine Art Experiment und Untersuchung von Dingen.
alsor.net
Kleine Frame-Herausforderung: Ein dynamischer Compiler, wie er in modernen JVMs verwendet wird, verfügt nicht nur über eine Version des kompilierten Codes. Es beginnt möglicherweise mit der Interpretation, kompiliert dann eine Methode oder nur einen Teil davon und kompiliert sie möglicherweise mehrmals neu, wenn Klassen geladen / entladen werden oder sich die Verwendungsmuster ändern oder auf Leistungsstatistiken basieren. (Ich denke, es kann sogar die kompilierte Version verwerfen und zum Interpretieren zurückkehren, wenn dies vorteilhaft erscheint.) Sie erhalten also möglicherweise nicht nur unterschiedlichen Code auf verschiedenen Computern, auch nicht für unterschiedliche Läufe auf demselben Computer, sondern zu unterschiedlichen Zeiten im selben Lauf .
gidds

Antworten:

45

Angenommen, Sie verwenden die Sun Hotspot-JVM (dh die von Oracle auf java.com bereitgestellte ), können Sie das Flag hinzufügen

-XX: + PrintOptoAssembly

wenn Sie Ihren Code ausführen. Dadurch wird der vom JIT-Compiler generierte optimierte Code ausgedruckt und der Rest weggelassen.

Wenn Sie den gesamten Bytecode einschließlich der nicht optimierten Teile anzeigen möchten, fügen Sie hinzu

-XX: CompileThreshold = #

wenn Sie Ihren Code ausführen.

Weitere Informationen zu diesem Befehl und der Funktionalität von JIT im Allgemeinen finden Sie hier .

Falaina
quelle
Ist diese Option nur in Debug-Builds oder so vorhanden? Da meine JVM ("Java (TM) SE-Laufzeitumgebung (Build 1.6.0_16-b01")) sie nicht erkennt, obwohl die Quelle im Web angibt, dass diese Funktion in Sun Java 6 und OpenJDK verfügbar ist.
Joachim Sauer
2
Ja, DEBUG-Binärdateien werden benötigt. blogs.warwick.ac.uk/richardwarburton/entry/…
alsor.net
3
Sollte das nicht (heutzutage) -XX: + PrintAssembly sein, zumindest heutzutage? Auf meinem Computer getestet und entspricht den hier genannten Informationen: wikis.sun.com/display/HotSpotInternals/PrintAssembly Vor dieser Option benötigen Sie -XX: + UnlockDiagnosticVMOptions und ein Disassembler-Plugin.
Blaisorblade
@Blaisorblade Ich erhalte: Falsch angegebene VM-Option 'PrintAssembly' Fehler: Die Java Virtual Machine konnte nicht erstellt werden. Fehler: Eine schwerwiegende Ausnahme ist aufgetreten. Das Programm wird geschlossen.
Koray Tugay
@KorayTugay Weitere Antworten anzeigen - Der aktualisierte Link lautet wikis.oracle.com/display/HotSpotInternals/PrintAssembly , wie in stackoverflow.com/a/15146962/53974 oder stackoverflow.com/a/4149878/53974 angegeben . Wenn das Befolgen der Anweisungen nicht funktioniert, fragen Sie bitte an einer geeigneten Stelle nach Details (nicht sicher, ob es sich um eine andere Frage für Ihren Fall handelt, die auf diese verweist).
Blaisorblade
76

Allgemeine Verwendung

Wie in anderen Antworten erläutert, können Sie mit den folgenden JVM-Optionen ausgeführt werden:

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

Filtern Sie nach einer bestimmten Methode

Sie können auch nach einer bestimmten Methode mit der folgenden Syntax filtern:

-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod

Anmerkungen:

  • Je nach Betriebssystem usw. müssen Sie möglicherweise das zweite Argument in Anführungszeichen setzen.
  • Wenn die Methode inline wird, können einige Optimierungen fehlen

Gewusst wie: Installieren Sie die erforderlichen Bibliotheken unter Windows

Wenn Sie Windows ausführen, finden Sie auf dieser Seite Anweisungen zum Erstellen und Installieren hsdis-amd64.dllsowie zu hsdis-i386.dllden erforderlichen Funktionen. Wir kopieren unten und erweitern den Inhalt dieser Seite * als Referenz:


Wo Sie vorgefertigte Binärdateien erhalten

Sie können vorgefertigte Binärdateien für Windows aus dem fcml- Projekt herunterladen

Wie man hsdis-amd64.dllund hsdis-i386.dllunter Windows baut

Diese Version des Handbuchs wurde unter Windows 8.1 64-Bit mit 64-Bit-Cygwin erstellt und erzeugt hsdis-amd64.dll

  1. Installieren Sie Cygwin . Fügen Sie auf dem Select PackagesBildschirm die folgenden Pakete hinzu (indem Sie die DevelKategorie erweitern und dann einmal auf die SkipBeschriftung neben jedem Paketnamen klicken ):

    • make
    • mingw64-x86_64-gcc-core(nur benötigt für hsdis-amd64.dll)
    • mingw64-i686-gcc-core(nur benötigt für hsdis-i386.dll)
    • diffutils(in UtilsKategorie)
  2. Führen Sie das Cygwin-Terminal aus. Dies kann über das vom Installationsprogramm erstellte Desktop- oder Startmenüsymbol erfolgen und erstellt Ihr Cygwin-Ausgangsverzeichnis ( C:\cygwin\home\<username>\oder C:\cygwin64\home\<username>\standardmäßig).

  3. Laden Sie das neueste GNU binutils-Quellpaket herunter und extrahieren Sie den Inhalt in Ihr Cygwin- Ausgangsverzeichnis . Zum Zeitpunkt des Schreibens ist das neueste Paket binutils-2.25.tar.bz2. Dies sollte zu einem Verzeichnis mit dem Namen binutils-2.25(oder der neuesten Version) in Ihrem Cygwin-Ausgangsverzeichnis führen.
  4. Laden Sie die OpenJDK-Quelle herunter , indem Sie das Repository für JDK 8-Updates aufrufen , das Tag auswählen, das Ihrer installierten JRE-Version entspricht, und auf bz2 klicken. Extrahieren Sie das Verzeichnis hsdis (gefunden in src\share\tools) in Ihr Cygwin- Ausgangsverzeichnis .
  5. Geben Sie im Cygwin Terminal ein cd ~/hsdis.
  6. Geben Sie zum Erstellen hsdis-amd64.dllein

    make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25

    Geben Sie zum Erstellen hsdis-i386.dllein

    make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25

    Ersetzen 2.25Sie in beiden Fällen die heruntergeladene binutils-Version. OS=Linuxist notwendig, da Cygwin zwar eine Linux-ähnliche Umgebung ist, das hsdis-Makefile es jedoch nicht als solches erkennt.

  7. Der Build schlägt mit Nachrichten ./chew: No such file or directoryund fehl gcc: command not found. Bearbeiten Sie <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefilein einem Texteditor wie Wordpad oder Notepad ++, um dies zu ändern SUBDIRS = doc po(Zeile 342, wenn Sie binutils 2.25 verwenden) SUBDIRS = po. Führen Sie den vorherigen Befehl erneut aus.

Die DLL kann jetzt installiert werden, indem Sie sie von hsdis\build\Linux-amd64oder hsdis\build\Linux-i586in Ihre JREs bin\serveroder Ihr bin\clientVerzeichnis kopieren . Sie können alle diese Verzeichnisse auf Ihrem System finden, indem Sie nach suchen java.dll.

Bonus-Tipp: Wenn Sie die Intel ASM-Syntax AT & T vorziehen, geben Sie diese zusammen -XX:PrintAssemblyOptions=intelmit anderen von Ihnen verwendeten PrintAssembly-Optionen an.

* Seitenlizenz ist Creative Commons

Assylien
quelle
1
Vorgefertigte Binärdateien für andere Plattformen - kenai.com/projects/base-hsdis/downloads
Ashwin Jayaprakash
@AshwinJayaprakash Wo soll ich diese Dateien in Mac OS ablegen?
Koray Tugay
@ KorayTugay legte sie in/usr/lib/
Jean-François Savard
Ich habe die Antwort durch Kopieren von der neuesten Version der verlinkten Seite aktualisiert, aber dies unterstreicht den Grund, warum wir im Allgemeinen auf externe Ressourcen verlinken, anstatt sie wörtlich zu kopieren.
Aleksandr Dubinsky
@AleksandrDubinsky Danke für das Update. Ich habe es absichtlich kopiert: Wenn diese Seite heruntergefahren wird, ist meine Antwort immer noch in sich geschlossen ...
Assylias
29

Sie benötigen ein hsdis-Plugin, um es zu verwenden PrintAssembly. Eine bequeme Wahl ist das auf der FCML-Bibliothek basierende hsdis-Plugin.

Es kann für UNIX-ähnliche Systeme kompiliert werden und unter Windows können Sie vorgefertigte Bibliotheken verwenden, die im FCML- Download- Bereich von Sourceforge verfügbar sind :

So installieren Sie unter Windows:

  • Extrahieren Sie die DLL (sie befindet sich in hsdis-1.1.2-win32-i386.zip und hsdis-1.1.2-win32-amd64.zip).
  • Kopieren Sie die DLL an einen beliebigen Ort java.dll(verwenden Sie die Windows-Suche). Auf meinem System habe ich es an zwei Stellen gefunden:
    • C:\Program Files\Java\jre1.8.0_45\bin\server
    • C:\Program Files\Java\jdk1.8.0_45\jre\bin\server

So installieren Sie unter Linux:

  • Quellcode herunterladen, extrahieren
  • cd <source code dir>
  • ./configure && make && sudo make install
  • cd example/hsdis && make && sudo make install
  • sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/lib/amd64/hsdis-amd64.so
  • sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/jre/lib/amd64/hsdis-amd64.so
  • Auf meinem System befindet sich das JDK in /usr/lib/jvm/java-8-oracle

Wie man es ausführt:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 
-XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code 
-jar fcml-test.jar

Zusätzliche Konfigurationsparameter:

Code Druckmaschinencode vor der Mnemonik.
Intel Verwenden Sie die Intel-Syntax.
gas Verwenden Sie die AT & T-Assembler-Syntax (GNU-Assembler-kompatibel).
dec Druckt IMM und Verschiebung als Dezimalwerte.
mpad = XX Auffüllen für den mnemonischen Teil der Anweisung.
cpad = XX Auffüllen des Maschinencodes.
seg Zeigt die Standardsegmentregister an.
Nullen HEX-Literalen werden führende Nullen angezeigt.

Die Intel-Syntax ist bei Windows eine Standardsyntax, während die AT & T-Syntax für GNU / Linux eine Standardsyntax ist.

Weitere Informationen finden Sie im FCML Library Reference Manual

swojtasiak
quelle
Danke, dass du die Bibliothek repariert hast. Es funktioniert auch unter Linux hervorragend. Ich lösche meine alten Kommentare, um die Unordnung gering zu halten.
Aleksandr Dubinsky
Unter Linux, nachdem ich die Datei libhsdis.so installiert und einen Softlink zu hsdis-amd64.so erstellt habe, führe ich den Befehl java aus. Prmpts kann hsdis-amd64.so nicht finden. Ich starte neu und führe dann Java erneut aus, es ist in Ordnung. Wie vermeide ich einen Neustart, damit der Softlink sofort funktioniert? Ausloggen?
Gfan
2
Nur eine kleine Ergänzung: Auf einigen Linux-Distributionen können Sie einfach ein Paket installieren, zum Beispiel in Ubuntu: apt-get install libhsdis0-fcml( askubuntu.com/a/991166/489909 ). Dies selbst zu erstellen ist möglicherweise nicht erforderlich.
David Georg Reichelt
8

Für die HotSpot (war Sun) JVM auch in Produktmodi:

http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly

Einige Montage erforderlich: Es benötigt ein Plugin.

John Rose
quelle
Es scheint, dass der Link in Ihrer Antwort weg ist. Würden Sie ihn bitte aktualisieren? Vielen Dank im Voraus.
Chaojun Zhong
5

Ich glaube, WinDbg wäre hilfreich, wenn Sie es auf einem Windows-Computer ausführen. Ich habe gerade ein Glas laufen lassen.

  • Dann habe ich über Windbg an den Java-Prozess angehängt
  • Untersuchte Threads mit dem Befehl ~ ; Es gab 11 Threads, 0 Thread war der Hauptarbeitsthread
  • Auf 0-Thread umgeschaltet - ~ 0s
  • Durch einen nicht verwalteten Callstack von kb geschaut gab es:

    0008fba8 7c90e9c0 ntdll! KiFastSystemCallRet
    0008fbac 7c8025cb ntdll! ZwWaitForSingleObject + 0xc
    0008fc10 7c802532 kernel32! WaitForSingleObjectEx + 0xa8
    0008fc24 00403a13 kernel32! WaitForSingleObject + 0x12
    0008fc40 00402f68 java + 0x3a13
    0008fee4 004087b8 java + 0x2f68
    0008ffc0 7c816fd7 java + 0x87b8

    0008fff0 00000000 kernel32! BaseProcessStart + 0x23

Hervorgehobene Zeilen führen direkt JIT-Code auf JVM aus.

  • Dann können wir nach der Methodenadresse suchen:
    Java + 0x2f68 ist 00402f68

  • In WinDBG:
    Klicken Sie auf Ansicht -> Demontage.
    Klicken Sie auf Bearbeiten -> Gehe zu Adresse.
    Setzen Sie 00402f68 dort
    und bekam

    00402f68 55 push ebp
    00402f69 8bec mov ebp, esp
    00402f6b 81ec80020000 sub esp, 280h
    00402f71 53 push ebx
    00402f72 56 push esi
    00402f73 57 push edi
    ... und so weiter

Weitere Informationen finden Sie im Beispiel zum Zurückverfolgen von JIT-ed-Code aus Speicherabbildern mithilfe von Process Explorer und WinDbg.

Andriy Tkach
quelle
4

Eine andere Möglichkeit, Maschinencode und einige Leistungsdaten anzuzeigen, ist die Verwendung von CodeDnalyst oder OProfile von AMD, die über ein Java-Plugin verfügen, um die Ausführung von Java-Code als Maschinencode zu visualisieren.

Ian
quelle
0

Drucken Sie die Baugruppe Ihrer Hotspots mit den Perfasm-Profilern ( LinuxPerfAsmProfileroder WinPerfAsmProfiler) von JMH . JMH benötigt die hsdisBibliothek, da sie darauf angewiesen ist PrintAssembly.

Aleksandr Dubinsky
quelle