Хабрахабр

Тысячи вещей, которые в Java стоило бы поправить с первой версии: большое интервью с Сергеем Куксенко из Oracle

0. Сергей Куксенко — перформанс-инженер, видевший Java еще версии 1. Производительностью Java занимается c 2005 года и в данный момент в Oracle работает над улучшением производительности JDK. За это время успел поучаствовать в разработке мобильных, клиентских, серверных приложений и виртуальных машин. Один из самых популярных докладчиков на Joker и JPoint.

Этот хабрапост — большое интервью с Сергеем, посвященное следующим темам:

  • Культ Производительности;
  • Когда и что нужно оптимизировать, изначальный дизайн языка и библиотеки;
  • Перспективные направления для дальнейшей оптимизации;
  • Как можно поучаствовать в разработке и что можно сломать оптимизациями;
  • Компиляторные трюки, размещение регистров;
  • Можно ли собрать кошку из фарша;
  • Когда тесты работают пять дней подряд и прочая бытовуха;
  • Как стать перформанс-инженером;
  • Подготовка доклада на следующий Joker.

О культе Производительности

Расскажи немножко, кто ты сейчас, чем ты занимаешься? Олег: Ты наш давний докладчик, и это не первое наше интервью.

Я работаю в команде Java Performance и отвечаю за производительность Java-машин Oracle, OpenJDK. Сергей: Я тот же самый, что и много лет назад, и занимаюсь тем же самым.

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

Всё зависит от другого. Сергей: Это хороший вопрос. С другой стороны, производительность с точки зрения бизнеса — это деньги. Подобное внимание аудитории можно считать излишним.

Если ты не обрабатываешь свои запросы достаточно быстро — всё, ты теряешь клиентов, теряешь деньги, теряешь всё остальное. Это реальные деньги, которые люди тратят на железо, на какие-нибудь облака в Amazon. Вопрос в том, насколько он является важным в каждом конкретном случае. Поэтому запрос на производительность, конечно же, всегда есть. Я уж молчу про high-frequency trading.

Олег: Кстати, как думаешь, Java подходит для этого?

Сергей: У тебя была возможность встречаться с таким человеком, как Питер Лори (Peter Lawrey)?

Олег: Это который CEO Chronicle Software, разработчики OpenHFT?

Они работают на Java в high-frequency trading, живут прекрасно. Сергей: Это очень известный товарищ из Лондона, который много ездит по конференциям.

Всё-таки разница есть. Олег: Они именно на Java это делают или из Java зовут нативный код?

В принципе, при желании, всего, чего нужно, можно достичь на самой Java. Сергей: Я на таком уровне не знаю, он это не рассказывал.

Если взять, к примеру, какое-нибудь сообщество питонистов, то у них куда меньше культ производительности. Олег: Интересно. Может, это вы спровоцировали культ перформанса своими докладами? Как получилось, что именно в нашем сообществе так происходит? Ты, Шипилев, Паньгин, Иванов и так далее.

Культ производительности на российской конференции заметно выше, чем на американской. Сергей: Не знаю, как так получилось. У нас люди хотят больше заниматься производительностью, им это интересно. Может быть, это отражает саму аудиторию. Но это гипотеза, догадки. А в той же Америке больше хотят заниматься тем, за что больше платят. Так сложилось.

Когда и что нужно оптимизировать

В какой момент нужно начинать задумываться о производительности? Олег: Ты сказал, что запрос на перформанс всё равно есть. Когда гром грянет?

Лучше ещё раз обратиться к кейноуту Алексея Шипилёва с одной из прошлых конференций, где он достаточно хорошо всё это расписал. Сергей: Это общий абстрактный вопрос.

Олег: Да, я помню «кривую имени Ш».

Необязательно сразу писать бенчмарки. Сергей: Заниматься перформансом нужно сразу, но смотря на каком уровне. Известно, например, что банальное ограничение уровня архитектуры API между Set’ом как множеством и SortedSet уже накладывает на нас фундаментальные алгоритмические ограничения.

Если мы в API запихнули SortedSet (хотя то, что он отсортированный, никому не нужно), а потом это расползлось по всей нашей системе, то потом эту штуку придется вырывать больно и трудно.

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

BigDecimal. Конкретный пример: я в свое время приседал вокруг класса java.math. Есть достаточно хороший, частный случай, когда у нас BigDecimal нифига не «Big», он просто Decimal, и нужно их читать. Был большой реквест с разных сторон его как-то разогнать.

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

Олег: Следует ли из этого, что при разработке стандартной библиотеки стоит отказаться от конструкторов и везде делать билдеры?

Сергей: Уже поздно.

Олег: Если бы не было поздно, это была бы хорошая идея?

Вот смотри: мы пишем new, и это new стоит снаружи конструктора. Сергей: Она бы дала больше пространства для манёвра. А иногда было бы очень полезно спрятать само создание объекта и создавать не тот объект, который у нас снаружи. Получаются две операции: сначала создаем объект, затем вызываем конструктор, который его заполняет. Это языковое ограничение, изначальное, с первых времен Java.

В изначальном дизайне языка можно было бы что-то такое добавить, встроенный dependency injection container? Олег: Ну, сейчас все пользуются DI-фреймворками, которые позволяют крутить прокси как хочешь и добавлять что угодно, обходя это ограничение.

Если вспомнить историю выхода Java 1. Сергей: У меня есть очень конкретное мнение по поводу изначального дизайна языка. 0, она выходила достаточно серьезным time pressure, нужно было все было сделать быстро.

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

Что ещё можно оптимизировать в Java

Возникает вопрос: за более 20 лет развития Java остались ли в JDK какие-то области, вмешательство в которые core-инженеров может привести к заметному эффекту? Олег: Обычные люди могут поправить что-то только в своем проекте, а вы как перформанс-инженеры JDK воздействуете сразу на сотни тысяч проектов. И насколько заметен этот «заметный эффект»?

Железо сейчас и железо 10 лет назад — это две большие разницы, и желательно делать различные оптимизации. Сергей: Во-первых, сейчас Java работает совсем не на том железе, что, скажем, 10 лет назад.

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

Вы же не верифицируете код формально. Олег: А как можно убедиться? Что такое «убедиться»?

В зависимости от размера фичи это подразумевает под собой иногда совсем немножко действий, иногда много разных усилий. Сергей: Убедиться, что всё ОК с точки зрения перформанса — это субъективное экспертное мнение performance-инженера, который напишет отчет и скажет, что «в этой фиче всё нормально». Начиная с того, что надо просто тупо сидеть, смотреть, что там делается, забенчмаркать эту область, погонять бенчмарки, посмотреть, что там получается на выходе, и принять разумное обоснованное решение.

Там есть что-то? Олег: А с точки зрения перформанса и новых фич — Java вообще вперед двигается? Потому что железо у нас не сильно изменилось, если, например, об Intel говорить.

Сергей: За какой это период не изменилось?

Олег: Например, последние 10 лет.

Сергей: Да, на железе десятилетней давности есть AVX-512?

Он, наверное, и на современном не везде есть? Олег: Нет.

У нас в лабе есть, но это всё оккупировано компиляторщиками. Сергей: У меня точно нет. Они пока прикручивают, поэтому я ещё не посмотрел.

Олег: Можно ли считать поддержку AVX-512 примером типичной фичи?

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

Олег: Они как-то аппаратно ускоряются?

Есть очень хорошо ускоренные алгоритмы. Сергей: Всё зависит от конкретных алгоритмов. Все это было реализовано с минимальным временным интервалом. Кстати, 10 лет назад это не заработало бы на железе Intel, но лет 5-6 как появились хорошие инструкции, вплоть до AES-блоков с ускорениями.

Олег: Что насчет GPU, они же тоже матрицы умеют перемножать?

У нас есть для этого есть проект Panama, в котором ведутся все эти работы, и когда-нибудь он дойдет и до мейнлайна Java со всеми плюшками. Сергей: Про GPU — отдельный разговор.

Начиная с какого-то момента они всегда переходят на С++ для вычислений и утверждают, что из managed-платформы очень неудобно все эти оптимизации и аппаратные штуки использовать. Олег: У меня есть пара знакомых, которые занимаются, условно, финансовой математикой. Можно ли это улучшить?

Например, сделать что-то, чтобы в области machine learning всё работало лучше. Сергей: У нас тоже есть большой запрос на это и есть ряд внутренних требований. Работы по этому ведутся, скажем так. Как правило, это банальное матричное перемножение, которое можно скидывать на GPU.

На стыке Valhalla и Panama сидит vector API, который работает с нашими инструкциями SIMD/SSE/AVX, напрямую из Java-кода, и сама Valhalla с inline-типами — это всё большие шаги в ту сторону. У нас есть два больших проекта-«зонтика»: Valhalla и Panama, которые должны собрать фичи вроде GPU.

Что можно сломать оптимизацией, как поучаствовать в разработке

Не бывает ли так, что один проект влияет на другой, в том числе, с точки зрения кода и профиля производительности? Олег: Упомянутые тобой зонтики похожи друг на друга. Например, ты у себя что-то отрефакторил, а несчастный Рон Пресслер, обливаясь слезами, в уголке вечером чинит свои тесты?

Конкретный пример — Vector API. Сергей: Такое бывает постоянно. Можно сделать обходной маневр в hotspot и как-то это реализовать, но хочется иметь и общее решение. Для того, чтобы Vector API хорошо работал, наши нативные вектора должны в конце концов стать value-типами, или как сейчас это называется в Java, inline-типами. С другой стороны, ключевая фишка inline-типов как раз в том, чтобы не запариваться с layout-ом этих данных, а layout этих данных для Vector API предельно важен.

Понятно, что нужно сделать некоторые приседания, некоторые оптимизации, которые, с одной стороны, сделают inline-тип обычным типом, но у которого будет аппаратно завязанный layout. Потому что он, на самом деле, напрямую соответствует AVX-512 и всему такому. Если посмотреть на группы людей, которые двигают Panama и двигают Valhalla, они больше, чем наполовину пересекаются. Естественно, возникают пересечения.

Что делать дальше? Олег: Чисто организационно, вот у тебя есть проект, какая-то проблема с перформансом, а она находится в стыке нескольких проектов. Получается, это уже trade-off между проектами и людьми, а не между какими-то абстрактными задачами. Как это решать?

Давайте сделаем по-другому». Сергей: Здесь всё очень просто: если это перформанс-проблема с фичей, которая только дизайнится, надо пойти к людям, которые дизайнят, и сказать — «так-то и так-то, что будем делать? Начинается обсуждение, и проблема решается.

В идеальном случае ты чинишь эту проблему, или, если не можешь починить полноценно, — ляпаешь прототип, потом опять приходишь к владельцу кода и говоришь: «Вот прототип, что будем делать?» Дальше мы этот вопрос решаем конкретно по каждому случаю. Если же код уже существует — он уже работает.

Олег: У нас тут есть заинтересованные лица, которые не могут в этом процессе поучаствовать, это конечные пользователи.

Если зарплата не нужна — приходите в OpenJDK и участвуйте. Сергей: Они не могут поучаствовать ровно настолько, что им за это не будут платить зарплату в Oracle.

В OpenJDK сидят какие-то чертовы гении типа тебя, и где обычные люди, и где вы. Олег: Насколько это вообще реально? Допустим, у меня что-то тормозит, что и как я должен сделать?

Даже если не знаешь проблему, имеет смысл, может быть, написать на OpenJDK и спросить. Сергей: Если ты не знаешь проблемы, это отдельный вопрос, будет ли кто-то заниматься за тебя поиском решения, это вопрос как области, примера и так далее. Если это никому не интересно, это будет висеть без ответа. Если это что-то такое, у кого-то сразу щёлкнет в голове, народ за это схватится.

Олег: Допустим, я знаю проблему и даже знаю, что надо поправить.

Сергей: Если ты знаешь проблему, ты приходишь в OpenJDK, подписываешь все нужные бумажки, предлагаешь патчик, его ревьят и заливают.

Олег: Вот так просто?

Вот вчера Тагир (lany) у меня подхватил один небольшой фикс, который я забросил. Сергей: Ну да, немножко бюрократии, немножко подождать. Он стал его самостоятельно доводить до ума. Ему вот хочется, чтобы его довели до конца. Ну да, никто не ревьюит. Говорит: «Блин, ну что такое, я вот всё сделал, выложил, никто не ревьюит». Вот выйдут из отпусков и проревьюят. Сейчас июль, половина джавовского офиса в отпусках.

Олег: В США отпуска примерно в те же даты, что обычно в России?

Во-первых, они существенно меньше. Сергей: Нет, в США система отпусков совершенно не такая, как в России. Когда у тебя дети на каникулах — тогда и отпуска. А еще, в США система отпусков завязана на школы. А поскольку занятия здесь заканчиваются в середине июня и начинаются в середине августа, то эта дельта для отпуска не такая уж большая — всего два месяца. Как только начинаются каникулы, вся Америка приходит в движение.

Компиляторные трюки, размещение регистров

Условно говоря, если операция выделения подстроки раньше брала диапазон, а теперь делает полную копию, то этот рефакторинг меняет способ написания кода. Олег: Бывало ли так, что вы что-то оптимизировали у себя, а пользователям после этого пришлось по-другому код писать?

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

Это происходит только если ты взял на себя такой вот технический долг — отслеживать изменения в компиляторе. Допустим, вдруг через 20 лет придёт Graal как основной компилятор для HotSpot — тогда этим бедным ребятам придётся переписать вообще всё. Гораздо проще писать правильный код без прямых завязок, с более-менее нормальными общими реализациями.

Есть закон Мура, который нифига не закон, а просто эмпирическое наблюдение о том, что количество транзисторов удваивается каждые полтора года. Кстати, про компиляторы — не только про компиляторы Java, а вообще.

Эти 4 процента — то, что конечные пользователи получают на халяву просто от эволюции компиляторов. А есть точно такой же закон (Proebsting's Law) о том, что производительность кода без его модификации увеличивается на 4 процента каждые полтора-два года. Не железа, а именно компиляторов.

Это какая-то изначальная неэффективность? Олег: Интересно, откуда эти проценты вообще берутся. Но тогда когда-нибудь этот запас неэффективностей закончится.

Я бросил заниматься компиляторами, когда стал работать над перформансом. Сергей: Нет, это просто вопрос развития технологии. Я узнал об этом вообще в 2008, потому что вовремя не прочитал статью. Но когда-то я занимался, и самое большое открытие для меня было сделано в 2005 или 2006 году.

Известно, что в общем виде эта задача — NP-полная. Очень важная задача любой кодогенерации — это размещение регистров. Решать ее очень сложно, и поэтому все компиляторы пытаются гонять какой-то приближенный алгоритм с той или иной степенью качества.

Ура, поехали! И вот выходит статья, где ребята доказывают, что в каких-то случаях, которые покрывают огромное количество компиляторов и огромное количество внутренних представлений с определенными ограничениями, для задачи размещения аллокации регистров существует точный полиномиальный алгоритм.

Это случилось в 2005 году, компиляторы, сделанные раньше, этого не знали.

Олег: Теперь можно сделать новый аллокатор для Java?

Не вдавался в детали, но знаю, что ребята из Excelsior реализовали у себя алгоритм. Сергей: Теперь, когда есть теоретическое решение, его можно переписать.

Не хотите написать ещё один? Олег: Мы недавно делали интервью с Клиффом Кликом, и он рассказывал, какой безумно сложный и безумной гениальный аллокатор он написал для Java.

Сергей: Нет.

Олег: Тот, что есть, в целом — нормальный?

Я со своей утилитарной точки зрения скажу, что смотрю в ассемблер и иногда вижу: «Ну да, вот здесь регистры легли плохо». Сергей: Нет, он не нормальный. Мы получим какой-то выигрыш, но вряд ли я его увижу кроме как на тех примерах, где я увидел неэффективное размещение регистров. Если я прибегу пинать наших компиляторщиков, и мы перепишем аллокатор, то что мы получим? Пока нет каких-то огромных провалов в этой области, всегда есть чем заняться и получить больше выигрыша.

Ты говоришь, что надо писать обычный нормальный код и всё будет хорошо, но это звучит подозрительно. Олег: Есть ли какие-то фронт работ в JDK, где вся подкапотная компиляторная или performance-магия вырывается на поверхность?

Если тебе нужно совсем быстро, будь готов, что будешь переписывать всегда. Сергей: Всё будет хорошо, пока тебе не нужно супер-пупер. На текущий момент, если взять абстрактное большое приложение, по большое счету, как оно написано — вообще не играет роли с точки зрения производительности.

Огромная проблема, которую я видел в куче приложений — они занимаются тем, что перекладывают данные. С одной стороны, как только срабатывает garbage collector, он отжирает свои 10-20%, с другой стороны начинает всплывать архитектура приложения. В целом, любая программа делает только это. Мы взяли данные отсюда, переложили туда, там сделали какие-то преобразования. Но если у тебя в программе слишком много перекладываний, то компилятор ничем не поможет. Она перекладывает данные из одного места в другое каким-то образом.

Олег: Ты можешь попробовать отследить какие-то простые вещи, вроде: вот этот кусок памяти меняется владельцами и перемещается между объектами вот в таком направлении.

Я же не просто перекладываю, а перекладываю с модификациями, что-то с ними делаю. Сергей: Нет, это вопрос дизайна. Вместо десяти сделать семь — это уже хорошо. Самую большую выгоду, в реальных, массовых приложениях можно получить, если подумать: а нужно ли столько перекладываний.

На самом деле все проще, Хабр закэшировал не ту картинку с YouTube) (Может показаться, что тут случайно задублировано одно и то же видео.

Собираем кошку из фарша

И очень многие люди очень сильно заморачивались такими вещами, как модель стоимости, определение стоимости каждой операции очень гранулярно, очень точно. Олег: У нас только что была конференция Hydra про распределенные вычисления. Интересно, насколько этот подход работает в современной действительности. Людям очень хочется выписать все инструкции, сложить стоимость каждой из них и посмотреть, сколько тактов займет твой код. И если не работает, то что делать?

Есть мысли, как это попытаться объяснить. Сергей: Ну, на полпроцента может быть и работает. Входит мясо, а на выходе выходит фарш. Я отослал бы к одной из своих старых презентаций, где показывал мясорубку. И как ты посчитаешь эти такты на секунду и всё прочее? Фарш выходит параллельно, а если кухня большая, то на ней работает несколько мясорубок, и все эти куски мяса там перекладываются распределенно.

Олег: Задача: «как собрать кошку из фарша».

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

Олег: А если пытаться её заставить работать линейно, то это приведет к потере производительности?

Она будет предсказуемой, но это скажется на скорости. Сергей: Если её пытаться зафорсить линейно, то что нам это даст? Сколько лет у нас нет прироста гигагерц в процессорах?

Олег: Ну, где-то лет пять?

А процессоры почему-то становятся быстрее. Сергей: Я бы сказал, что они и десять лет не так сильно растут — так, колебания маркетингового уровня. А за счет того, что вот в мясорубке есть дырки, откуда мясо лезет, и в следующем процессоре этих дырочек становится больше, мясо лезет быстрее. За счет чего? Ну, если ручку крутить достаточно быстро и мясо подавать в нужном количестве.

Олег: Количество голов тоже растет.

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

Пять дней на тесты и другие задачи performance-инженера

Насколько реально с помощью железа ускорить сборку проекта? Олег: Ты же наверняка компилируешь OpenJDK три раза за обед. Если купить самый топовый десктопный процессор — это поможет как-то? C++ наверняка не быстро собирается.

Никогда не заморачивался этим вопросом. Сергей: Я, честно сказать, не знаю. И у меня всегда есть 15 минут чем заняться параллельно. На моем ноутбуке сборка OpenJDK занимает 15 минут.

Ты не можешь два символа поменять и перезапустить все тесты. Олег: Но тогда получается, что нужно очень хорошо все продумывать, и только уже готовое отправлять на пересборку.

Я не могу отправить на пересборку потому, что изменения чуть больше, чем два символа. Сергей: Так это неважно! Такое возможно, но я лично с таким не сталкивался. У меня нет такой ситуации, что поменял два символа, собрал билд, запустил, посмотрел, через минуту снова поменял два символа и начал собирать. Иногда он успевает отработать за ночь, но есть вещи, которые приходится ждать по пять дней. У меня обычно происходит следующее: я делаю билд, потом сажусь, пишу скрипт (или не пишу, он уже у меня есть), и запускаю часа на три — в лучшем случае.

Олег: Ой, а что это может быть такое?

Сергей: Например, минимальный, очень ограниченный прогон всей базы микробенчмарков Java.

Олег: Когда это нужно?

Сергей: Это, например, нужно для проекта Valhalla.

Сколько тестов тебе надо собрать? Олег: Вот ты поменял что-то в проекте, не важно, что — как ты поймешь, насколько далеко распространилось влияние твоих изменений? Ты же не можешь собрать все тесты со всеми профилями на всем железе в мире.

Локальный пример — у меня были работы в криптографическом алгоритме. Сергей: А это надо знать, что поменялось. Предложил фикс, его подтвердили, всё. Я взял эти алгоритмы, посмотрел на них, написал бенчмарки и увидел, что это можно разогнать. Вот у нас 2-3 алгоритма, на которые повлиял тот кусок кода, вот различные длинные ключи входных данных, чтобы понять картинку немного в общих чертах, погоняли — замечательно, коротко и просто. Мы крутимся в районе этих бенчмарок.

Там совершенно другая ситуация. Или, например, наши замечательные inline-типы, которые рано или поздно дойдут до основной Java и о которых я буду рассказывать на Joker. И это уже большой red flag: runtime-проверки не могут стоит 0. Там известно, что некоторые базовые Java-операции требуют изменения семантики, где появляются дополнительные runtime-проверки. Маленькая проверка, параллельное исполнение операции на современных out of order-процессорах — чепуха. А будет ли это вообще видно в реальной жизни?

Например, нужно найти регрессии. Но ведь это уже гадание, это надо проверять. Вот у нас базовые два десятка больших бенчмарков и порядка двух тысяч маленьких. А на чем искать регрессии? Запустим baseline, запустим модифицированную версию, а потом это всё будет работать 5-6 дней, мы ещё неделю будем сидеть и тупо сравнивать результат — есть там регрессия или нету. Давайте мы все это запустим и посмотрим. Если же 3% выскочило на каком-то микробенчмарке, ты бьешься головой об стену. И хорошо, если ты увидел разницу, что где-то в 2 раза упала скорость — тогда срочно надо пинать кого-то и смотреть что произошло. Эти 3% взялись откуда?

Олег: Правильно ли я понял, что вы определяете нужное место интуитивно?

У нас есть регрессионное performance-тестирование, которое состоит из нескольких уровней. Сергей: У нас нет никакой интуиции, у нас есть регрессионное тестирование. Понятно, что для частых коммитов и промоушенов у нас есть небольшое специально выбранное подмножество, для редких — большое.

Рутинная работа performance-разработчика — когда ты приходишь с утра, на тебя сваливается какая-нибудь performance-регрессия в каком-то конкретном билде по сравнению с другим билдом, на определенных бенчмарках. У нас есть база данных со всеми трендами, куда заходишь и смотришь, что произошло. Надо разобраться, в чем дело, и ты сидишь и разбираешься.

Понятно, что поиск регрессий автоматизирован, перепроверка регрессий автоматизирована, даже автоматизировано выявление, где случилась performance-проблема — в class libraries или в самом hotspot, что тоже очень ускоряет работу.

Как «войти» в performance

Скажи, осмысленная ли формулировка задачи или нет, и как войти во всю эту тему? Олег: Допустим, какой-нибудь Вася Пупкин хочет стать performance-инженером, сейчас все хотят ими стать.

Что должен делать абстрактный Вася? Сергей: Это очень интересный вопрос. Здесь вопрос в том, зачем вообще нужны performance-инженеры и кто может себе позволить иметь роскошь иметь performance-инженера.

Потому что здесь ты выжал пару копеек из своего железа, а на всю твою систему это даст десятки или сотни тысяч денег выигрыша — это вполне нормальная ситуация. Как правило, это вопрос вхождения в предметную область: те компании, которые жестко завязаны на большую базу клиентов, будь то Oracle, Twitter, Netflix или те, которым нужно выжимать какие-то копейки из железа. Как правило, в таких компаниях эти performance-инженеры тренируются сами по себе, под нужды компании.

Нужно просто писать нормальный код, чтобы всё работало, и это гораздо важнее. Если это компания не какого-то конкретного проекта, а более обобщенная, то там держать performance-инженера просто расточительно, так ли часто он будет нужен?

Есть такой классический тест: если человеку дать два куска кода и попросить провести какое-то performance review, то больше половины разработчиков завернут его в бенчмарки, измерят, выявят, что быстрее, и остановятся. А с точки зрения того, как стать performance-инженером — нужно не стесняться копать. Если на этом остановились — с performance у них плохо.

То, что какой-то кусок кода работает быстрее — ну, кто его знает, может у тебя там серверный Брендан Грегг сидит и орёт на твои харддрайвы, вот оно и замедлилось. А если они говорят: «Это быстрее, потому что...», когда они прокопали дальше и нашли правильное объяснение, почему именно оно быстрее — это хорошо.

Подготовка к Joker

Что за доклад? Олег: Ты приезжаешь на Joker с докладом.

Сергей: Про inline-типы, которые за это время переименовались.

Олег: Это то, что раньше называлось value-типами?

Параллельно с текущими разработками в коде идут модификации и спецификации. Сергей: Да, на самом деле там очень простое объяснение, почему они были переименованы. Само слово value в текущей Java-спецификации встречается очень часто. И люди поняли, что они выглядят страшно. Получается очень много масляного масла, когда эти сущности сложно разделять и очень неудобно читать. У нас то value, сё value, передача параметров by value, что-то ещё by value, и вот мы вводим ещё один value type.

Было голосование, опрос независимых людей, вплоть до того, что Rémi Forax где-то у себя во Франции бегал и опрашивал студентов, чтобы выбрать название inline-типов. Поэтому было решено их просто переименовать. Правда, Роман Елизаров обиделся, потому что у них в Kotlin inline-типы были придуманы специально, чтобы не путать с value-типами Java, но так уж получилось.

У нас сейчас выходит третий мажорный релиз внутри value-типов, два года назад это был, что называется, mvt (minimum value types), год назад это был LW 1. Они дошли до вполне приличной стадии. Люди поигрались, посмотрели, как оно ведет себя в разных трудных ситуациях, и картинка начала вырисовываться. Через недельку будет выпущен LW 2 — следующий релиз, когда поведение и ключевые аспекты этих типов уже вырисовались. Поэтому я думаю, что полезно дать представление о том, что грядет, рассказать, какие performance-преимущества это даёт, как их достичь, что там может быть не очень хорошо, и показать людям, куда всё идет.

Олег: А я правильно понимаю, что эта штука влияет на весь дизайн кода внутри и её не забэкпортировать на семерку-восьмерку какую-нибудь?

С другой стороны, меньше, чем на семерку, точно не сделать, потому что invokedynamic надо портировать. Сергей: В принципе, какой-нибудь активный человек может и забэкпортировать.

Олег: То есть, это хороший стимул перейти, например, на новую версию, минимум восьмерку.

Теоретически — да, но я уверен, что никто не возьмется. Сергей: Это жестко фиксированный дизайн, там меняется дизайн байткода, поэтому я не думаю, что это можно просто так бэкпортировать на предыдущие версии без малой крови. Точно так же, кто портировал лямбды из восьмерки?

Олег: Для этого нужна, наверное, огромная экспертиза, и смысл этого непонятен.

С моей точки зрения, то, что грядут inline-типы и вслед за ними грядет реификация generic-ов со специализацией и прочими вкусностями, но для этого нужно иметь базовые inline-типы. Сергей: Вот да. Это будут очень крупные изменения на уровне языка, самые большие по сравнению с теми же лямбдами.

Олег: А текущее состояние про реификацию, оно где-то обновляется в публичном виде?

Необходимо сначала сделать value-типы, а потом уже заниматься generic, потому что это завязанные и последовательные вещи. Сергей: Текущее обновление примерно следующее: как раз выпуск релиза inline-типов LW2 позволит заняться этим.

Узкий взгляд инженера по производительности на проект Valhalla» на следующую конференцию Joker, которая пройдет в Санкт-Петербурге 25-26 октября 2019 года. Сергей Куксенко приедет с докладом «Нужны ли в Java инлайн-типы? Как всегда, билеты можно приобрести на официальном сайте.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть