Comments 14
Завтра пойду попрошусь в Питер :-)
Интересует насколько этот доклад будет пересекаться с докладом «Invokedynamic: роскошь или необходимость?».
Есть вопрос про JIT-компиляцию в HotSpot (1.8.0.31 у меня стоит), но не связанный с invokedynamic. Вчера экспериментировал с кодом, эмулирующим коллекцию на примитивном типе int. При этом хотелось, чтобы при обходе вида
for(int val : collection)
не происходило боксинга. Ну то есть я в итераторе коллекции делаю боксинг, а в конструкции for сразу происходит анбоксинг. Комбинацию боксинг-анбоксинг JIT-компилятор на раз выкашивает (например, new Integer(i).toString()
и Integer.toString(i)
JIT-компилируются в одинаковый код и по быстродействию эквивалентны). Инлайнить JIT-компилятор тоже неплохо умеет. Я даже создал специальный тип IntegerIterator implements Iterator<Integer>
и метод iterator() коллекции объявил с ковариантным возвращаемым типом. И коллекция используется конкретного типа, а не какое-нибудь Iterable. А всё равно не инлайнит и как следствие итерация получается раз в 10 медленнее :( Что я не так делаю? Это из-за того, что в байткоде invokeinterface Iterator.next() и раз интерфейс, то JIT-компилятор умывает руки?Ещё немного поковырял код. Оказалось, что если возвращать из next() не
Код моего бенчмарка здесь. Результат примерно такой:
Integer.valueOf(primitive)
, а new Integer(primitive)
, то вся цепочка легко заводится даже без дополнительных приседаний в виде ковариантных возвращаемых значений. Соотвественно вопрос снимается, но возникает другой: нельзя ли специально обрабатывать Integer.valueOf (и аналоги для других типов), чтобы при JIT-компиляции он работал не хуже, чем new Integer?Код моего бенчмарка здесь. Результат примерно такой:
Benchmark Mode Cnt Score Error Units
IteratorBench.testArray avgt 30 3,555 ± 0,015 us/op // итерация по массиву — контроль
IteratorBench.testIteratorList avgt 30 8,784 ± 0,062 us/op // итерация по ArrayList<Integer> — контроль
IteratorBench.testIntIterator avgt 30 3,556 ± 0,022 us/op // свой класс итератора, явно возвращает примитив
IteratorBench.testIterator avgt 30 49,804 ± 0,615 us/op // итерация по коллекции Iterable<Integer> с автобоксингом в next()
IteratorBench.testIteratorAbstract avgt 30 52,482 ± 1,946 us/op // то же, но метод принимает а Iterable<Integer>
IteratorBench.testIterator2 avgt 30 3,585 ± 0,039 us/op // итерация по коллекции Iterable<Integer> с new Integer() в next()
IteratorBench.testIterator2Abstract avgt 30 3,587 ± 0,036 us/op // то же, но метод принимает а Iterable<Integer>
скинул Вовину почту в личку — спрашивай там :)
Что означает «то же, но метод принимает а Iterable»?
А по-существу — возможно переполняется максимальный размер инлайна на вызове Integer.valueOf(primitive) — вот, такое наивное предположение.
Не пробовали поиграться с -XX:MaxInlineSize= (например, 70 там выставить) и -XX:InlineSmallCode= (тут подбирать нужно, но можно попробовать поставить 255 — должно точно хватить)?
А по-существу — возможно переполняется максимальный размер инлайна на вызове Integer.valueOf(primitive) — вот, такое наивное предположение.
Не пробовали поиграться с -XX:MaxInlineSize= (например, 70 там выставить) и -XX:InlineSmallCode= (тут подбирать нужно, но можно попробовать поставить 255 — должно точно хватить)?
Коряво отредактировал, извините. Посмотрите код по ссылке. В одном случае метод, который обходил коллекцию, принимает в качестве параметра конкретный тип коллекции (например, IntCollection). Во втором случае метод принимает Iterable<Integer>, то есть снаружи его могут вызвать с любой коллекцией и решение об инлайнинге JIT-компилятору принять сложнее.
Отписался Владимиру, он говорит, что это похоже на баг и обещал разобраться.
Отписался Владимиру, он говорит, что это похоже на баг и обещал разобраться.
А чем последний случай отличается от предпоследнего?
Ps идея очень красивая.
Ps идея очень красивая.
Если вы имеете в виду, чем отличается IteratorBench.testIterator2 и IteratorBench.testIterator2Abstract, то ответил выше.
Владимир подсказал, кстати, что с опциями -XX:+UnlockExperimentalVMOptions -XX:+AggressiveUnboxing производительность варианта с анбоксингом в несколько раз выше, хотя всё же не достигает производительности testIterator2. Возможно, со временем AggressiveUnboxing будет включено по умолчанию.
Владимир подсказал, кстати, что с опциями -XX:+UnlockExperimentalVMOptions -XX:+AggressiveUnboxing производительность варианта с анбоксингом в несколько раз выше, хотя всё же не достигает производительности testIterator2. Возможно, со временем AggressiveUnboxing будет включено по умолчанию.
Sign up to leave a comment.
Владимир Иванов, Oracle — Глубокое погружение в invokedynamic