Pull to refresh

Comments 14

Завтра пойду попрошусь в Питер :-)
В командировку, как минимум!

А так — дождитесь апрельской конференции JPoint, а на после уже окончательно переезжайте!
Не, переезжать не вариант. В Питере столько не платят :(
А вот заехать на денек на доклад — да, самое то.
Зря вы так. Питер — это Питер. Мало кого оттуда выманишь «московской» зарплатой.
Я люблю Питер, но именно как «турист».
Интересует насколько этот доклад будет пересекаться с докладом «Invokedynamic: роскошь или необходимость?».
«Invokedynamic: роскошь или необходимость?» — короткий вариант, без погружения в кишки. Тут будет больше времени, Владимир успеет осветить гораздо больше моментов, чем на Джокере полтора года назад. Ну и времени много прошло, Java 8 вышла, Nashorn, все дела.
Есть вопрос про 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 — должно точно хватить)?
Коряво отредактировал, извините. Посмотрите код по ссылке. В одном случае метод, который обходил коллекцию, принимает в качестве параметра конкретный тип коллекции (например, IntCollection). Во втором случае метод принимает Iterable<Integer>, то есть снаружи его могут вызвать с любой коллекцией и решение об инлайнинге JIT-компилятору принять сложнее.

Отписался Владимиру, он говорит, что это похоже на баг и обещал разобраться.
А чем последний случай отличается от предпоследнего?

Ps идея очень красивая.
Если вы имеете в виду, чем отличается IteratorBench.testIterator2 и IteratorBench.testIterator2Abstract, то ответил выше.

Владимир подсказал, кстати, что с опциями -XX:+UnlockExperimentalVMOptions -XX:+AggressiveUnboxing производительность варианта с анбоксингом в несколько раз выше, хотя всё же не достигает производительности testIterator2. Возможно, со временем AggressiveUnboxing будет включено по умолчанию.
Sign up to leave a comment.