Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
лимит инлайнинга в Hostpot JVM — 35 байткод инструкцийПосле этой ерунды можно дальше не читать. И что invokestatic якобы эффективнее invokevirtual, и что «лишние» push/pop якобы влияют на скорость — всё от начала и до конца — сплошная неправда. Уберите, пожалуйста, статью, чтоб не путать людей.
После этой ерунды можно дальше не читать.
всё от начала и до конца — сплошная неправда
и тогда заголовок статьи про «самый быстрый пул соединений» — тем более надувательство.
Benchmark (initCapacity) (listImpl) Mode Cnt Score Error Units
FastListBench.testList 14 new thrpt 6 6444,598 ± 195,891 ops/ms
FastListBench.testList 14 orig thrpt 6 18426,890 ± 790,905 ops/ms
FastListBench.testList 15 new thrpt 6 19122,083 ± 436,809 ops/ms
FastListBench.testList 15 orig thrpt 6 18567,706 ± 101,215 ops/ms
0x000000010f02e688: sub $0x30,%rsp ;*synchronization entry
; - com.zaxxer.microbench.FastList2::add@-1 (line 73)
0x000000010f02e68c: mov 0x20(%rsi),%ebx ;*getfield elementData
; - com.zaxxer.microbench.FastList2::add@5 (line 73)
0x000000010f02e68f: mov 0xc(%r12,%rbx,8),%r11d ;*arraylength
; - com.zaxxer.microbench.FastList2::add@8 (line 73)
; implicit exception: dispatches to 0x000000010f02e7a5
0x000000010f02e694: mov 0x18(%rsi),%ebp ;*getfield size
; - com.zaxxer.microbench.FastList2::add@1 (line 73)
0x000000010f02e697: cmp %r11d,%ebp
0x000000010f02e69a: jge 0x000000010f02e785 ;*if_icmpge
; - com.zaxxer.microbench.FastList2::add@9 (line 73)
0x000000010f02e6a0: mov %ebp,%r8d
0x000000010f02e6a3: inc %r8d
0x000000010f02e6a6: mov %r8d,0x18(%rsi) ;*putfield size
; - com.zaxxer.microbench.FastList2::add@24 (line 74)
0x000000010f02e6aa: cmp %r11d,%ebp ; Лишняя проверка
0x000000010f02e6ad: jae 0x000000010f02e76d
0x000000010f02e6b3: mov 0x8(%rdx),%r10d ; implicit exception: dispatches to 0x000000010f02e7b5
java 8
Benchmark (initCapacity) (listImpl) Mode Cnt Score Error Units
FastListBench.testList 32 new thrpt 18 24669,079 ± 245,068 ops/ms
FastListBench.testList 32 orig thrpt 18 24275,624 ± 225,616 ops/ms
java 9
Benchmark (initCapacity) (listImpl) Mode Cnt Score Error Units
FastListBench.testList 32 new thrpt 18 12797,725 ± 373,708 ops/ms
FastListBench.testList 32 orig thrpt 18 11771,681 ± 286,235 ops/ms
-XX:+UseParallelGC.И тут же, кстати, у меня возникает ощущение, что всё это абсолютно зря.
Spliterator<Integer> spliterator = Stream.of(1)
.flatMap(x -> IntStream.range(0, Integer.MAX_VALUE).boxed())
.spliterator();static class MyException extends RuntimeException {}
try {
spliterator.forEachRemaining(x -> {
System.out.println(x);
throw new MyException();
});
} catch(MyException ex) { /* ignore */ }spliterator.tryAdvance(System.out::println);Вы не знаете, о чём говорите.
И тут же, кстати, у меня возникает ощущение, что всё это абсолютно зря.
Benchmark Mode Cnt Score Error Units
Inlining.inlineStaticSmall thrpt 5 298,373 ± 5,752 ops/us
Inlining.inlineVirtualLarge thrpt 5 298,515 ± 9,902 ops/us
@ 16 bench.Inlining::inlineStaticSmall (4 bytes)
@ 0 bench.Inlining::smallMethod (25 bytes) inline (hot)
@ 16 bench.Inlining::inlineVirtualLarge (5 bytes)
@ 1 bench.Inlining::largeMethod (109 bytes) inline (hot)
лимит задаётся совсем другими параметрами JVM
Заодно и развеем миф invokestatic vs. invokevirtual:
длина метода в байткодах для инлайнинга, дефолтная она 35 байткодовЭто называется «слышал звон, да не знает, где он». Есть параметр JVM
MaxInlineSize=35, но он означает совсем не то, что думает автор. Это лишь некая эвристика для инлайнинга, и она не мешает заинлайниться и более длинному методу, если JIT сочтёт нужным. Попытки «помочь» JIT-компилятору могут привести ровно к обратному эффекту. Метод checkException не листовой. Принудительно заинлайнив его, автор, например, рискует лишиться инлайнинга вложенных методов, тем самым получив вместо одного вызова два или три. Там говорится, что у JIT больше возможностей по оптимизации в случае invokestatic.А это тоже неправда. Вот, навскидку, ровно противоположный пример.
MaxInlineSize не играет никакой роли для горячего кода. Утверждение «Наверное ни для кого уже не секрет, что лимит инлайнинга в Hostpot JVM — 35 байткод инструкций» — абсолютная ложь, а не просто «упрощение». И попытки вогнать метод в 34 байта байткода бессмысленны. В контексте статьи автор как раз усложнил себе жизнь, делая бессмысленные операции. Если оптимизировать инлайнинг, надо не гадать, а хотя бы посмотреть, что реально инлайнится, а что — нет. Для этого есть опция +PrintInlining. Про неё же ни слова в статье.Про неё же ни слова в статье.
Почти добрая половина статьи
Окей, я тогда скажу, что подходы неверные.
Вот тут вы мух с котлетами путаете.
Конкретные примеры вам Андрей Паньгин разъяснил, тут вроде бы нечего добавить.
Вы же утверждаете, что этот труд не помог есть стать миллардером, а причина в молитве макаронному монстру
Пока из их раговора я не понял, кто же прав.
Мы изучали скомпилированный байткод для каждого метода и даже изменяли методы так, чтобы они попадали под лимит инлайнинга
Иногда, видя что метод превышает лимит инлайнинга, мы думали о том как изменить его таким образом, чтобы избавится от нескольких байт-инструкций. Например:
Наверное ни для кого уже не секрет, что лимит инлайнинга в Hostpot JVM — 35 байткод инструкций. Поэтому мы уделили некоторое внимание этому методу, чтобы сократить его и изменили его следующим образом:
Получилось довольно близко к лимиту, но все еще 36 инструкций. Поэтому мы сделали так:
Выглядит проще. Неправда ли? На самом деле, этот код хуже предыдущего — 45 инструкций.
Как раз ниже лимита в 35 байткод инструкций. Это маленький метод и на самом деле даже не высоконагруженный, но идею Вы поняли.
try {
elementData[size++] = element;
}
catch (ArrayIndexOutOfBoundsException e) {
// overflow-conscious code
final int oldCapacity = elementData.length;
final int newCapacity = oldCapacity << 1;
@SuppressWarnings("unchecked")
final T[] newElementData = (T[]) Array.newInstance(clazz, newCapacity);
System.arraycopy(elementData, 0, newElementData, 0, oldCapacity);
newElementData[size - 1] = element;
elementData = newElementData;
}
String s = «aaa...»; //100500 chars
new StringBuilder().append(«1»).append(s).toString();
I benchmarked both ways when the code was written. This is faster 95% of the time. It only incurs overhead when the list is expanded — but that is a slow path anyway because of the memory copy.
ArrayList-то расширять? Мало граблей на этом собрали? Если в девятке вдруг во все листы добавят новый метод (скажем, parallelSort), и у ArrayList будет оптимизированная реализация, в данном классе он будет молча ничего не делать. Можно будет хвастаться, что FastList нереально быстро сортирует в параллель :-) Неужели мало граблей на этом в восьмёрке собрали? Что плохого в том, чтобы AbstractList наследовать?Error(null, null, false, false), который в несколько раз ускоряет создание исключения. Наблюдаю константную потерю на выкидывании где-то 200-300 наносекунд (против примерно 1500±длина стектрейса при обычном исключении). В моём случае эта константная потеря окупается, потому что альтернативный вариант без исключения затормаживает даже на не очень больших объёмах данных (только на совсем маленьких входных данных наблюдается проигрыш при использовании исключения).потому что альтернативный вариант без исключения затормаживает
if (condition) return error_core;
как динамическое создание класса, с помощью javassist ускоряет работу 34 инструкций перед 35 инструкциями.
HikariCP — самый быстрый пул соединений на java