Я сравниваю производительность MethodHandle::invoke
и прямого вызова статического метода. Вот статический метод:
public class IntSum {
public static int sum(int a, int b){
return a + b;
}
}
И вот мой ориентир:
@State(Scope.Benchmark)
public class MyBenchmark {
public int first;
public int second;
public final MethodHandle mhh;
@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public int directMethodCall() {
return IntSum.sum(first, second);
}
@Benchmark
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public int finalMethodHandle() throws Throwable {
return (int) mhh.invoke(first, second);
}
public MyBenchmark() {
MethodHandle mhhh = null;
try {
mhhh = MethodHandles.lookup().findStatic(IntSum.class, "sum", MethodType.methodType(int.class, int.class, int.class));
} catch (NoSuchMethodException | IllegalAccessException e) {
e.printStackTrace();
}
mhh = mhhh;
}
@Setup
public void setup() throws Exception {
first = 9857893;
second = 893274;
}
}
Я получил следующий результат:
Benchmark Mode Cnt Score Error Units
MyBenchmark.directMethodCall avgt 5 3.069 ± 0.077 ns/op
MyBenchmark.finalMethodHandle avgt 5 6.234 ± 0.150 ns/op
MethodHandle
имеет некоторое снижение производительности.
Запуск с -prof perfasm
показывает следующее:
....[Hottest Regions]...............................................................................
31.21% 31.98% C2, level 4 java.lang.invoke.LambdaForm$DMH::invokeStatic_II_I, version 490 (27 bytes)
26.57% 28.02% C2, level 4 org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub, version 514 (84 bytes)
20.98% 28.15% C2, level 4 org.openjdk.jmh.infra.Blackhole::consume, version 497 (44 bytes)
Насколько я мог понять, причина результатов теста заключается в том, что Самый горячий регион 2 org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub
содержит все проверки типов, выполненные MethodHandle::invoke
внутри цикла JHM. Фрагмент вывода сборки (часть кода опущена):
....[Hottest Region 2]..............................................................................
C2, level 4, org.sample.generated.MyBenchmark_finalMethodHandle_jmhTest::finalMethodHandle_avgt_jmhStub, version 519 (84 bytes)
;...
0x00007fa2112119b0: mov 0x60(%rsp),%r10
;...
0x00007fa2112119d4: mov 0x14(%r12,%r11,8),%r8d ;*getfield form
0x00007fa2112119d9: mov 0x1c(%r12,%r8,8),%r10d ;*getfield customized
0x00007fa2112119de: test %r10d,%r10d
0x00007fa2112119e1: je 0x7fa211211a65 ;*ifnonnull
0x00007fa2112119e7: lea (%r12,%r11,8),%rsi
0x00007fa2112119eb: callq 0x7fa211046020 ;*invokevirtual invokeBasic
;...
0x00007fa211211a01: movzbl 0x94(%r10),%r10d ;*getfield isDone
;...
0x00007fa211211a13: test %r10d,%r10d
;jumping at the begging of jmh loop if not done
0x00007fa211211a16: je 0x7fa2112119b0 ;*aload_1
;...
Перед вызовом invokeBasic
мы выполняем проверку типов (внутри цикла jmh), которая влияет на вывод avgt.
ВОПРОС. Почему не вся проверка типов вынесена за пределы цикла? Я объявил public final MethodHandle mhh;
внутри теста. Поэтому я ожидал, что компилятор сможет это понять и устранить те же проверки типов. Как устранить однотипные проверки типов? Является ли это возможным?
ConstantCallSite
? Если да, то, поскольку это постояннаяCallSite
, требуется ли, чтобы она также была статической? 15.03.2018ConstantCallSite
требует указать целевой метод в конструкторе. В этом смыслеConstantCallSite
бесполезен - это будет то же самое, что создавать статическийMethodHandle
напрямую.MutableCallSite
, с другой стороны, позволяет отложить решение о цели до более позднего времени выполнения. 16.03.2018static final
. Я почему-то подумал, что если мы объявим неизменяемое поле какfinal
, компилятор сможет узнать, что оно неизменяемое и окончательное, и поднимет некоторую связанную проверку вне цикла (в моем случае). Может быть, вы знаете, где можно найти информацию о подъеме/складывании констант JIT? Я просмотрел opto пакет, но он кажется размытым... 16.03.2018-XX:+TrustFinalNonStaticFields
. См.ciField::initialize_from
а>. 16.03.2018SignaturePolymorphic
имеют строгое определение в JVMS. docs.oracle.com/javase/ specs/jvms/se8/html/jvms-2.html#jvms-2.9 Таким образом, никаких других методов, кроме тех, что вjava.lang.invoke
, быть не может. 17.03.2018mh = ...
конкретным утверждением? Это помогло бы сделать пример более понятным. 28.12.2018mh
указывает на вызываемый целевой метод. В исходном вопросе есть пример. 28.12.2018mhh
иmhhh
, оба из которых являютсяMethodHandle
. Надеюсь, вы понимаете, как это может запутать. 28.12.2018