Skip to content

Instantly share code, notes, and snippets.

@retronym
Created October 14, 2025 03:45
Show Gist options
  • Save retronym/170214abc4da8039075c563ff3e25773 to your computer and use it in GitHub Desktop.
Save retronym/170214abc4da8039075c563ff3e25773 to your computer and use it in GitHub Desktop.
CakePattern +-UseSecondarySupersTable JVM performance
package scala.tools.nsc;
import org.openjdk.jmh.annotations.*;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
@Warmup(iterations = 4, time = 2)
@Measurement(iterations = 4, time = 2)
@Fork(value = 3)
public class CakePattern {
// Approximation of the "Cake Pattern"
static class API {
interface Names {
class Name {
final Names outer;
Name(Names outer) {
this.outer = outer;
}
}
}
}
static class Impl {
interface Names extends API.Names {
class Name extends API.Names.Name {
// Scala compiler synthetically adds this outer parameter to this constructor and super call.
// As such, it knows that the checkcast below is always successful (modulo null).
Name(Names outer) {
super(outer);
}
Names outer() {
return (Names) this.outer;
}
}
}
}
// approximation of scala.tools.nsc.Global (core class in the Scala 2 compiler)
static Impl.Names global(int numInterfaces) {
Objects.checkIndex(numInterfaces - 1, INTERFACES.length);
// randomly select interfaces to cache-bust speculative compilation schemes of HotSpot.
List<Class<?>> shuffled = new ArrayList<>(Arrays.asList(INTERFACES));
Collections.shuffle(shuffled, new Random());
List<Class<?>> l1 = new ArrayList<>(shuffled.subList(0, numInterfaces));
// last in the list for the worst case linear search
l1.add(Impl.Names.class);
Class<?>[] interfaces = l1.toArray(Class[]::new);
ClassLoader loader = CakePattern.class.getClassLoader();
return (Impl.Names) Proxy.newProxyInstance(loader, interfaces, (proxy, _, args) -> null);
}
private Impl.Names names;
@Param("80")
public int numInterfaces;
@Setup(Level.Iteration)
public void setup() {
names = global(numInterfaces);
}
@Benchmark
public Object measure() {
return new Impl.Names.Name(names).outer();
}
// @formatter:off
static final Class<?>[] INTERFACES = {
I1.class, I2.class, I3.class, I4.class, I5.class, I6.class, I7.class, I8.class, I9.class, I10.class, I11.class, I12.class, I13.class, I14.class, I15.class, I16.class, I17.class, I18.class, I19.class, I20.class, I21.class, I22.class, I23.class, I24.class, I25.class, I26.class, I27.class, I28.class, I29.class, I30.class, I31.class, I32.class, I33.class, I34.class, I35.class, I36.class, I37.class, I38.class, I39.class, I40.class, I41.class, I42.class, I43.class, I44.class, I45.class, I46.class, I47.class, I48.class, I49.class, I50.class, I51.class, I52.class, I53.class, I54.class, I55.class, I56.class, I57.class, I58.class, I59.class, I60.class, I61.class, I62.class, I63.class, I64.class, I65.class, I66.class, I67.class, I68.class, I69.class, I70.class, I71.class, I72.class, I73.class, I74.class, I75.class, I76.class, I77.class, I78.class, I79.class, I80.class, I81.class, I82.class, I83.class, I84.class, I85.class, I86.class, I87.class, I88.class, I89.class, I90.class, I91.class, I92.class, I93.class, I94.class, I95.class, I96.class, I97.class, I98.class, I99.class, I100.class, I101.class, I102.class, I103.class, I104.class, I105.class, I106.class, I107.class, I108.class, I109.class, I110.class, I111.class, I112.class, I113.class, I114.class, I115.class, I116.class, I117.class, I118.class, I119.class, I120.class, I121.class, I122.class, I123.class, I124.class, I125.class, I126.class, I127.class, I128.class, I129.class, I130.class, I131.class, I132.class, I133.class, I134.class, I135.class, I136.class, I137.class, I138.class, I139.class, I140.class, I141.class, I142.class, I143.class, I144.class, I145.class, I146.class, I147.class, I148.class, I149.class, I150.class, I151.class, I152.class, I153.class, I154.class, I155.class, I156.class, I157.class, I158.class, I159.class, I160.class, I161.class, I162.class, I163.class, I164.class, I165.class, I166.class, I167.class, I168.class, I169.class, I170.class, I171.class, I172.class, I173.class, I174.class, I175.class, I176.class, I177.class, I178.class, I179.class, I180.class, I181.class, I182.class, I183.class, I184.class, I185.class, I186.class, I187.class, I188.class, I189.class, I190.class, I191.class, I192.class, I193.class, I194.class, I195.class, I196.class, I197.class, I198.class, I199.class, I200.class, I201.class, I202.class, I203.class, I204.class, I205.class, I206.class, I207.class, I208.class, I209.class, I210.class, I211.class, I212.class, I213.class, I214.class, I215.class, I216.class, I217.class, I218.class, I219.class, I220.class, I221.class, I222.class, I223.class, I224.class, I225.class, I226.class, I227.class, I228.class, I229.class, I230.class, I231.class, I232.class, I233.class, I234.class, I235.class, I236.class, I237.class, I238.class, I239.class, I240.class, I241.class, I242.class, I243.class, I244.class, I245.class, I246.class, I247.class, I248.class, I249.class, I250.class, I251.class, I252.class, I253.class, I254.class, I255.class, I256.class, I257.class, I258.class, I259.class, I260.class, I261.class, I262.class, I263.class, I264.class, I265.class, I266.class, I267.class, I268.class, I269.class, I270.class, I271.class, I272.class, I273.class, I274.class, I275.class, I276.class, I277.class, I278.class, I279.class, I280.class, I281.class, I282.class, I283.class, I284.class, I285.class, I286.class, I287.class, I288.class, I289.class, I290.class, I291.class, I292.class, I293.class, I294.class, I295.class, I296.class, I297.class, I298.class, I299.class, I300.class
};
interface I1 {}; interface I2 {}; interface I3 { }; interface I4 { }; interface I5 { }; interface I6 { }; interface I7 { }; interface I8 { }; interface I9 { }; interface I10 { }; interface I11 { }; interface I12 { }; interface I13 { }; interface I14 { }; interface I15 { }; interface I16 { }; interface I17 { }; interface I18 { }; interface I19 { }; interface I20 { }; interface I21 { }; interface I22 { }; interface I23 { }; interface I24 { }; interface I25 { }; interface I26 { }; interface I27 { }; interface I28 { }; interface I29 { }; interface I30 { }; interface I31 { }; interface I32 { }; interface I33 { }; interface I34 { }; interface I35 { }; interface I36 { }; interface I37 { }; interface I38 { }; interface I39 { }; interface I40 { }; interface I41 { }; interface I42 { }; interface I43 { }; interface I44 { }; interface I45 { }; interface I46 { }; interface I47 { }; interface I48 { }; interface I49 { }; interface I50 { }; interface I51 { }; interface I52 { }; interface I53 { }; interface I54 { }; interface I55 { }; interface I56 { }; interface I57 { }; interface I58 { }; interface I59 { }; interface I60 { }; interface I61 { }; interface I62 { }; interface I63 { }; interface I64 { }; interface I65 { }; interface I66 { }; interface I67 { }; interface I68 { }; interface I69 { }; interface I70 { }; interface I71 { }; interface I72 { }; interface I73 { }; interface I74 { }; interface I75 { }; interface I76 { }; interface I77 { }; interface I78 { }; interface I79 { }; interface I80 { }; interface I81 { }; interface I82 { }; interface I83 { }; interface I84 { }; interface I85 { }; interface I86 { }; interface I87 { }; interface I88 { }; interface I89 { }; interface I90 { }; interface I91 { }; interface I92 { }; interface I93 { }; interface I94 { }; interface I95 { }; interface I96 { }; interface I97 { }; interface I98 { }; interface I99 { }; interface I100 { }; interface I101 { }; interface I102 { }; interface I103 { }; interface I104 { }; interface I105 { }; interface I106 { }; interface I107 { }; interface I108 { }; interface I109 { }; interface I110 { }; interface I111 { }; interface I112 { }; interface I113 { }; interface I114 { }; interface I115 { }; interface I116 { }; interface I117 { }; interface I118 { }; interface I119 { }; interface I120 { }; interface I121 { }; interface I122 { }; interface I123 { }; interface I124 { }; interface I125 { }; interface I126 { }; interface I127 { }; interface I128 { }; interface I129 { }; interface I130 { }; interface I131 { }; interface I132 { }; interface I133 { }; interface I134 { }; interface I135 { }; interface I136 { }; interface I137 { }; interface I138 { }; interface I139 { }; interface I140 { }; interface I141 { }; interface I142 { }; interface I143 { }; interface I144 { }; interface I145 { }; interface I146 { }; interface I147 { }; interface I148 { }; interface I149 { }; interface I150 { }; interface I151 { }; interface I152 { }; interface I153 { }; interface I154 { }; interface I155 { }; interface I156 { }; interface I157 { }; interface I158 { }; interface I159 { }; interface I160 { }; interface I161 { }; interface I162 { }; interface I163 { }; interface I164 { }; interface I165 { }; interface I166 { }; interface I167 { }; interface I168 { }; interface I169 { }; interface I170 { }; interface I171 { }; interface I172 { }; interface I173 { }; interface I174 { }; interface I175 { }; interface I176 { }; interface I177 { }; interface I178 { }; interface I179 { }; interface I180 { }; interface I181 { }; interface I182 { }; interface I183 { }; interface I184 { }; interface I185 { }; interface I186 { }; interface I187 { }; interface I188 { }; interface I189 { }; interface I190 { }; interface I191 { }; interface I192 { }; interface I193 { }; interface I194 { }; interface I195 { }; interface I196 { }; interface I197 { }; interface I198 { }; interface I199 { }; interface I200 { }; interface I201 { }; interface I202 { }; interface I203 { }; interface I204 { }; interface I205 { }; interface I206 { }; interface I207 { }; interface I208 { }; interface I209 { }; interface I210 { }; interface I211 { }; interface I212 { }; interface I213 { }; interface I214 { }; interface I215 { }; interface I216 { }; interface I217 { }; interface I218 { }; interface I219 { }; interface I220 { }; interface I221 { }; interface I222 { }; interface I223 { }; interface I224 { }; interface I225 { }; interface I226 { }; interface I227 { }; interface I228 { }; interface I229 { }; interface I230 { }; interface I231 { }; interface I232 { }; interface I233 { }; interface I234 { }; interface I235 { }; interface I236 { }; interface I237 { }; interface I238 { }; interface I239 { }; interface I240 { }; interface I241 { }; interface I242 { }; interface I243 { }; interface I244 { }; interface I245 { }; interface I246 { }; interface I247 { }; interface I248 { }; interface I249 { }; interface I250 { }; interface I251 { }; interface I252 { }; interface I253 { }; interface I254 { }; interface I255 { }; interface I256 { }; interface I257 { }; interface I258 { }; interface I259 { }; interface I260 { }; interface I261 { }; interface I262 { }; interface I263 { }; interface I264 { }; interface I265 { }; interface I266 { }; interface I267 { }; interface I268 { }; interface I269 { }; interface I270 { }; interface I271 { }; interface I272 { }; interface I273 { }; interface I274 { }; interface I275 { }; interface I276 { }; interface I277 { }; interface I278 { }; interface I279 { }; interface I280 { }; interface I281 { }; interface I282 { }; interface I283 { }; interface I284 { }; interface I285 { }; interface I286 { }; interface I287 { }; interface I288 { }; interface I289 { }; interface I290 { }; interface I291 { }; interface I292 { }; interface I293 { }; interface I294 { }; interface I295 { }; interface I296 { }; interface I297 { }; interface I298 { }; interface I299 { }; interface I300 { };
// @formatter:on
}
/* +UseSecondarySupersTable
[info] # JMH version: 1.37
[info] # VM version: JDK 25, OpenJDK 64-Bit Server VM, 25+36-LTS
[info] # VM invoker: /Users/jz/.sdkman/candidates/java/25-zulu/zulu-25.jdk/Contents/Home/bin/java
[info] # VM options: -DscalaVersion=2.13.16 -DscalaRef=v2.13.16 -Dsbt.launcher=/opt/homebrew/Cellar/sbt/1.11.0/libexec/bin/sbt-launch.jar -XX:+UnlockDiagnosticVMOptions -XX:+UseSecondarySupersTable
[info] # Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
[info] # Warmup: 4 iterations, 2 s each
[info] # Measurement: 4 iterations, 2 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Average time, time/op
[info] # Benchmark: scala.tools.nsc.CakePattern.measure
[info] # Parameters: (numInterfaces = 80)
[info] # Run progress: 0.00% complete, ETA 00:00:16
[info] # Fork: 1 of 1
...
[info] ns percent samples top
[info] ---------- ------- ------- ---
[info] 7640000000 94.91% 764 lookup_secondary_supers_table_slow_path
[info] 310000000 3.85% 31 scala.tools.nsc.CakePattern.measure
[info] 70000000 0.87% 7 scala.tools.nsc.CakePattern$Impl$Names$Name.<init>
[info] 10000000 0.12% 1 Matcher::match_tree
[info] 10000000 0.12% 1 __psynch_cvwait
[info] 10000000 0.12% 1 java.util.AbstractQueue.addAll
[info] Async profiler results:
[info] /Users/jz/code/compiler-benchmark/micro/scala.tools.nsc.CakePattern.measure-AverageTime-numInterfaces-80/summary-cpu.txt
[info] # Run complete. Total time: 00:00:19
[info] REMEMBER: The numbers below are just data. ...
[info] Benchmark (numInterfaces) Mode Cnt Score Error Units
[info] CakePattern.measure 80 avgt 4 24.877 ± 7.768 ns/op
[info] CakePattern.measure:async 80 avgt NaN ---
[success] Total time: 25 s, completed 14 Oct 2025, 1:40:17 pm
*/
/* -UseSecondarySupersTable
[info] # JMH version: 1.37
[info] # VM version: JDK 25, OpenJDK 64-Bit Server VM, 25+36-LTS
[info] # VM invoker: /Users/jz/.sdkman/candidates/java/25-zulu/zulu-25.jdk/Contents/Home/bin/java
[info] # VM options: -DscalaVersion=2.13.16 -DscalaRef=v2.13.16 -Dsbt.launcher=/opt/homebrew/Cellar/sbt/1.11.0/libexec/bin/sbt-launch.jar -XX:+UnlockDiagnosticVMOptions -XX:-UseSecondarySupersTable
[info] # Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable)
[info] # Warmup: 4 iterations, 2 s each
[info] # Measurement: 4 iterations, 2 s each
[info] # Timeout: 10 min per iteration
[info] # Threads: 1 thread, will synchronize iterations
[info] # Benchmark mode: Average time, time/op
[info] # Benchmark: scala.tools.nsc.CakePattern.measure
[info] # Parameters: (numInterfaces = 80)
[info] # Run progress: 0.00% complete, ETA 00:00:16
[info] # Fork: 1 of 1
[info] # Preparing profilers: AsyncProfiler
[info] ns percent samples top
[info] ---------- ------- ------- ---
[info] 5050000000 62.66% 505 scala.tools.nsc.CakePattern.measure
[info] 2870000000 35.61% 287 scala.tools.nsc.jmh_generated.CakePattern_measure_jmhTest.measure_avgt_jmhStub
[info] 100000000 1.24% 10 scala.tools.nsc.CakePattern$Impl$Names$Name.<init>
[info] 30000000 0.37% 3 __psynch_cvwait
[info] 10000000 0.12% 1 PhaseChaitin::elide_copy
[info] Async profiler results:
[info] /Users/jz/code/compiler-benchmark/micro/scala.tools.nsc.CakePattern.measure-AverageTime-numInterfaces-80/summary-cpu.txt
[info] # Run complete. Total time: 00:00:16
[info] REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
[info] why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
[info] experiments, perform baseline and negative tests that provide experimental control, make sure
[info] the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
[info] Do not assume the numbers tell you what you want them to tell.
[info] NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise
[info] extra caution when trusting the results, look into the generated code to check the benchmark still
[info] works, and factor in a small probability of new VM bugs. Additionally, while comparisons between
[info] different JVMs are already problematic, the performance difference caused by different Blackhole
[info] modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons.
[info] Benchmark (numInterfaces) Mode Cnt Score Error Units
[info] CakePattern.measure 80 avgt 4 0.584 ± 0.198 ns/op
[info] CakePattern.measure:async 80 avgt NaN ---
[success] Total time: 18 s, completed 14 Oct 2025, 1:43:26 pm
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment