Какие ошибки чаще всего делают самодельный микробенчмарк бессмысленным?
- Почему замеру через System.nanoTime в цикле нельзя верить?
- Коллега замерил два варианта кода через System.nanoTime в цикле и сделал вывод о производительности. Почему такому замеру нельзя верить?
Нет прогрева — меряется интерпретатор, а не скомпилированный код. Результат не используется — JIT выбрасывает вычисление, меряется пустой цикл. Константный вход — выражение сворачивается при компиляции. Плюс шум GC, кэшей, частоты процессора.
- Все три ошибки дают одинаково «впечатляющие» результаты
- JMH: Blackhole, @State, прогрев и форки
- Один прогон — не статистика
А ещё Профилировщик (async-profiler) часто полезнее микробенчмарка
Подробно
Все три ошибки приводят к одинаково впечатляющему результату: измеряемый код просто исчезает. JIT вправе удалить вычисление, результат которого никому не нужен, и свернуть выражение, вход которого известен заранее. Именно поэтому JMH предлагает Blackhole для потребления результата и аннотацию State для входных данных, которые компилятор не сможет счесть константами, а также сам управляет прогревом и итерациями. К этому добавляются менее очевидные факторы, которые JMH тоже учитывает: разброс между запусками JVM, влияние сборки мусора и профиль, накопленный предыдущими бенчмарками в том же процессе. Общий вывод для собеседования — измерять микропроизводительность вручную практически невозможно, и правильный ответ на вопрос «как вы это измеряли» звучит как JMH.
Что хотят услышать
- Три классические ошибки и почему.
- Как решает JMH.
Частые ошибки
- Верить результатам замера через System.nanoTime без прогрева.
- Игнорировать разброс между запусками и мерить один раз.
Проверьте себя
Несколько верных вариантов. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✓Нет прогрева: измеряется интерпретируемый код
- ✗Использование long вместо int для накопления результата: 64-битная арифметика заметно искажает замер
- ✓Мёртвый код: результат не используется, и JIT выбрасывает вычисление
- ✓Свёртка констант: вход известен заранее, и вычисление делается раз
Что спросят дальше
- Зачем нужен Blackhole?
- Почему один прогон JVM не даёт надёжного результата?
- Что такое деоптимизация и почему она случается после долгой работы?
- Когда микробенчмарк вообще не нужен?
Разбор темы
- JIT, оптимизации и бенчмаркинг
Tiered compilation C1/C2, ключевые оптимизации JIT (inlining, escape analysis), деоптимизация и прогрев, корректные микробенчмарки на JMH.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.