Вопрос-ответ

How do I write a correct micro-benchmark in Java?

Как мне написать правильный микро-бенчмарк на Java?

Как написать (и запустить) правильный микро-бенчмарк на Java?

Я ищу несколько примеров кода и комментариев, иллюстрирующих различные вещи, над которыми стоит подумать.

Пример: Должен ли бенчмарк измерять время / итерацию или итерации / время и почему?

По теме: Допустим ли бенчмаркинг по секундомеру?

Переведено автоматически
Ответ 1

Советы по написанию микро-бенчмарков от создателей Java HotSpot:

Правило 0: Прочитайте авторитетную статью о JVM и микро-бенчмаркинге. Хорошая статья - Брайан Гетц, 2005. Не ожидайте слишком многого от микро-бенчмарков; они измеряют лишь ограниченный диапазон характеристик производительности JVM.

Правило 1: Всегда включайте фазу прогрева, которая полностью запускает ваше тестовое ядро, достаточную для запуска всех инициализаций и компиляций перед фазой (фазами) синхронизации. (На этапе прогрева допустимо меньшее количество итераций. Эмпирическое правило - несколько десятков тысяч итераций внутреннего цикла.)

Правило 2: Всегда запускайте с -XX:+PrintCompilation, -verbose:gc и т.д., Чтобы вы могли убедиться, что компилятор и другие части JVM не выполняют непредвиденную работу на этапе синхронизации.

Правило 2.1: Выводите сообщения в начале и конце фаз синхронизации и прогрева, чтобы вы могли убедиться, что на этапе синхронизации нет выходных данных из правила 2.

Правило 3: Помните о разнице между -client и -server, а также OSR и обычными компиляциями. Флаг -XX:+PrintCompilation сообщает о компиляциях OSR со знаком at для обозначения не начальной точки входа, например: Trouble$1::run @ 2 (41 bytes). Предпочитайте сервер клиенту, а обычный OSR - OSR, если вам нужна максимальная производительность.

Правило 4: Помните об эффектах инициализации. Не печатайте в первый раз на этапе синхронизации, поскольку печать загружает и инициализирует классы. Не загружайте новые классы вне фазы прогрева (или фазы заключительного отчета), если только вы специально не тестируете загрузку классов (и в этом случае загружайте только тестовые классы). Правило 2 - это ваша первая линия защиты от подобных эффектов.

Правило 5: Помните об эффектах деоптимизации и перекомпиляции. Не используйте какой-либо путь к коду в первый раз на этапе синхронизации, потому что компилятор может отбросить и перекомпилировать код, основываясь на более раннем оптимистичном предположении, что путь вообще не собирался использоваться. Правило 2 - это ваша первая линия защиты от подобных эффектов.

Правило 6: Используйте соответствующие инструменты, чтобы читать мысли компилятора и ожидать, что код, который он создает, будет удивлен. Проверьте код самостоятельно, прежде чем строить теории о том, что делает что-то быстрее или медленнее.

Правило 7: Уменьшите шум в ваших измерениях. Запустите свой бенчмарк на тихой машине и запустите его несколько раз, отбрасывая выбросы. Используйте -Xbatch для сериализации компилятора с приложением и рассмотрите возможность настройки -XX:CICompilerCount=1 для предотвращения параллельной работы компилятора с самим собой. Делайте все возможное, чтобы уменьшить накладные расходы на сборку данных, устанавливайте Xmx(достаточно большие) equals Xms и используйте UseEpsilonGC, если это доступно.

Правило 8: Используйте библиотеку для своего бенчмарка, поскольку она, вероятно, более эффективна и уже была отлажена исключительно для этой цели. Такой как JMH, Caliper или отличные бенчмарки Билла и Пола UCSD для Java.

Ответ 2

I know this question has been marked as answered but I wanted to mention two libraries that help us to write micro benchmarks

Caliper from Google

Getting started tutorials


  1. http://codingjunkie.net/micro-benchmarking-with-caliper/

  2. http://vertexlabs.co.uk/blog/caliper

JMH from OpenJDK

Getting started tutorials


  1. Avoiding Benchmarking Pitfalls on the JVM

  2. Using JMH for Java Microbenchmarking

  3. Introduction to JMH

Ответ 3

Important things for Java benchmarks are:


  • Warm up the JIT first by running the code several times before timing it

  • Make sure you run it for long enough to be able to measure the results in seconds or (better) tens of seconds

  • While you can't call System.gc() between iterations, it's a good idea to run it between tests, so that each test will hopefully get a "clean" memory space to work with. (Yes, gc() is more of a hint than a guarantee, but it's very likely that it really will garbage collect in my experience.)

  • I like to display iterations and time, and a score of time/iteration which can be scaled such that the "best" algorithm gets a score of 1.0 and others are scored in a relative fashion. This means you can run all algorithms for a longish time, varying both number of iterations and time, but still getting comparable results.

I'm just in the process of blogging about the design of a benchmarking framework in .NET. I've got a couple of earlier posts which may be able to give you some ideas - not everything will be appropriate, of course, but some of it may be.

Ответ 4

jmh is a recent addition to OpenJDK and has been written by some performance engineers from Oracle. Certainly worth a look.


The jmh is a Java harness for building, running, and analysing nano/micro/macro benchmarks written in Java and other languages targetting the JVM.


Very interesting pieces of information buried in the sample tests comments.

See also:

java jvm