Как быть уверенным, что блок кода был составлен JIT?

При проведении тестирования производительности Java-кода вы хотите протестировать JIT-скомпилированный код, а не raw-байт-код. Чтобы скомпилировать байт-код, вы должны инициировать компиляцию, выполняя код несколько раз, а также допускать достаточное время выполнения фонового потока для завершения компиляции.

  • Какое минимальное количество "разогревающих" исполнений пути кода должно быть "очень уверенным" в том, что код будет скомпилирован JIT?
  • Какое минимальное время сна основного потока должно быть "очень уверенным" в том, что компиляция завершена (предполагая небольшой блок кода)?

Я ищу порог, который будет безопасно применяться в любой современной ОС, скажем, Mac OS или Windows для среды разработки и Linux для CI/production.

Ответ 1

Поскольку намерение OP на самом деле не выясняет, является ли блок JIT-скомпилированным, но скорее убедитесь, что он измеряет оптимизированный код, я думаю, что OP должен смотреть некоторые из этих переговоров по бенчмаркингу.

TL; версия DR: нет надежного способа выяснить, попадете ли вы в "устойчивое состояние":

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

  • Наблюдение -XX:+PrintCompilation не является надежным, потому что вы можете находиться в фазе, когда счетчики все еще находятся в движении, и JIT стоит, чтобы скомпилировать следующую партию горячих методов. Из-за этого вы можете легко иметь несколько плавательных бассейнов. Метод может даже перекомпилировать несколько раз, в зависимости от количества многоуровневых компиляторов.

  • В то время как можно утверждать о пороговых значениях вызова, эти вещи также не являются надежными, поскольку может быть задействована многоуровневая компиляция, метод может быстрее вписаться в вызывающего абонента, вероятностные счетчики могут пропустить обновления и т.д. Это, общая мудрость о -XX:CompileThreshold=# ненадежна.

  • Компиляция JIT не является единственным эффектом разминки, который вы используете. Автоматическая эвристика GC, эвристика планировщика и т.д. Также требуют разминки.

Получите микрообъектив, который облегчит вам задачу!

Ответ 2

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

Кроме того, компиляция "реального мира" зависит от контекста, в котором выполняется ваш байт-код. Например, компиляция может произойти, когда сайт мономорфного вызова продвигается до мегаморфного, так что наблюдаемая компиляция фактически представляет собой де-оптимизацию. Поэтому будьте осторожны, если предположить, что ваш микрозадача отражает фактическую производительность кода.

Вместо предлагаемого флага я предлагаю вам использовать CompilationMXBean, который позволяет вам проверять количество времени, которое JVM все еще тратит с компиляцией. Если это время слишком велико, повторите тест, пока значение не станет достаточно стабильным. (Будьте терпеливы!) Рамки могут помочь вам в создании хороших тестов. Лично мне нравится caliper. Однако никогда не доверяйте своему эталону.

Из моего опыта, пользовательский байтовый код лучше всего работает, когда вы меняете идиомы javac. Чтобы упомянуть один анекдот, который я могу рассказать по этому поводу, однажды написал пользовательский байт-код для исходного кода Java, эквивалентный:

int[] array = {1, 2, 3};

javac создает массив и использует dup для назначения каждого значения, но я сохранил ссылку на массив в локальной переменной и загрузил его обратно в стек операнда для назначения каждого значения. Массив имел больший размер, чем тот, и наблюдалась заметная разница в производительности.

Наконец, я рекомендую эту статью перед тем, как написать тест.

Ответ 3

Не уверен в цифрах, но при выполнении тестов скорости я делаю:

  • Запустите с -XX:-PrintCompilation флаг
  • Разбавьте JVM до тех пор, пока не будет создано больше сообщений об отладке компиляции, и, если возможно, синхронизация станет согласованной.