-
-
Save navyxliu/1bbb22f3894ca48fe278d76c30aa1244 to your computer and use it in GitHub Desktop.
package com.amazon.jdkteam; | |
import org.openjdk.jmh.annotations.*; | |
import org.openjdk.jmh.infra.Blackhole; | |
import org.openjdk.jmh.profile.GCProfiler; | |
import org.openjdk.jmh.runner.Runner; | |
import org.openjdk.jmh.runner.RunnerException; | |
import org.openjdk.jmh.runner.options.Options; | |
import org.openjdk.jmh.runner.options.OptionsBuilder; | |
import java.util.concurrent.TimeUnit; | |
// derived from Vladimir Dolzhenko's | |
// https://gist.github.com/vladimirdolzhenko/d85789232d289f72607bebac88d43ab2 | |
@BenchmarkMode(Mode.AverageTime) | |
@OutputTimeUnit(TimeUnit.NANOSECONDS) | |
@Fork(1) | |
@Warmup(iterations = 10, time = 5000, timeUnit = TimeUnit.MILLISECONDS) | |
@Measurement(iterations = 5, time = 5000, timeUnit = TimeUnit.MILLISECONDS) | |
@State(Scope.Benchmark) | |
public class PartialEATest { | |
@Param(value = {"-1", "1"}) | |
private int value; | |
@Param(value = {"10"}) | |
private int param; | |
@Benchmark | |
public void allocate(Blackhole bh) { | |
checkArg(bh, value > 0, "expected non-negative value: %s, %s", value, 1000, "A", 700); | |
} | |
private static void checkArg(Blackhole bh, boolean cond, String msg, Object ... args){ | |
if (!cond){ | |
bh.consume(String.format(msg, args)); | |
} | |
} | |
// 1/param odds to have escaped object -- Object[] args | |
// partial escape analysis requires to inline 'checkArg' | |
// when param == 10, | |
// gc.alloc.rate.norm of cond_allocate() expects to be 2x than allocate() with value == -1. | |
// because cond == false twice. | |
// | |
// we see that c2 reports 4x allocation | |
// PartialEATest.allocate:·gc.alloc.rate.norm 10 -1 avgt 5 608.049 ± 0.002 B/op^ | |
// PartialEATest.cond_allocate:·gc.alloc.rate.norm 10 -1 avgt 5 2320.179 ± 0.005 B/op | |
@Benchmark | |
public void cond_allocate(Blackhole bh) { | |
for (int i = 0; i < 20; ++i) { | |
checkArg(bh, (i % param) != 0, "expected non-negative value: %s, %s", param, 1000, "A", 700); | |
} | |
} | |
public static void main(String[] args) throws RunnerException { | |
Options opt = new OptionsBuilder() | |
.include(PartialEATest.class.getSimpleName()) | |
.addProfiler(GCProfiler.class) | |
.build(); | |
new Runner(opt).run(); | |
} | |
} |
navyxliu
commented
Sep 26, 2022
cond_alloc | jdk19_ga | graal22_jdk17 | graal22_wo_PEA |
---|---|---|---|
runtime(ns/op) | 945.800615 | 552.64111 | 858.128181 |
allocate_norm(B/op) | 2320.04308 | 1344.02671 | 2544.05462 |
Here is Graal IR without PEA. there are 20 iterations in cond_allocate
, but graal peels one iteration.
For simplicity, just focus on the loop body from 7 LoopBegin
to 79 LoopEnd
. It corresponds the shortcut of loop body which cond is true at line 35
Eyes on 25 NewArray
. It allocates Object[4] for VLA(ie. args of chkArgs). Either true or false of 19 ==
, 25 NewArray
is on the control path. It will be materialized! Besides that, there are some collateral boxing objects 27, 31, 40 for args.
The following graph is from 'After Partial Escape Analysis'.
The VLA args
is materialized by 271 Alloc
, which is a CommitAllocationNode
It's worth noting that 271 Alloc
is dominated by the IFTrue branch of 46 If
. It means that allocation only takes place when 19 ==
is true. The shortcut path(IFFalse) gets away without allocation! The code motion is attributed to Graal's PEA.