JMH тестирует с помощью javaagent

Я пытаюсь измерить влияние агента JVM на производительность, чтобы убедиться, что он не сделает недействительными тесты, которые мы пытаемся запустить (и, возможно, обосновать выбор некоторых образцов из prod). Этот случай представляет собой набор сценариев BTrace, которые будут выполняться во время автоматического нагрузочного тестирования, но проблема может быть общей для любого агента.

Чтобы запустить тесты, я создал небольшой проект JMH и прикрепляю агент как:

java -javaagent:/home/ssube/btrace/build/btrace-agent.jar=scriptdir=/home/ssube/btrace/scripts/,port=0 -jar benchmarks.jar

Это приводит к появлению следующей ошибки каждый раз, когда JMH разветвляет JVM:

# Run progress: 0.00% complete, ETA 00:02:00
# Fork: 1 of 1
Exception in thread "main" java.lang.IllegalArgumentException: org.openjdk.jmh.runner.options.CommandLineOptions; local class incompatible: stream classdesc serialVersionUID = 8906142321598115825, local class serialVersionUID = 7529911323947566771
    at org.openjdk.jmh.runner.ForkedMain.main(ForkedMain.java:72)
<binary link had failed, forked VM corrupted the stream? Use EXTRA verbose to print exception>
<forked VM failed with exit code 1>
<stdout last='10 lines'>
</stdout>
<stderr last='10 lines'>
Exception in thread "main" java.lang.IllegalArgumentException: org.openjdk.jmh.runner.options.CommandLineOptions; local class incompatible: stream classdesc serialVersionUID = 8906142321598115825, local class serialVersionUID = 7529911323947566771
    at org.openjdk.jmh.runner.ForkedMain.main(ForkedMain.java:72)
</stderr>

# VM invoker: /usr/java/jdk1.8.0_11/jre/bin/java
# VM options: -javaagent:/home/ssube/btrace/build/btrace-agent.jar=scriptdir=/home/ssube/btrace/scripts/,port=0
# Warmup: 20 iterations, 1 s each
# Measurement: 20 iterations, 1 s each
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: com.stackoverflow.questions.ShaderBench.testProcessProc

Ни один из моих классов не сериализуем и не имеет serialVersionUID. Бенчмарк JMH работает без подключенного агента BTrace, а агент и скрипты работают с кодом без JMH.

(Как) вы можете подключить javaagent к набору тестов JMH и зафиксировать различия в производительности, вызванные агентом?


person ssube    schedule 15.08.2014    source источник


Ответы (2)


Сопровождающий JMH здесь. С точки зрения сопровождающего это похоже на ошибку JMH в том, что он не предоставляет SUID для своих собственных внутренних классов, поэтому он может быть устойчив к безвредному инструментированию. Теперь это исправлено с помощью 3d44d68e45be:

changeset:   960:3d44d68e45be
tag:         tip
user:        shade
date:        Sat Aug 16 15:00:18 2014 +0400
summary:     Apply SUIDs for all Serializable classes: this protects from the benign instrumentation.

Попробуйте использовать передовой JMH и посмотрите, решит ли он проблему для ты. Обратите внимание, что предоставление SUID не защищает нас от вопиющих изменений в форме сериализации, которые может сделать агент Java (например, вставка непереходного поля), поэтому, если BTrace (не) ведет себя подобным образом, у нас проблемы.

Если приведенное выше изменение JMH не работает, отправьте минимальный воспроизводимый сценарий на адрес jmh-dev. список рассылки, мы хотели бы посмотреть, что можно сделать, чтобы смягчить проблему.

В противном случае ищите исключение org.openjdk.jmh.* классов из инструментовки.

person Aleksey Shipilev    schedule 16.08.2014
comment
Изучаю это сегодня, спасибо. Дам вам знать, что я найду. - person ssube; 18.08.2014
comment
Это, кажется, сделало свое дело. Протестировано без необходимости указывать какие-либо jvmArgs в аннотации @Fork с различным количеством ответвлений; теперь все работает правильно. Обратите внимание, что для BTrace необходимо указать port=0, иначе каждая вилка попытается привязаться к значению по умолчанию и потерпит неудачу. - person ssube; 18.08.2014
comment
BTrace не будет внедрять непереходные поля, поскольку введение новых полей не поддерживается текущей реализацией классов ретрансляции JVM. - person JB-; 25.08.2014
comment
@ J.B: Хорошо, тогда мы в безопасности. - person Aleksey Shipilev; 26.08.2014

Недавно я столкнулся с той же проблемой. Я предполагаю, что это связано с разветвление JMH. Как видно из выходных данных теста, JMH создает ответвление 1 of 1, где JMH запускает свежий экземпляр JVM для каждой тестовой строки. К этим JVM больше не подключен ваш агент.

Это влияет на классы, которые вы переопределяете с помощью своего агента, которые загружаются без агента на разветвленных JVM. Таким образом, вы получаете проблемы с сериализацией. Поскольку вы не определяете явный UID для своих классов, эти UID вычисляются неявно. Таким образом, разветвленные JVM распознают, что исходные классы JVM отличаются от классов разветвленных JVM, что приводит к вашей ошибке. Вы можете избежать этих проблем с сериализацией, явно определив UID, но ваши классы все равно не будут инструментированы.

Вместо этого попробуйте аннотировать тесты с помощью @Fork(0), что полностью отключит разветвление. Однако вы должны быть осторожны, если это слишком сильно искажает ваши результаты. Это тот случай, когда ваш код можно сильно оптимизировать с помощью профилирования. Это особенно верно, если вы разделяете код между своими тестами, где профиль из первых тестов будет влиять на ваши другие тесты, обычно в худшую сторону.

Другое решение — также применить агент к разветвленной JVM. Для этого аннотация @Fork предлагает несколько параметров. Для вашего примера вы можете определить:

@Fork(jvmArgs = "-javaagent:/home/ssube/btrace/build/btrace-agent.jar=scriptdir=/home/ssube/btrace/scripts/,port=0")

Однако обратите внимание, что это делает вашу сборку зависимой от вашей файловой системы.

person Rafael Winterhalter    schedule 15.08.2014
comment
Метод @Fork(jvmArgs) у меня не работает: появляется та же ошибка serialVersionUID. Использование @Fork(0) действительно работает и, к счастью, не сильно меняет результаты моих тестов, но, безусловно, является хорошим общим решением. - person ssube; 15.08.2014
comment
@ssube Я только что увидел, что у вас возникла ошибка сериализации для классов JMH. С недавним исправлением JMH он должен работать без добавления идентификаторов в ваши классы. Подробнее см. ответ Алексея. - person Rafael Winterhalter; 18.08.2014
comment
На данный момент это вполне функциональный обходной путь. В зависимости от ваших тестов разветвление может изменить или не изменить результаты (в моем случае это не так). Однако я собираюсь принять ответ, который является исправлением, а не обходным путем. - person ssube; 18.08.2014
comment
Трудно превзойти ответ, который является исправлением сопровождающего, вы извините. - person Rafael Winterhalter; 18.08.2014