Czy na pewno chcesz zobaczyć kod skompilowany przez JIT (natywny), czy tylko kod bajtowy? Pytam, ponieważ zadawanie tego pytania tutaj rodzi wątpliwości, czy naprawdę chcesz zobaczyć kod natywny ... I przepraszam, też nie znam takiego narzędzia.
gimpf
3
Chcę zobaczyć kod natywny skompilowany dokładnie w JIT. Oczywiście to nie jest coś, czego potrzebuję do wykonania pracy, raczej rodzaj eksperymentów i badań.
alsor.net
Drobne wyzwanie związane z ramkami: dynamiczny kompilator używany we współczesnych maszynach JVM nie ma tylko jednej wersji skompilowanego kodu; może rozpocząć interpretację, a następnie skompilować metodę lub tylko jej część, a następnie potencjalnie przekompilować ją wiele razy, gdy klasy są ładowane / usuwane lub zmieniają się wzorce użycia lub w oparciu o statystyki wydajności. (Myślę, że może nawet odrzucić skompilowaną wersję i powrócić do interpretacji, jeśli wydaje się to korzystne). Więc możesz nie tylko uzyskać inny kod na różnych maszynach, ani nawet dla różnych uruchomień na tej samej maszynie, ale w różnym czasie w tym samym przebiegu .
gidds
Odpowiedzi:
45
Zakładając, że używasz maszyny wirtualnej Sun Hotspot JVM (tj. Tej dostarczonej na java.com przez Oracle), możesz dodać flagę
-XX: + PrintOptoAssembly
podczas uruchamiania kodu. Spowoduje to wydrukowanie zoptymalizowanego kodu wygenerowanego przez kompilator JIT i pominie resztę.
Jeśli chcesz zobaczyć cały kod bajtowy, w tym niezoptymalizowane części, dodaj
-XX: CompileThreshold = #
kiedy uruchamiasz swój kod.
Możesz przeczytać więcej o tym poleceniu i ogólnie o funkcjonalności JIT tutaj .
Czy ta opcja jest obecna tylko w kompilacjach debugowania, czy cokolwiek? Ponieważ moja JVM („Java (TM) SE Runtime Environment (build 1.6.0_16-b01”) nie rozpoznaje go, mimo że źródła w sieci wskazują, że ta funkcja jest dostępna w Sun Java 6 i OpenJDK.
Czy nie powinno to być (obecnie) -XX: + PrintAssembly, przynajmniej obecnie? Przetestowane na moim komputerze i pasuje do tego, co zostało powiedziane tutaj: wikis.sun.com/display/HotSpotInternals/PrintAssembly Potrzebujesz -XX: + UnlockDiagnosticVMOptions przed tą opcją i wtyczką deasemblera.
Blaisorblade
@Blaisorblade Otrzymuję: Nieprawidłowo określona opcja maszyny wirtualnej „PrintAssembly” Błąd: nie można utworzyć wirtualnej maszyny języka Java. Błąd: wystąpił krytyczny wyjątek. Program zostanie zamknięty.
może być konieczne umieszczenie drugiego argumentu w cudzysłowie w zależności od systemu operacyjnego itp.
jeśli metoda zostanie wbudowana, możesz przegapić niektóre optymalizacje
Instrukcje: instalowanie wymaganych bibliotek w systemie Windows
Jeśli używasz systemu Windows, na tej stronie znajdują się instrukcje, jak zbudować i zainstalować hsdis-amd64.dlloraz hsdis-i386.dllco jest wymagane, aby działał. Kopiujemy poniżej i rozszerzamy zawartość tej strony * w celach informacyjnych:
Skąd wziąć gotowe pliki binarne
Możesz pobrać gotowe pliki binarne dla systemu Windows z projektu fcml
Jak budować hsdis-amd64.dlli hsdis-i386.dllna Windowsie
Ta wersja poradnika została przygotowana na Windows 8.1 64-bitowym przy użyciu 64-bitowego Cygwin i produkując hsdis-amd64.dll
Zainstaluj Cygwin . Na Select Packagesekranie dodaj następujące pakiety (rozwijając Develkategorię, a następnie klikając raz Skipetykietę obok nazwy każdego pakietu):
make
mingw64-x86_64-gcc-core(potrzebne tylko do hsdis-amd64.dll)
mingw64-i686-gcc-core(potrzebne tylko do hsdis-i386.dll)
diffutils(w Utilskategorii)
Uruchom terminal Cygwin. Można to zrobić za pomocą ikony Pulpit lub Menu Start utworzonej przez instalator i utworzy katalog domowy Cygwin ( C:\cygwin\home\<username>\lub C:\cygwin64\home\<username>\domyślnie).
Pobierz najnowszy pakiet źródłowy GNU binutils i wypakuj jego zawartość do katalogu domowego Cygwin. W chwili pisania tego tekstu najnowszy pakiet to binutils-2.25.tar.bz2. Powinno to spowodować utworzenie katalogu o nazwie binutils-2.25(lub jakiejkolwiek najnowszej wersji) w katalogu domowym Cygwin.
Pobierz źródło OpenJDK, przechodząc do repozytorium JDK 8 Updates , wybierając znacznik odpowiadający zainstalowanej wersji JRE i klikając bz2. Rozpakuj katalog hsdis (znajdujący się w src\share\tools) do katalogu domowego Cygwin.
W terminalu Cygwin wprowadź cd ~/hsdis.
Aby zbudować hsdis-amd64.dll, wejdź
make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Aby zbudować hsdis-i386.dll, wejdź
make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
W obu przypadkach zastąp 2.25pobraną wersją binutils. OS=Linuxjest konieczne, ponieważ chociaż Cygwin jest środowiskiem podobnym do Linuksa, plik makefile hsdis nie rozpoznaje go jako takiego.
Kompilacja zakończy się niepowodzeniem z komunikatami ./chew: No such file or directoryi gcc: command not found. Edytuj <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefilew edytorze tekstu, takim jak Wordpad lub Notepad ++, aby zmienić SUBDIRS = doc po(wiersz 342, jeśli używasz binutils 2.25) na SUBDIRS = po. Ponownie uruchom poprzednie polecenie.
Bibliotekę DLL można teraz zainstalować, kopiując ją z hsdis\build\Linux-amd64lub hsdis\build\Linux-i586do środowiska JRE bin\serverlub bin\clientkatalogu. Możesz znaleźć wszystkie takie katalogi w swoim systemie, wyszukując java.dll.
Dodatkowa wskazówka: jeśli wolisz składnię Intel ASM od AT&T, określ -XX:PrintAssemblyOptions=intelobok innych używanych opcji PrintAssembly.
@AshwinJayaprakash Gdzie mam umieścić te pliki w systemie Mac OS?
Koray Tugay
@KorayTugay umieścił je/usr/lib/
Jean-François Savard
Zaktualizowałem odpowiedź, kopiując z najnowszej wersji strony, do której prowadzą linki, ale to podkreśla powód, dla którego generalnie łączymy się z zasobami zewnętrznymi, zamiast kopiować je dosłownie.
Aleksandr Dubinsky
@AleksandrDubinsky Dzięki za aktualizację. Skopiowałem to celowo: jeśli ta strona zostanie wyłączona, moja odpowiedź nadal będzie niezależna ...
asylias
29
Potrzebujesz wtyczki hsdis do użycia PrintAssembly. Wygodnym wyborem jest wtyczka hsdis oparta na bibliotece FCML.
Można go skompilować dla systemów typu UNIX, aw systemie Windows można użyć gotowych bibliotek dostępnych w sekcji pobierania FCML na Sourceforge:
Aby zainstalować w systemie Windows:
Wyodrębnij bibliotekę dll (można ją znaleźć w plikach hsdis-1.1.2-win32-i386.zip i hsdis-1.1.2-win32-amd64.zip).
Skopiuj bibliotekę dll do dowolnego miejsca java.dll(użyj wyszukiwania systemu Windows). W moim systemie znalazłem go w dwóch lokalizacjach:
kod Wydrukuj kod maszynowy przed mnemonikiem. intel Użyj składni Intela. gas Używa składni asemblera AT&T (kompatybilna z GNU assembler). dec Drukuje IMM i przemieszczenie jako wartości dziesiętne. mpad = XX Wypełnienie mnemonicznej części instrukcji. cpad = XX Wypełnienie kodu maszynowego. seg Pokazuje domyślne rejestry segmentów. zera W przypadku literałów szesnastkowych wyświetla zera wiodące.
Składnia Intela jest domyślna w przypadku Windows, podczas gdy AT&T jest domyślna dla GNU / Linux.
Dzięki za naprawienie lib. Działa również świetnie na Linuksie. Usuwam moje stare komentarze, aby zachować porządek.
Aleksandr Dubinsky
W Linuksie, po zainstalowaniu libhsdis.so i utworzeniu miękkiego linku do hsdis-amd64.so, uruchamiam polecenie java, prmpts nie może znaleźć hsdis-amd64.so. Ponownie uruchamiam i uruchamiam java, wszystko w porządku. Jak uniknąć ponownego uruchomienia, aby miękkie łącze działało natychmiast? Wyloguj?
gfan
2
Tylko mały dodatek: w niektórych dystrybucjach Linuksa możesz po prostu zainstalować pakiet, na przykład w Ubuntu: apt-get install libhsdis0-fcml( askubuntu.com/a/991166/489909 ). Samodzielne budowanie może nie być konieczne.
David Georg Reichelt
8
W przypadku HotSpot (wcześniej Sun) JVM, nawet w trybach produktu:
Wyróżnione wiersze to bezpośrednio uruchamiany kod JIT w JVM.
Następnie możemy poszukać adresu metody: java + 0x2f68 to 00402f68
W WinDBG: Kliknij Widok -> Demontaż. Kliknij Edytuj -> Idź do adresu. Umieść 00402f68 tam
i otrzymaj
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 ... i tak dalej
Aby uzyskać dodatkowe informacje, tutaj znajduje się przykład śledzenia wstecznego kodu w formacie JIT ze zrzutów pamięci za pomocą eksploratora procesów i WinDbg.
Innym sposobem zobaczenia kodu maszynowego i niektórych danych dotyczących wydajności jest użycie CodeAnalyst lub OProfile firmy AMD, które mają wtyczkę Java do wizualizacji wykonywania kodu Java jako kodu maszynowego.
Wydrukuj zespół swoich punktów aktywnych za pomocą profilerów perfasm JMH ( LinuxPerfAsmProfilerlub WinPerfAsmProfiler). JMH wymaga hsdisbiblioteki, ponieważ opiera się na PrintAssembly.
Odpowiedzi:
Zakładając, że używasz maszyny wirtualnej Sun Hotspot JVM (tj. Tej dostarczonej na java.com przez Oracle), możesz dodać flagę
podczas uruchamiania kodu. Spowoduje to wydrukowanie zoptymalizowanego kodu wygenerowanego przez kompilator JIT i pominie resztę.
Jeśli chcesz zobaczyć cały kod bajtowy, w tym niezoptymalizowane części, dodaj
kiedy uruchamiasz swój kod.
Możesz przeczytać więcej o tym poleceniu i ogólnie o funkcjonalności JIT tutaj .
źródło
Ogólne zastosowanie
Jak wyjaśniono w innych odpowiedziach, możesz uruchomić z następującymi opcjami JVM:
Filtruj według określonej metody
Możesz również filtrować według określonej metody za pomocą następującej składni:
Uwagi:
Instrukcje: instalowanie wymaganych bibliotek w systemie Windows
Jeśli używasz systemu Windows, na tej stronie znajdują się instrukcje, jak zbudować i zainstalować
hsdis-amd64.dll
orazhsdis-i386.dll
co jest wymagane, aby działał. Kopiujemy poniżej i rozszerzamy zawartość tej strony * w celach informacyjnych:Skąd wziąć gotowe pliki binarne
Możesz pobrać gotowe pliki binarne dla systemu Windows z projektu fcml
Jak budować
hsdis-amd64.dll
ihsdis-i386.dll
na WindowsieTa wersja poradnika została przygotowana na Windows 8.1 64-bitowym przy użyciu 64-bitowego Cygwin i produkując hsdis-amd64.dll
Zainstaluj Cygwin . Na
Select Packages
ekranie dodaj następujące pakiety (rozwijającDevel
kategorię, a następnie klikając razSkip
etykietę obok nazwy każdego pakietu):make
mingw64-x86_64-gcc-core
(potrzebne tylko dohsdis-amd64.dll
)mingw64-i686-gcc-core
(potrzebne tylko dohsdis-i386.dll
)diffutils
(wUtils
kategorii)Uruchom terminal Cygwin. Można to zrobić za pomocą ikony Pulpit lub Menu Start utworzonej przez instalator i utworzy katalog domowy Cygwin (
C:\cygwin\home\<username>\
lubC:\cygwin64\home\<username>\
domyślnie).binutils-2.25.tar.bz2
. Powinno to spowodować utworzenie katalogu o nazwiebinutils-2.25
(lub jakiejkolwiek najnowszej wersji) w katalogu domowym Cygwin.src\share\tools
) do katalogu domowego Cygwin.cd ~/hsdis
.Aby zbudować
hsdis-amd64.dll
, wejdźmake OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
Aby zbudować
hsdis-i386.dll
, wejdźmake OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25
W obu przypadkach zastąp
2.25
pobraną wersją binutils.OS=Linux
jest konieczne, ponieważ chociaż Cygwin jest środowiskiem podobnym do Linuksa, plik makefile hsdis nie rozpoznaje go jako takiego../chew: No such file or directory
igcc: command not found
. Edytuj<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\Makefile
w edytorze tekstu, takim jak Wordpad lub Notepad ++, aby zmienićSUBDIRS = doc po
(wiersz 342, jeśli używasz binutils 2.25) naSUBDIRS = po
. Ponownie uruchom poprzednie polecenie.Bibliotekę DLL można teraz zainstalować, kopiując ją z
hsdis\build\Linux-amd64
lubhsdis\build\Linux-i586
do środowiska JREbin\server
lubbin\client
katalogu. Możesz znaleźć wszystkie takie katalogi w swoim systemie, wyszukującjava.dll
.Dodatkowa wskazówka: jeśli wolisz składnię Intel ASM od AT&T, określ
-XX:PrintAssemblyOptions=intel
obok innych używanych opcji PrintAssembly.* Licencja strony to Creative Commons
źródło
/usr/lib/
Potrzebujesz wtyczki hsdis do użycia
PrintAssembly
. Wygodnym wyborem jest wtyczka hsdis oparta na bibliotece FCML.Można go skompilować dla systemów typu UNIX, aw systemie Windows można użyć gotowych bibliotek dostępnych w sekcji pobierania FCML na Sourceforge:
Aby zainstalować w systemie Windows:
java.dll
(użyj wyszukiwania systemu Windows). W moim systemie znalazłem go w dwóch lokalizacjach:C:\Program Files\Java\jre1.8.0_45\bin\server
C:\Program Files\Java\jdk1.8.0_45\jre\bin\server
Aby zainstalować w systemie Linux:
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
/usr/lib/jvm/java-8-oracle
Jak to uruchomić:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code -jar fcml-test.jar
Dodatkowe parametry konfiguracyjne:
kod Wydrukuj kod maszynowy przed mnemonikiem.
intel Użyj składni Intela.
gas Używa składni asemblera AT&T (kompatybilna z GNU assembler).
dec Drukuje IMM i przemieszczenie jako wartości dziesiętne.
mpad = XX Wypełnienie mnemonicznej części instrukcji.
cpad = XX Wypełnienie kodu maszynowego.
seg Pokazuje domyślne rejestry segmentów.
zera W przypadku literałów szesnastkowych wyświetla zera wiodące.
Składnia Intela jest domyślna w przypadku Windows, podczas gdy AT&T jest domyślna dla GNU / Linux.
Aby uzyskać więcej informacji, zobacz Podręcznik referencyjny biblioteki FCML
źródło
apt-get install libhsdis0-fcml
( askubuntu.com/a/991166/489909 ). Samodzielne budowanie może nie być konieczne.W przypadku HotSpot (wcześniej Sun) JVM, nawet w trybach produktu:
http://wikis.oracle.com/display/HotSpotInternals/PrintAssembly
Wymagany montaż: wymaga wtyczki.
źródło
Wierzę, że WinDbg byłby pomocny, jeśli uruchamiasz go na komputerze z systemem Windows. Właśnie wypuściłem jeden słoik.
Przejrzałem niezarządzany stos wywołań przez kb :
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
Wyróżnione wiersze to bezpośrednio uruchamiany kod JIT w JVM.
Następnie możemy poszukać adresu metody:
java + 0x2f68 to 00402f68
W WinDBG:
Kliknij Widok -> Demontaż.
Kliknij Edytuj -> Idź do adresu.
Umieść 00402f68 tam
i otrzymaj
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
... i tak dalej
Aby uzyskać dodatkowe informacje, tutaj znajduje się przykład śledzenia wstecznego kodu w formacie JIT ze zrzutów pamięci za pomocą eksploratora procesów i WinDbg.
źródło
Innym sposobem zobaczenia kodu maszynowego i niektórych danych dotyczących wydajności jest użycie CodeAnalyst lub OProfile firmy AMD, które mają wtyczkę Java do wizualizacji wykonywania kodu Java jako kodu maszynowego.
źródło
Wydrukuj zespół swoich punktów aktywnych za pomocą profilerów perfasm JMH (
LinuxPerfAsmProfiler
lubWinPerfAsmProfiler
). JMH wymagahsdis
biblioteki, ponieważ opiera się naPrintAssembly
.źródło