Pull to refresh

Comments 32

1. странно, что не упомянута библиотека perf4j
2. Мне кажется, что чаще без профайлера надо работать, когда приходишь к клиенту у которого инсталлирована твоя программа. Там изменения кода не помогут, а вот знания флагов JVM очень полезны
3. При разработке мне кажется всё же почти всегда удобнее пользоваться готовыми профайлерами, которые точно также будут делать sampling и инструментацию байт кода, только лучше
Из готовых библиотек для профилировки, которые спасли много часов мне и коллегам, я бы упомянул о: jetm и JavaMelody
Доклад был не о библиотеках профилирования, а о том как сделать самому. Конечно, если готовый профайлер решает вашу задачу, то логично им воспользоваться. А если нет, то приходится что-то делать самому.

я не спец по профелированию, a потому хочу спросить: чем вас не устаривают jconsole и visualvm?
Если «вас» — это вы ко мне, то разочарую. Я мало программирую на Java, я лишь составил стенограмму выступления автора, у которого нет habraaccounta (это самый первый абзац текста).

Но напомню посыл автора — в профилировании живого высоконагруженного приложения, только самодельным низкоуровневым профилированием вы сможете нащупать компромисс между потерями производительности и получением нужной информации.
Смысл доклада передан верно :)
… но аккаунт у меня есть.
Тчорт! Я искал! Сейчас внесу правки в текст.
Порадовало, что упомянули ASM: приходилось по одной учебной дисциплине заниматься динамическим программным анализом с этой библиотекой, было интересно.
… вы убъете кучу времени в нем разбираясь. Инструменты надо учиться, а делать что-то самому, конечно, намного приятней…
— следуя вашей логике так и Java неинтересно, лучше свой язык написать.
А вообще вы или неоговораиваете почему не решили использовать существующие наработки или у вас в отделе разработки бардак и все делают что ему вздумается. Слишком сложные сторонние инструменты, докажите, покажите что вы провели анализ предметной области, а не занимаетесь разработкой велосипедов с квадратными колёсами.
То что вы сказали о профайлинге аллокаций памяти, я даже как человек который не занимается активной разработкой под Java, а просто пасивно просматривая статьи по теме, скажу что это полное незнание предмета.
Рассмотрим например продукт foursquare engineering.foursquare.com/2012/02/02/heapaudit-jvm-memory-profiler-for-the-real-world/ — с вашим подходом что вы вообще увидите при доступе к памяти другого ядра в NUMA-архитектуре?
Вы вообще не упомянули DTrace, на какой вообще Java вы пишете? JDK 1.1.3?
Возможно для разработки собственных инструментов действительно были причины, но только что я постоянно отмечаю у наших докладчиков, что они сошлются на «неведомые» причины (мы крутая финансовая организация) и считаю что «прокатит».
Вы упоминаете «финансы», «большую производительность», сравните например эту статью www.infoq.com/articles/scalable-java-components и ваш доклад, ваш получился из разряда «я выучил Java».
Как я бы улучшил ваш доклад:
— выбросить финансы и высокие нагрузки, поскольку это формирует завышеные ожидания к уровню доклада
— Назвать обзорный доклад native-средств Java, для случаев когда нужно разобраться в существующей системе которую нельзя трогать или к которой нет доступа, например post-mortem dump от клиента, или система у клиента к которым ограничен прямой доступ.
— Говорить о профилировании и не сказать ни слова о DTrace, скажет скорее о незнании предмета.
— Если упоминаете о существовании стороних инструментов, хороший докладчик приведёт хорошие аргументы для сравниения, а не отделается общими фразами.
Бывает масса случаев когда и язык свой надо написать. Всё зависит от стоящей перед вами задачи. В любом случая, я считаю что каждый обязан знать как именно устроен компилятор, виртуальная машина, и операционная система и в принципе понимать как это можно всё написать. Тогда будет программист будет ценить уже готовые инструменты и понимать в каких случаях их нужно применять.

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

Суть моей претензии в том что вы своими «финансовая сфера, высокие нагрузки» сформировали свосем другой уровень ожиданий к докладу, тогда как в нём показаны азы.
К сожалению, очень часто говоря про «финансовую сферу и высокие нагрузки» начинают с придыханием рассказывать про какие-нибудь много-мегабайтные каркасы, библиотеки и иснтрументы, при этом вообще не понимая азов: как они устроены изнутри, почему и на каких принципах они работают. Инстументы это отличная вещь, если вы понимаете как они устроены. Например, зная внутренее устройство DTrace намного проще понимать когда его нужно применять, а когда нет.

Мне казалось, что в анонсе своего доклада на ADD-2011 я достачно полно расклыл суть того, о чем я буду говорить (цитирую): «В докладе пойдет речь о методиках изучения производительности Java приложений без использования готовых сторонних инструментов профилирования, а используя не так широко известные встроенные в JVM возможности (threaddumps, java agents, bytecode manipulation).»

Как это моголо сформировать какие-то ложные ожидания?
Похоже я слишком развращён западными докладчиками и когда слышу финансы и высокие нагрузки я ожидал услышать что-то вроде:
martinfowler.com/articles/lmax.html
www.infoq.com/presentations/Tuning-Java-for-Virtual-with-EM4J
www.infoq.com/presentations/Java-without-the-GC-Pauses
www.infoq.com/presentations/Understanding-Java-Garbage-Collection
Куча графиков, объяснений.
Думаю мы можем прекратить дискусию. Вы сделали интересный доклад, я ожидал услышать что-то для себя новое, но судя по откликам, вы свою аудиторию нашли.
Спасибо. Моя цель была сделать доклад интересным для программистов, которым не приходилось глубоко разбираться в возможностях JVM. Безусловно, если Вы знакомы c threadumps, java agents и bytecode manipulation, то Вы вряд ли найдете в этом докладе что-то нового для себя. Так же как, например, люди профессионально многие годы занимающиеся дизайном и оптимизацией высоконгруженных финансовых приложений не найдут для себя много новой информации в перечисленных выше докладах очень уважаемых людей. И это естественно, ибо это не научные статьи с новыми никому доселе не известными знаниями. Обо всём этом можно было прочитать много лет назад. У каждого доклада своя аудитория.

Еще раз спасибо за проявленный интерес и коментарии. Буду пытаться в будущих докладах расширить «диаппазон», то есть буду стараться сделать их интересными более широкому кругу слушателей.
Кстати, большое спасибо за ссылку на Foursquare Heapaudit!

Приятно видеть, когда в других компаниях (в данном случае Foursquare) думают точно также как и мы — если готовые инструменты не решают нашу задачу (и да, мы, как я уверен и Foursquare, очень глубоко знакомы с DTrace и он эту задачу не решает), то инстурумент для её решения надо писать самим. Мы сделали это в 2005 год (и в прошлом году у меня долшли руки сделать на эту тему доклад).

Тот факт, что Foursquare сделало это сейчас, говорит о том, что DIY Java Profiling не потеряло актуальность за прошедшие 7 лет. Кстати, мы (Devexperts) тоже планируем выложить наш инструмент под открытой лицензией. Stay Tuned!
UFO just landed and posted this here
Единственный реальный выход — это использовать нативный код, для x86 процессора есть такая замечательная инструкция rdtsc, которая возращает счетчик количества тактов процессора. Напрямую к ней доступа нет, можно написать на C однострочный метод, который вызывает «rdtsc», а дальше слинковать его с Java-кодом, и вызывать из Java. Этот вызов вам займет сто тактов

Судя по этой статье, System.nanoTime() как раз и будет порядка 100 тактов на TSC таймере.

Жаль, автора тут нет, хотелось бы услышать комментарий…
Тем более что книга Effective Java рекомендует использовать nanoTime для измерения интервалов…
Залез в исходники OpenJDK, nanoTime для Linux использует clock_gettime(CLOCK_MONOTONIC) для получения времени, который, в свою очередь, использует либо TSC, либо HPET на x86 для получения точного времени (ядро 3.3.5)

Т.е. утверждение «Напрямую к ней доступа нет» — неверно, System.nanoTime() использует инструкцию rdtsc, по крайней мере в Linux 3.3.5 (а реально, и в гораздо более ранних версиях тоже).

Получается, что и nanoTime, и currentTimeMillis используют native-вызовы, но nanoTime должна быть быстрее чем currentTimeMillis, т.к. использует инструкцию rdstc. Чуть позже попробую потестировать.
Чуть позже попробую потестировать.

Было бы интересное дополнение («нанотехнологии на марше»). Ждем.

Набросал очень простой микробенчмарк на Google Caliper
Вот исходники, каждый может проверить на своей машине github.com/relgames/ClockTest

Мои результаты:
Intel® Pentium® D CPU 3.20GHz
Linux 2.6.38-15-generic #59-Ubuntu SMP Fri Apr 27 16:04:29 UTC 2012 i686 i686 i386 GNU/Linux
Java(TM) SE Runtime Environment (build 1.7.0_04-b20) Java HotSpot(TM) Client VM (build 23.0-b21, mixed mode)

relgames@oleg:~/myprojects/ClockTest$ java -jar target/clocktest-1.0-SNAPSHOT-jar-with-dependencies.jar --trials 5
 0% Scenario{vm=java, trial=0, benchmark=CurrentTimeMillis} 0,66 ns; σ=0,02 ns @ 10 trials
10% Scenario{vm=java, trial=1, benchmark=CurrentTimeMillis} 0,67 ns; σ=0,01 ns @ 10 trials
20% Scenario{vm=java, trial=2, benchmark=CurrentTimeMillis} 0,66 ns; σ=0,00 ns @ 3 trials
30% Scenario{vm=java, trial=3, benchmark=CurrentTimeMillis} 0,67 ns; σ=0,01 ns @ 10 trials
40% Scenario{vm=java, trial=4, benchmark=CurrentTimeMillis} 0,67 ns; σ=0,01 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=NanoTime} 0,66 ns; σ=0,01 ns @ 10 trials
60% Scenario{vm=java, trial=1, benchmark=NanoTime} 0,67 ns; σ=0,01 ns @ 10 trials
70% Scenario{vm=java, trial=2, benchmark=NanoTime} 0,67 ns; σ=0,01 ns @ 10 trials
80% Scenario{vm=java, trial=3, benchmark=NanoTime} 0,68 ns; σ=0,01 ns @ 10 trials
90% Scenario{vm=java, trial=4, benchmark=NanoTime} 0,68 ns; σ=0,01 ns @ 10 trials

        benchmark trial    ns linear runtime
CurrentTimeMillis     0 0,664 =============================
CurrentTimeMillis     1 0,669 =============================
CurrentTimeMillis     2 0,656 ============================
CurrentTimeMillis     3 0,665 =============================
CurrentTimeMillis     4 0,667 =============================
         NanoTime     0 0,665 =============================
         NanoTime     1 0,674 =============================
         NanoTime     2 0,674 =============================
         NanoTime     3 0,680 ==============================
         NanoTime     4 0,676 =============================


3.20GHz — это 0.3125нс на такт, 2 такта это 0.625нс
Т.е. каждый вызов — это 2 такта, погрешность вызвана неточностью расчетов в ядре (тут принимаю комментарии, ибо не вполне уверен, почему так)

Выводы: на моей машине вызов currentTimeMillis и nanoTime занимает одинаковое время, а именно 2 такта.
Вы ничего не замеряете в своем коде. HotSpot (-server уж точно) оптимизует (уберет) ваши вызовы, ибо вы ни как не используете их результат. Я рекомендую внимательно изучить документацию к Google Caliper (там вполне адекватная подборка советов), а также другую литературу посвященную написанию microbenchmarks.
Они сами так делают.

Переписал. Вот новые результаты:
0% Scenario{vm=java, trial=0, benchmark=CurrentTimeMillis} 500,36 ns; σ=0,42 ns @ 3 trials
10% Scenario{vm=java, trial=1, benchmark=CurrentTimeMillis} 509,32 ns; σ=4,70 ns @ 5 trials
20% Scenario{vm=java, trial=2, benchmark=CurrentTimeMillis} 500,87 ns; σ=0,76 ns @ 3 trials
30% Scenario{vm=java, trial=3, benchmark=CurrentTimeMillis} 496,79 ns; σ=2,31 ns @ 3 trials
40% Scenario{vm=java, trial=4, benchmark=CurrentTimeMillis} 501,60 ns; σ=3,01 ns @ 3 trials
50% Scenario{vm=java, trial=0, benchmark=NanoTime} 505,25 ns; σ=4,90 ns @ 3 trials
60% Scenario{vm=java, trial=1, benchmark=NanoTime} 513,66 ns; σ=4,92 ns @ 3 trials
70% Scenario{vm=java, trial=2, benchmark=NanoTime} 518,22 ns; σ=6,33 ns @ 10 trials
80% Scenario{vm=java, trial=3, benchmark=NanoTime} 507,69 ns; σ=5,77 ns @ 10 trials
90% Scenario{vm=java, trial=4, benchmark=NanoTime} 510,61 ns; σ=2,24 ns @ 3 trials

        benchmark trial  ns linear runtime
CurrentTimeMillis     0 500 ============================
CurrentTimeMillis     1 509 =============================
CurrentTimeMillis     2 501 ============================
CurrentTimeMillis     3 497 ============================
CurrentTimeMillis     4 502 =============================
         NanoTime     0 505 =============================
         NanoTime     1 514 =============================
         NanoTime     2 518 ==============================
         NanoTime     3 508 =============================
         NanoTime     4 511 =============================


Похоже, Вы правы. ~1600 тактов на вызов.

А как JVM может выкидывать вызов native метода? Или она знает, что эти методы ничего не меняют, а только читают счетчик?

Чуть позже сделаю версию с native rdtsc; похоже, в Linux тратится много тактов на ядро. Как я понял из исходников, они в начале опрашивают wall clock, и потом прибавляют результат rdtsc, чтобы получить время в нс.
В НоtSpot эти методы intrinsic.
System.nanoTime делает много больше, чем RDTSC. В числе прочего он пересчитывает такты процессора в наносекунды и гарантирует неубываемость результатов. Что именно вам подходит лучше (RDTSC или System.nanoTime) зависит от вашей конкретной ситуации.

Например, в своей серии статей о производительности я использую System.nanoTime для всех замеров, но в своей практике сталкивался с реальными случаями, когда был нужен именно RDTSC.
Блог это не мой memory dump :) Логичного повода упомянуть про RDTSC в блоге пока не было. Да и вообще вряд ли я смогу написать что-то новое про RDTSC — Google вам поможет если вы хотите про него больше знать.
Есть у меня аккунт на хабре, только я сюда не пишу. Я пишу все свои техничесные заметки в свой журнал. Там же есть запись про этот доклад, в которой содержаться мои дополнительные мысли и разъяснения на тему доклада. Но я готов отвечать на вопросы и здесь.
Весьма познавательно! Вольно перевел вашу статью-стенограмму на английский для коллег :) Результат тут.
Инструменты надо учиться, а делать что-то самому, конечно, намного приятней.
Обычно это основной аргумент у разработчиков для разработки нового велосипеда)
Судя по роликам типа этого
( https://youtu.be/8piqauDj2yo ), concurrency — это как раз такая область, где абстракции часто оказываются дырявыми, а велосипеды — самым эффективным решением…
Sign up to leave a comment.

Articles