Як побачити JIT-компільований код у JVM?


84

Чи є спосіб побачити власний код, який виробляє JIT, у JVM?


Ви впевнені, що хочете побачити компільований JIT (власний) код або просто байт-код? Я запитую, тому що задання цього питання тут призводить до певних сумнівів, якщо ви дійсно хочете побачити власний код ... І, вибачте, я теж не знаю такого інструменту.
gimpf

3
Я хочу бачити вбудований код, скомпільований JIT. Звичайно, це не те, що мені потрібно, щоб зробити роботу, а різновид експериментів та досліджень.
alsor.net

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

Відповіді:


45

Припускаючи, що ви використовуєте Sun Hotspot JVM (тобто той, який надає Oracle на java.com ), ви можете додати прапор

-XX: + PrintOptoAssembly

під час запуску коду. Це роздрукує оптимізований код, створений компілятором JIT, а решту залишить.

Якщо ви хочете побачити весь байт-код, включаючи неоптимізовані частини, додайте

-XX: CompileThreshold = #

коли ви запускаєте свій код.

Детальніше про цю команду та функціональність JIT ви можете прочитати тут .


Цей параметр присутній лише у збірках налагодження чи щось інше? Оскільки мій JVM ("Java (TM) SE Runtime Environment (збірка 1.6.0_16-b01") не розпізнає його, навіть якщо джерело в Інтернеті вказує, що ця функція доступна в Sun Java 6 та OpenJDK.
Йоахім Зауер,

2
Так, потрібні двійкові файли DEBUG. blogs.warwick.ac.uk/richardwarburton/entry/…
alsor.net

3
Хіба це не повинно бути (сьогодні) -XX: + PrintAssembly, принаймні сьогодні? Перевірено на моїй машині та відповідає сказаному тут: wikis.sun.com/display/HotSpotInternals/PrintAssembly Вам потрібна -XX: + UnlockDiagnosticVMOptions перед цією опцією та плагін для розбірки.
Blaisorblade

@Blaisorblade Я отримую: Неправильно вказаний параметр VM Помилка "PrintAssembly": Не вдалося створити віртуальну машину Java. Помилка: сталося фатальне виняток. Програма вийде.
Корай Тугай

@KorayTugay Див. Інші відповіді - оновленим посиланням є wikis.oracle.com/display/HotSpotInternals/PrintAssembly , як зазначено у stackoverflow.com/a/15146962/53974 або stackoverflow.com/a/4149878/53974 . Якщо наступні вказівки не працюють, будь ласка, запитайте деталі у певному відповідному місці (не впевнені, чи слід це ще одне запитання для вашої справи, посилаючись на це).
Blaisorblade

76

Загальне використання

Як пояснюється іншими відповідями, ви можете запустити такі опції 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

Ця версія посібника була підготовлена ​​для Windows 8.1 64bit із використанням 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, hsdis makefile не розпізнає його як такий.

  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 перед AT&T, вкажіть -XX:PrintAssemblyOptions=intelпоряд із будь-якими іншими параметрами PrintAssembly, які ви використовуєте.

* ліцензія на сторінку - Creative Commons


1
Попередньо побудовані двійкові файли для інших платформ - kenai.com/projects/base-hsdis/downloads
Ashwin

@AshwinJayaprakash Де я повинен розмістити ці файли в Mac OS?
Корай Тугай

@KorayTugay помістив їх/usr/lib/
Жан-Франсуа Савард

Я оновив відповідь, скопіювавши з останньої версії сторінки, на яку пов’язано посилання, але це підкреслює причину, по якій ми зазвичай посилаємось на зовнішні ресурси, а не копіюємо їх дослівно.
Олександр Дубінський

@AleksandrDubinsky Дякую за оновлення. Я спеціально скопіював його: якщо цей сайт буде збитий, моя відповідь все одно буде автономною ...
assylias

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

Додаткові параметри конфігурації:

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

Синтаксис Intel є типовим для Windows, тоді як AT&T є типовим для GNU / Linux.

Докладніше див. У довідковому посібнику бібліотеки FCML


Дякуємо за фіксацію ліб. Це чудово працює і на Linux. Я видаляю свої старі коментарі, щоб тримати безлад.
Олександр Дубінський

У Linux після того, як я встановив libhsdis.so і зробив м'яке посилання на hsdis-amd64.so, я запустив команду java, вона prmpts не може знайти 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

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


0

Надрукуйте збірку своїх гарячих точок за допомогою профілів для парфуму JMH ( LinuxPerfAsmProfilerабо WinPerfAsmProfiler). JMH вимагає hsdisбібліотеки, оскільки вона покладається на PrintAssembly.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.