Как увидеть JIT-скомпилированный код в JVM?


86

Есть ли способ увидеть собственный код, созданный JIT в JVM?


Вы уверены, что хотите увидеть JIT-скомпилированный (собственный) код или просто байт-код? Я спрашиваю, потому что этот вопрос вызывает некоторые сомнения, действительно ли вы хотите увидеть собственный код ... И, извините, я тоже не знаю такого инструмента.
gimpf 01

3
Я хочу видеть точный JIT-скомпилированный собственный код. Конечно, это не то, что мне нужно для выполнения работы, это скорее эксперименты и исследования.
alsor.net 01

Незначительная проблема с кадрами: динамический компилятор, используемый в современных JVM, не имеет только одной версии скомпилированного кода; он может начать с интерпретации, затем скомпилировать метод или его часть, а затем потенциально перекомпилировать его несколько раз по мере загрузки / выгрузки классов или изменения шаблонов использования или на основе статистики производительности. (Я думаю, что он может даже отказаться от скомпилированной версии и вернуться к интерпретации, если это покажется полезным.) Таким образом, вы можете получить не только разный код на разных машинах и даже для разных запусков на одной машине, но и в разное время в одном и том же запуске. .
gidds

Ответы:


45

Предполагая, что вы используете JVM Sun Hotspot (то есть ту, которая предоставляется Oracle на java.com ), вы можете добавить флаг

-XX: + PrintOptoAssembly

при запуске вашего кода. Это распечатает оптимизированный код, сгенерированный JIT-компилятором, и оставит все остальное.

Если вы хотите увидеть весь байт-код, включая неоптимизированные части, добавьте

-XX: CompileThreshold = #

когда вы запускаете свой код.

Вы можете узнать больше об этой команде и о функциональных возможностях JIT в целом здесь .


Эта опция присутствует только в отладочных сборках или в чем-то еще? Потому что моя JVM ("Java (TM) SE Runtime Environment (build 1.6.0_16-b01") не распознает ее, хотя исходный текст в Интернете указывает, что эта функция доступна в Sun Java 6 и OpenJDK.
Joachim Sauer

2
Да, требуются двоичные файлы DEBUG. blogs.warwick.ac.uk/richardwarburton/entry/…
alsor.net 01

3
Разве это не должно быть (сейчас) -XX: + PrintAssembly, по крайней мере, в наши дни? Протестировано на моей машине и соответствует тому, что здесь сказано: wikis.sun.com/display/HotSpotInternals/PrintAssembly. Вам нужно -XX: + UnlockDiagnosticVMOptions перед этой опцией и плагином дизассемблера.
Blaisorblade

@Blaisorblade Я получаю: Неправильно указанный параметр виртуальной машины «PrintAssembly». Ошибка: не удалось создать виртуальную машину Java. Ошибка: возникла фатальная исключительная ситуация. Программа будет закрыта.
Корай Тугай

@KorayTugay См. Другие ответы - обновленная ссылка - wikis.oracle.com/display/HotSpotInternals/PrintAssembly , как указано в stackoverflow.com/a/15146962/53974 или stackoverflow.com/a/4149878/53974 . Если следующие инструкции не работают, спросите подробности в каком-нибудь подходящем месте (не уверен, должен ли это быть другой вопрос для вашего случая, ссылаясь на этот).
Blaisorblade

77

Общее использование

Как объясняется в других ответах, вы можете работать со следующими параметрами JVM:

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

Фильтр по определенному методу

Вы также можете отфильтровать определенный метод с помощью следующего синтаксиса:

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

Ноты:

  • вам может потребоваться заключить второй аргумент в кавычки в зависимости от ОС и т. д.
  • если метод будет встроен, вы можете пропустить некоторые оптимизации

Как: установить необходимые библиотеки в Windows

Если вы используете Windows, на этой странице есть инструкции по сборке и установке, hsdis-amd64.dllа также о том, hsdis-i386.dllчто необходимо для ее работы. Мы копируем ниже и расширяем содержание этой страницы * для справки:


Где взять готовые двоичные файлы

Вы можете скачать готовые двоичные файлы для Windows из проекта fcml

Как собрать hsdis-amd64.dllи hsdis-i386.dllна Windows

Эта версия руководства была подготовлена ​​для 64-разрядной версии Windows 8.1 с использованием 64-разрядной версии Cygwin и создания hsdis-amd64.dll.

  1. Установите Cygwin . На Select Packagesэкране добавьте следующие пакеты (развернув Develкатегорию, а затем один раз щелкнув Skipярлык рядом с названием каждого пакета):

    • make
    • mingw64-x86_64-gcc-core(требуется только для hsdis-amd64.dll)
    • mingw64-i686-gcc-core(требуется только для hsdis-i386.dll)
    • diffutilsUtilsкатегории)
  2. Запустите терминал Cygwin. Это можно сделать с помощью значка на рабочем столе или в меню «Пуск», созданного установщиком, который создаст ваш домашний каталог Cygwin ( C:\cygwin\home\<username>\или C:\cygwin64\home\<username>\по умолчанию).

  3. Загрузите последний пакет исходного кода GNU binutils и извлеките его содержимое в домашний каталог Cygwin. На момент написания последней версии пакета является binutils-2.25.tar.bz2. Это должно привести к созданию каталога с именем binutils-2.25(или любой другой последней версии) в вашем домашнем каталоге Cygwin.
  4. Загрузите исходный код OpenJDK, перейдя в репозиторий обновлений JDK 8 , выбрав тег, соответствующий вашей установленной версии JRE, и щелкнув bz2. Извлеките каталог hsdis (находится в src\share\tools) в домашний каталог Cygwin.
  5. В терминале Cygwin введите cd ~/hsdis.
  6. Чтобы построить hsdis-amd64.dll, введите

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

    Чтобы построить hsdis-i386.dll, введите

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

    В любом случае замените 2.25загруженной версией binutils. OS=Linuxнеобходимо, потому что, хотя Cygwin является Linux-подобной средой, make-файл hsdis не может распознать ее как таковую.

  7. Сборка завершится ошибкой с сообщениями ./chew: No such file or directoryи gcc: command not found. <Cygwin home directory>\hsdis\build\Linux-amd64\bfd\MakefileВ текстовом редакторе, таком как Wordpad или Notepad ++, отредактируйте SUBDIRS = doc po(строка 342, если используется binutils 2.25) на SUBDIRS = po. Повторите предыдущую команду.

Теперь DLL можно установить, скопировав ее из hsdis\build\Linux-amd64или hsdis\build\Linux-i586в каталог JRE bin\serverили bin\client. Вы можете найти все такие каталоги в своей системе, выполнив поиск java.dll.

Дополнительный совет: если вы предпочитаете синтаксис Intel ASM -XX:PrintAssemblyOptions=intelвместо AT&T, укажите вместе с любыми другими используемыми вами параметрами PrintAssembly.

* лицензия на страницу - Creative Commons



@AshwinJayaprakash Куда мне поместить эти файлы в Mac OS?
Корай Тугай

@KorayTugay вставил их/usr/lib/
Жан-Франсуа Савар

Я обновил ответ, скопировав из последней версии связанной страницы, но это подчеркивает причину, по которой мы обычно ссылаемся на внешние ресурсы, а не копируем их дословно.
Александр Дубинский

@AleksandrDubinsky Спасибо за обновление. Я скопировал его специально: если этот сайт выйдет из
строя,

29

Для использования вам понадобится плагин hsdis PrintAssembly. Удобный выбор - плагин hsdis на основе библиотеки FCML.

Его можно скомпилировать для UNIX-подобных систем, а в Windows вы можете использовать готовые библиотеки, доступные в разделе загрузки FCML на Sourceforge:

Для установки в Windows:

  • Распакуйте dll (ее можно найти в hsdis-1.1.2-win32-i386.zip и hsdis-1.1.2-win32-amd64.zip).
  • Скопируйте dll туда, где есть java.dll(используйте поиск Windows). В своей системе я нашел его в двух местах:
    • C:\Program Files\Java\jre1.8.0_45\bin\server
    • C:\Program Files\Java\jdk1.8.0_45\jre\bin\server

Для установки в 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
  • В моей системе JDK находится в /usr/lib/jvm/java-8-oracle

Как запустить:

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

Дополнительные параметры конфигурации:

code Вывести машинный код перед мнемоникой.
intel Используйте синтаксис Intel.
gas Используйте синтаксис ассемблера AT&T (совместимый с GNU ассемблер).
dec Печатает IMM и смещение как десятичные значения.
mpad = XX Заполнение мнемонической части инструкции.
cpad = XX Заполнение машинного кода.
seg Показывает регистры сегментов по умолчанию.
нули Показывать ведущие нули в случае шестнадцатеричных литералов.

Синтаксис Intel является синтаксисом по умолчанию в случае Windows, тогда как синтаксис AT&T используется по умолчанию для GNU / Linux.

Дополнительные сведения см. В Справочном руководстве по библиотеке FCML.


Спасибо за исправление библиотеки. Он также отлично работает в Linux. Я удаляю свои старые комментарии, чтобы не было беспорядка.
Александр Дубинский

В Linux после того, как я установил libhsdis.so и сделал программную ссылку на hsdis-amd64.so, я запускаю команду java, она не может найти hsdis-amd64.so. Я перезагружаюсь, а затем повторно запускаю java, все в порядке. Как избежать перезагрузки, чтобы софт линк заработал мгновенно? выйти?
gfan

2
Небольшое дополнение: в некоторых дистрибутивах Linux вы можете просто установить пакет, например, в Ubuntu: apt-get install libhsdis0-fcml( askubuntu.com/a/991166/489909 ). Самостоятельное создание этого может не потребоваться.
Дэвид Георг Райхельт


5

Я считаю, что WinDbg будет полезен, если вы используете его на машине с Windows. Я только что запустил одну банку.

  • Потом подключил к java процессу через Windbg
  • Проверенные темы командой ~ ; Было 11 потоков, 0 поток был основным рабочим потоком
  • Перешел на 0-поток - ~ 0 с
  • Просмотрел неуправляемый стек вызовов по 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

Выделенные строки - это прямой запуск JIT-кода на JVM.

  • Затем мы можем найти адрес метода:
    java + 0x2f68 - 00402f68

  • В WinDBG:
    нажмите «Просмотр» -> «Разборка».
    Щелкните Правка -> Перейти к адресу.
    Поставил туда 00402f68
    и получил

    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
    ... и так далее

Для получения дополнительной информации вот пример того, как отследить JIT-код из дампов памяти с помощью проводника процессов и WinDbg.


4

Другой способ увидеть машинный код и некоторые данные о производительности - использовать AMD CodeAnalyst или OProfile, в которых есть подключаемый модуль Java для визуализации выполнения кода Java как машинного кода.


1

Распечатайте сборку ваших горячих точек с помощью профилировщика JMH perfasm ( LinuxPerfAsmProfilerили WinPerfAsmProfiler). JMH действительно требует hsdisбиблиотеки, поскольку он полагается на PrintAssembly.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.