Что может заставить мой код работать медленнее, когда сервер JIT активирован? - PullRequest
4 голосов
/ 27 мая 2010

Я делаю некоторые оптимизации на декодере MPEG. Чтобы убедиться, что мои оптимизации ничего не нарушают, у меня есть набор тестов, который тестирует всю кодовую базу (как оптимизированную, так и оригинальную), а также проверяет, что они оба дают идентичные результаты (в основном, просто пропуская пару разных потоков через декодер и crc32). выходы).

При использовании опции "-server" с Sun 1.6.0_18 набор тестов работает на 12% медленнее на оптимизированной версии после прогрева (по сравнению с настройкой по умолчанию "-client"), в то время как исходная кодовая база увеличивается хороший импульс, работающий примерно в два раза быстрее, чем в режиме клиента.

Хотя поначалу мне это казалось просто проблемой, я добавил цикл, чтобы повторить весь набор тестов несколько раз. Затем время выполнения становится постоянным для каждого прохода, начиная с 3-й итерации теста, но оптимизированная версия остается на 12% медленнее, чем в режиме клиента.

Я также почти уверен, что это не проблема сбора мусора, так как код не требует абсолютно никаких выделений объектов после запуска. Код состоит в основном из нескольких операций с битами (потоковое декодирование) и множества базовых математических вычислений (генерирование звука PCM) Используются только классы JDK - ByteArrayInputStream (передает поток в тест и исключает дисковый ввод-вывод из тестов) и CRC32 (для проверки результата). Я также наблюдал такое же поведение с Sun JDK 1.7.0_b98 (только там 15% вместо 12%). О, и все тесты проводились на одной машине (одноядерном) без запуска других приложений (WinXP). Хотя есть некоторые неизбежные различия в измеренных временах выполнения (с использованием System.nanoTime, кстати), разница между различными тестовыми прогонами с одинаковыми настройками никогда не превышала 2%, обычно менее 1% (после прогрева), поэтому я заключаю, что эффект реальный, а не чисто индуцированный измерительным механизмом / машиной.

Существуют ли какие-либо известные шаблоны кодирования, которые хуже работают на сервере JIT? В противном случае, какие варианты доступны, чтобы «заглянуть» под капот и посмотреть, что там делает JIT?

  • Может быть, я неверно описал свое "прогревочное" описание. Там нет явного кода разминки. Весь набор тестов (состоящий из 12 различных потоков MPEG, содержащий ~ 180 тыс. Аудиокадров) выполняется 10 раз, и я считаю, что первые 3 прогона являются «прогревом». Один тестовый цикл занимает около 40 секунд 100% процессора на моей машине.

  • Я играл с опциями JVM, как было предложено, и использовал "-Xms512m -Xmx512m -Xss128k -server -XX: CompileThreshold = 1 -XX: + PrintCompilation -XX: + AggressiveOpts -XX: + PrintGC" Я мог проверить что вся компиляция происходит в первые 3 раунда. Сборка мусора происходит каждые 3-4 раунда и занимает не более 40 мс (512 м чрезвычайно большой, так как тесты можно запустить с 16 м просто отлично). Из этого я делаю вывод, что сборка мусора не имеет здесь никакого влияния. Тем не менее, при сравнении клиента с сервером (другие параметры не изменились) разница в 12/15% остается.

1 Ответ

6 голосов
/ 27 мая 2010

Как вы уже видели, JIT может искажать результаты теста, поскольку он работает в фоновом потоке, краже циклов ЦП из основного потока, выполняющего тест.

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

HotSpot не компилирует методы сразу, а ждет, пока метод не будет выполнен определенное количество раз. На странице для параметров -XX указано, что значение по умолчанию для -server составляет 10000 раз, а для -client - 1500 раз. Это может быть причиной замедление, особенно если ваша разминка завершается вызовом многих критических методов от 1500 до 10000 раз: с опцией -client они будут JITed на этапе разогрева, но при запуске с -server компиляция может задержать выполнение вашего профилированного кода.

Вы можете изменить количество вызовов методов, необходимых до того, как HotSpot скомпилирует метод, установив -XX:CompileThreshold. Я выбираю двадцать, чтобы даже смутно горячие точки (теплые пятна?) Конвертировались во время прогрева, даже когда тест запускается всего несколько раз. Это работало для меня в прошлом, но YMMV и другие значения могут дать вам лучшие результаты.

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

См

...