Ява снова доступна!


Хотя правооблатетели торговой марки Java™ не признают, что произношение острова Jawa имеет отношение к их продукту, логотип, напоминающий чашечку дымящегося кофе, довольно устойчиво ассоциируется с замечательным кофе Лювак, проиводящимся в Индонезии, и вкус которого запомнится любому попробовавшему его кофеману.

Спустя 6 лет после сильнейшего цунами, обрушевшегося на остров Ява, туристы снова потянулись на этот удивительный индонезийский остров. Все возвращается на круги своя. Многие пользователи старого доброго VTune Performance Analyser наверняка помнят, что в нем поддерживался анализ Java-приложений, хотя этот тип профилировки имеет довольно специфичное назначение. С выходом нового поколения продуктов Parallel Amplifier и VTune Amplifier XE, поддержка Java как-то исчезла из списка приоритетных задач и не была востребована пользователями. Но сейчас возник новый интерес к профилировке производительности «чистых» Java и особенно гибридных Java + нативных C/C++ приложений. Поэтому этот инструмент снова появляется в VTune Amplifier XE в дополнение к поддержке jit-компилированных приложений.

Итак, что же позволяет нам сделать профилировка Java-приложений. Основное назначение профилировки – это выявление функций или участков кода, которые больше всего занимают процессорное время, и определить, насколько эффективно они это делают. Не смотря на то, что код выполняется под управлением Managed Run Time Environment, оперирование данными в памяти может быть также неэффективным, как и в нативных приложениях. Например, учитывать кэш-иерархию системы памяти и скорость доступа к массивам в основной физической памяти системы можно и нужно при написании Java-кода. В этом смысле профилировка Java-приложения почти ничем не отличается от профилировки C/C++ приложения, кроме, наверное, того, что показатели производительности теперь надо отображать относительно исходного кода, который виртуальная машина (JVM) выполняла как ей заблагорассудится (либо скомпилировала, либо интерпретировала), и еще в специальном виртуальном адресном пространстве.

Тем не менее, в результате Hotspot-анализа мы получаем список самых «горячих» функций-методов, выполнявшихся в приложении, с временными характеристиками, а также стеки их вызовов. Обратите внимание, что распределение нагрузки по потокам тоже отображается в результатах, а именованые потоки помогают определить, где выполнялся «тяжелый» код.



Не секрет, что в приложениях, где некоторый функционал требует максимальной производительности на платформе, часто прибегают к такой хитрости: наиболее критичные участки программы пишут и компилируют на низкоуровневых языках, например на С или даже на ассемблере. Это делают чтобы задействовать некоторые архитектурные особенности процессора, например векторный вычислитель. Часто такие функции и являются хотспотами, так как берут на себя львиную долю вычислительной нагрузки. Но иногда нам необходимо определить, откуда они были вызваны, что может оказаться проблемой в гибридном коде, потому что часть алгоритма вычисления реализована в Java-коде, а С-код вызывается с помощью интерфейса JNI.

В результатах Hotspot-анализа вы увидлите, что VTune Amplifier XE «сшивает» стеки вызовов сделанных из Java-кода, и перенаправленных в нативный C-код. Впрочем, и обратные вызовы из С-модуля в Java будут отображены на панели стеков.



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

Тем, кто любит поковыряться в недрах процессорного конвеера и вычислительных блоках, предлагается Hardware Event-based Sampling анализ, который позволяет собирать процессорные аппаратные события, и по их соотношениям или метрикам (как встроенным, так и пользовательским) судить о тех или иных проблемах в очереди исполнения команд. Все результаты в виде Hardware Events и метрик доступны на уровне методов и исходного кода Java-программы.



К сожалению, JVM-машина, выполняя различные трюки с исходным кодом, не всегда обеспечивает информацию о точном соответствии адреса исполняемой инструкции номеру строки исходного кода. В результате мы можем получить некоторое «сползание» временных значений относительно строк исходника. А если это цикл, то правильное время CPU Time может "уползти" и вверх. Здесь нужно просто быть внимательным, и оценивать какая именно из соседних строк с кодом может соответствовать результатам.



Иногда JVM предпочитает некоторые не часто вызываемые методы проинтерпретировать, так как компиляция требует большего времени. Символы таких функций мы пока не умеем надежно определять, поэтому они будут заменены на символ “!Interpreter” в стеке вызовов. Если вам необходимо увидеть эту функцию в стеке, заставьте JVM скомпилировать все методы опцией “–Xcomp”. Хотя и в этом случае нет гарантии появления символа в стеке, так как некоторые функции могут быть «заинлайнены».



Есть ли еще какие-либо ограничения в анализе Java-приложений? Конечно же есть. Поддержать все многообразие Java Runtime Environment (JRE) довольно сложно, поэтому мы остановились на поддержке Oracle* Java 6 и 7. Кроме того, профилировка полностью поддержвается в рамках Hotspot-анализа, и анализа на основе Hardware Event-based Sampling (например Lightweight Hotspot), а Cuncurrency-анализ ограничен тем, что некоторые встроенные в Java примитивы синхронизации (которые не вызывают напрямую объекты синхронизации ядра ОС) мы не сможем распознать, вследствие чего, некоторые временные характеристики могут быть искажены. Тоже самое относится и к Locks&Waits анализу. Пользователь пока не может прикрепиться инструментом к jre-процессу во время исполнения и у нас нет специальных библиотек, поддерживающих User API для управления коллекцией в коде Java-приложений. Но особо настойчивые могут попытаться «прикрутить» обычный API для С-программ, обернув соответствующие _itt вызовы JNI-функциями.

Ну и маленький совет тем, кто профилирует Java-приложения под Linux: на linux x86 платформах используйте клиентскую JVM, а не серверную, или специфицируйте опцию “–client” в командной строке.

For more complete information about compiler optimizations, see our Optimization Notice.