Видео запись
Подготовка к участию в мастер-классе
Для выполнения практической части семинара вам понадобится компьютер с операционной системой Linux и root доступом. Допустимо так же использование виртуальной машины Linux в другой OS.
Для работы вам понабится perf, OpenJDK 17 и опционально Mission Control. Там же понадобиться git для подготовки.
perf
perf может быть установлен с помощь менеджера пакетов вашего Linux дистрибутива. Например для Ubuntu - apt-get install linux-tools-common linux-tools-generic linux-tools-`uname -r`.
После инсталяции проверьте работо способность.
sudo perf stat sleep 10
Performance counter stats for 'sleep 10':
0.50 msec task-clock # 0.000 CPUs utilized
1 context-switches # 0.002 M/sec
0 cpu-migrations # 0.000 K/sec
61 page-faults # 0.123 M/sec
1,512,807 cycles # 3.055 GHz
1,087,665 stalled-cycles-frontend # 71.90% frontend cycles idle
899,793 instructions # 0.59 insn per cycle
# 1.21 stalled cycles per insn
180,697 branches # 364.870 M/sec
9,091 branch-misses # 5.03% of all branches
10.000879454 seconds time elapsed
0.000878000 seconds user
0.000000000 seconds sys
sudo perf stat -e cache-misses sleep 10
Performance counter stats for 'sleep 10':
8,278 cache-misses
10.001446216 seconds time elapsed
0.001394000 seconds user
0.000000000 seconds sys
git
git может быть установлен средствами вашего Linux дистрибутива.
OpenJDK и материалы мастер-класса
Для простоты дальнейшие инструкции будут в виде последовательности Linux комманд.
Директория для мастер-класса
export LABDIR=~/jpoint2023_perf
mkdir $LABDIR
cd $LABDIR
Установка OpenJDK 17
Я рекомендую использовать Liberica OpenJDK 17, но подойдёт любой дистрибутив OpenJDK 17 и выше. Не рекомендую устанавливать OpenJDK через менеджер пакетов, так как зачастую там отсутсвует отладочная информация.
wget https://download.bell-sw.com/java/17.0.6+10/bellsoft-jdk17.0.6+10-linux-amd64.tar.gz
tar -xf bellsoft-jdk17.0.6+10-linux-amd64.tar.gz
Создание алиазов.
alias java=$LABDIR/jdk-17.0.6/bin/java
alias jcmd=$LABDIR/jdk-17.0.6/bin/jcmd
Проверка.
java --version
openjdk 17.0.6 2023-01-17 LTS
OpenJDK Runtime Environment (build 17.0.6+10-LTS)
OpenJDK 64-Bit Server VM (build 17.0.6+10-LTS, mixed mode, sharing)
jcmd
1228 jdk.jcmd/sun.tools.jcmd.JCmd
Дополнительные материалы
Иснтрумент SJK.
wget https://training.ragozin.info/sjk.jar
Проверка.
java -jar sjk.jar --commands
Restarting java with unlocked package access
dexp - [Dump Export] Extract metrics from compressed dump into tabular format
flame - Generates flame graph from stack traces
gc - [Print GC] Print GC log like information for remote process
hh - [Heap Histo] Prints class histogram, similar to jmap -histo
hs - Hotspot JVM tweaks
jcmd - jcmd JMX command
jfr2json - [JFR 2 JSON] Flight decoder, command translates JFR files into JSON
jps - [JPS] Enhanced version of JDK's jps tool
mprx - JMX proxy - expose target process' MBeans for remote access
mx - [MBean] MBean query and invokation
mxdump - null
mxping - [MXPING] Verify JMX connection to target JVM
prfi - Pref import
ssa - [Stack Sample Analyzer] Analyzing stack trace dumps
stcap - [Stack Capture] Dumps stack traces to file for further processing
stcpy - [Stack Copy] Stack dump copy/filtering utility
ttop - [Thread Top] Displays threads from JVM process
vminfo - [VMINFO] Dumps various from local VM
Инструмент FlameGraph.
git clone https://github.com/brendangregg/FlameGraph.git
Материалы мастер-класса.
git clone https://github.com/aragozin/jpoint_2023.git
Mission control
Я рекомендую использовать дистрибутив Liberica Mission Control.
Мастер-класс, пошаговая инструкция
Подготовка окружения
Нам потребуются два терминала для работы
Выполните следующие команды в каждом из терминалов для насторий окружения
export LABDIR=~/jpoint2023_perf
cd $LABDIR
alias java=$LABDIR/jdk-17.0.6/bin/java
alias jcmd=$LABDIR/jdk-17.0.6/bin/jcmd
Обновим вспомогательные материалы до последней версии.
cd $LABDIR/jpoint_2023
git fetch && git reset --hard origin/main
cd $LABDIR
Часть 1
1
запустить тестовую программу в отдельной консоли
java -jar jpoint_2023/bias-sjk-v1.jar jpoint_2023/jboss-10k.std
в консоли профалера определим pid процесса
jcmd
присвоим java процесса переменной для удобства
export PID=1234
2
запустим perf с частотой 500 Hz
sudo perf record -F 500 -p $PID -g -o perf1.data -- sleep 30
файл данных perf создан от root пользователя, меняем уровень доступа к файлу
sudo chown $USER perf1.data
3
откроем файл данных perf в режиме отчёта
perf report -i perf1.data
4
сгенерируем файл символов для JIT компилированного кода
jcmd $PID Compiler.perfmap
попробуем открыть отчёт perf снова
perf report -i perf1.data
посмотрим JVM стэк-трейс нашего примера
jcmd $PID Thread.print
"SjkDumpParser" #13 daemon prio=5 os_prio=0 cpu=38776.94ms elapsed=38.89s tid=0x00007f6b101e0860 nid=0x5e9d runnable [0x00007f6ae19cc000]
java.lang.Thread.State: RUNNABLE
at java.util.zip.Inflater.inflateBytesBytes(java.base@17.0.6/Native Method)
at java.util.zip.Inflater.inflate(java.base@17.0.6/Inflater.java:378)
- locked <0x00000007176367b8> (a java.util.zip.Inflater$InflaterZStreamRef)
at java.util.zip.InflaterInputStream.read(java.base@17.0.6/InflaterInputStream.java:152)
at java.util.zip.InflaterInputStream.read(java.base@17.0.6/InflaterInputStream.java:122)
at java.io.DataInputStream.readByte(java.base@17.0.6/DataInputStream.java:271)
at org.gridkit.jvmtool.stacktrace.StackTraceCodec.readVarInt(StackTraceCodec.java:664)
at org.gridkit.jvmtool.stacktrace.StackTraceCodec$StackTraceReaderV2.readStackTrace(StackTraceCodec.java:642)
at org.gridkit.jvmtool.stacktrace.StackTraceCodec$StackTraceReaderV2.readTraceInfo(StackTraceCodec.java:610)
at org.gridkit.jvmtool.stacktrace.StackTraceCodec$StackTraceReaderV2.loadNext(StackTraceCodec.java:577)
at info.ragozin.proflab.SjkDumpParser.run(SjkDumpParser.java:21)
at info.ragozin.proflab.DemoRunner$1.run(DemoRunner.java:19)
исходный код примера доступен на github
5
остановим пример и перезапустим с опцией -XX:+PreserveFramePointer
java -XX:+PreserveFramePointer -jar jpoint_2023/bias-sjk-v1.jar jpoint_2023/jboss-10k.std
определим новый PID
jcmd
export PID=1234
6
проведём новую сессию профилирования с perf
sudo perf record -F 500 -p $PID -g -o perf2.data -- sleep 30 && sudo chown $USER perf2.data
сгенерируем символьную информацию
jcmd $PID Compiler.perfmap
и откроем отчёт
perf report -i perf2.data
7
используем скрипты Брендона Грега чтобы получить flame graph
perf script -i perf2.data | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > perf2.svg
8
построим flame graph с использованием SJK
perf script -i perf2.data | java -jar sjk.jar prfi -i - -o perf2.sjk
java -jar sjk.jar flame -f perf2.sjk -o perf2.html
9
сравним результы с JFR, снимен дамп
jcmd $PID JFR.start filename=$LABDIR/perf2.jfr method-profiling=high duration=1m
откроем файл perf2.jfr в Mission Control, и изучем полученные данные
10
построим flame graph на основании дампа JFR
java -jar sjk.jar flame -f perf1.jfr -o perf2.jfr.html
11
сравним результаты perf с JFR и классическим сэмплирование дампов потоков
проведём сэмплирование с помощью SJK
java -jar sjk.jar stcap -p $PID -o perf2.dump.sjk
java -jar sjk.jar flame -f perf2.dump.sjk -o perf2.dump.html
Часть 2
По-умолчанию perf использует "cycles" события для семплирования, попробуем поработать с другим типов событий.
12
Чтобы получить полный список доступных событий можно использовать команду.
sudo perf list
Нас интересует событие ошибки предсказателя условных переходов.
Проверим доступность этого типа событий
sudo perf stat -e branch-miss sleep 10
13
для демонстрации сэмплирования по branch-miss событиям (ошибкам предсказания условных переходов) запустим следующий пример коммандой ниже
java -XX:+PreserveFramePointer -cp jpoint_2023/ PositiveSumBench
зафиксируем PID
jcmd
export PID=1234
14
проведем профилирование в стандартном режиме
sudo perf record -F 500 -p $PID -g -o perf3.data -- sleep 30 && sudo chown $USER perf3.data
15
теперь проведём повторное профилирование, используя события ошибки предсказания перехода для сэмплирования
sudo perf record -F 500 -p $PID -g -o perf4.data -e branch-miss -- sleep 30 && sudo chown $USER perf4.data
экспортируем JIT символы
jcmd $PID Compiler.perfmap
16
запустим по очереди отчёт по обоим файлам полученым в разных режимах
perf report -i perf3.data
perf report -i perf4.data
Часть 3
17 запустим новый тестовый пример
java -XX:+PreserveFramePointer -jar jpoint_2023/javaref-bench-finalizer.jar
зафиксируем PID
jcmd
export PID=1234
18
проведём сэмплирование
sudo perf record -F 500 -p $PID -g -o perf5.data -- sleep 30 && sudo chown $USER perf5.data
jcmd $PID Compiler.perfmap
19
подготовим flame graph с помощью SJK
perf script -i perf5.data | java -jar sjk.jar prfi -i - -o perf5.sjk
java -jar sjk.jar flame -f perf5.sjk -o perf5.html
откроем полученный flame graph
Часть 4
20
начнём работу с новым примером
java -XX:+PreserveFramePointer -cp jpoint_2023/ CryptoBench
зафиксируем PID
jcmd
export PID=1234
21
проведём сэплирование JFR и perf для дальнейшего сравнения
jcmd $PID JFR.start filename=$LABDIR/perf6.jfr method-profiling=high duration=30s
sudo perf record -F 500 -p $PID -g -o perf6.data -- sleep 30 && sudo chown $USER perf6.data
jcmd $PID Compiler.perfmap
22
построим "огненые" графы и сравним их
java -jar sjk.jar flame -f perf6.jfr -o perf6.jfr.html
perf script -i perf6.data | java -jar sjk.jar prfi -i - -o perf6.sjk
java -jar sjk.jar flame -f perf6.sjk -o perf6.html
откроем файлы perf6.jfr.html и perf6.html для сравнения результатов
23
перезапустим пример с опцием -XX:+DebugNonSafepoints
java -XX:+PreserveFramePointer -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -cp jpoint_2023/ CryptoBench
зафиксируем PID
jcmd
export PID=1234
24
повторим профилирование и построение окчётов для JFR и perf
jcmd $PID JFR.start filename=$LABDIR/perf7.jfr method-profiling=high duration=30s
sudo perf record -F 500 -p $PID -g -o perf7.data -- sleep 30 && sudo chown $USER perf7.data
jcmd $PID Compiler.perfmap
java -jar sjk.jar flame -f perf7.jfr -o perf7.jfr.html
perf script -i perf7.data | java -jar sjk.jar prfi -i - -o perf7.sjk
java -jar sjk.jar flame -f perf7.sjk -o perf7.html
откроем файлы perf7.jfr.html и perf7.html и посмотрим как изменились результаты
Дополнительные материалы
Ссылки из дискуссионной зоны