The Art of Realizing One is Wrong - Exercises
Put the myth to the test
String
operation performance
public class D01
{
...
@Benchmark
public String classic() {
// classic string magic here, such as a + b
return null;
}
@Benchmark
public String concat() {
// use a.concat(b)
return null;
}
@Benchmark
public String builder() {
// use a stringbuilder a.append(b)
return null;
}
@Benchmark
public String sizedBuilder() {
// use a presized stringbuilder
// new StringBuilder(expectedSize)
// a.append(b)
return null;
}
}
org.xc.jmh.D01
Just write a benchmark
public class D05
{
@Setup
public void setup()
{
// Berlin;12.4
// Rom;25.9
// Bergen;-5.5
}
@Benchmark
public void split(final Blackhole b)
{
// String::split()
}
@Benchmark
public void indexOf(final Blackhole b)
{
// String::indexOf
}
@Benchmark
public void tokenizer(final Blackhole b)
{
// use StringTokenizer
}
@Benchmark
public void yourOwn(final Blackhole b)
{
// an optional different idea
}
}
org.xc.jmh.D05
A little bit of #1brc fun
org.xc.jmh.BRC01
Benchmark Mode Cnt Score Error Units
classic avgt 5 29.378 ± 0.282 ns/op
classic:IPC avgt 3.674 insns/clk
classic:L1-dcache-load-misses avgt 1.578 #/op
classic:L1-dcache-loads avgt 69.274 #/op
classic:branch-misses avgt 0.493 #/op
classic:branches avgt 70.527 #/op
classic:cycles avgt 74.957 #/op
classic:instructions avgt 275.363 #/op
classic:stalled-cycles-frontend avgt 4.690 #/op
ownParseDouble avgt 5 9.260 ± 0.155 ns/op
ownParseDouble:IPC avgt 4.174 insns/clk
ownParseDouble:L1-dcache-load-misses avgt 2.288 #/op
ownParseDouble:L1-dcache-loads avgt 12.608 #/op
ownParseDouble:branch-misses avgt 0.006 #/op
ownParseDouble:branches avgt 18.181 #/op
ownParseDouble:cycles avgt 23.588 #/op
ownParseDouble:instructions avgt 98.465 #/op
ownParseDouble:stalled-cycles-frontend avgt 0.328 #/op
parseToIntFromByte avgt 5 6.372 ± 0.216 ns/op
parseToIntFromByte:IPC avgt 4.805 insns/clk
parseToIntFromByte:L1-dcache-load-misses avgt 1.018 #/op
parseToIntFromByte:L1-dcache-loads avgt 10.084 #/op
parseToIntFromByte:branch-misses avgt 0.009 #/op
parseToIntFromByte:branches avgt 15.778 #/op
parseToIntFromByte:cycles avgt 16.394 #/op
parseToIntFromByte:instructions avgt 78.778 #/op
parseToIntFromByte:stalled-cycles-frontend avgt 0.146 #/op
parseToIntFromByteFixed3 avgt 5 2.767 ± 0.009 ns/op
parseToIntFromByteFixed3:IPC avgt 4.074 insns/clk
parseToIntFromByteFixed3:L1-dcache-load-misses avgt 1.023 #/op
parseToIntFromByteFixed3:L1-dcache-loads avgt 5.461 #/op
parseToIntFromByteFixed3:branch-misses avgt 0.001 #/op
parseToIntFromByteFixed3:branches avgt 6.447 #/op
parseToIntFromByteFixed3:cycles avgt 7.040 #/op
parseToIntFromByteFixed3:instructions avgt 28.683 #/op
parseToIntFromByteFixed3:stalled-cycles-frontend avgt 0.050 #/op
parseToIntFromString avgt 5 8.439 ± 0.065 ns/op
parseToIntFromString:IPC avgt 4.187 insns/clk
parseToIntFromString:L1-dcache-load-misses avgt 2.297 #/op
parseToIntFromString:L1-dcache-loads avgt 12.617 #/op
parseToIntFromString:branch-misses avgt 0.004 #/op
parseToIntFromString:branches avgt 17.272 #/op
parseToIntFromString:cycles avgt 21.475 #/op
parseToIntFromString:instructions avgt 89.904 #/op
parseToIntFromString:stalled-cycles-frontend avgt 0.257 #/op
Let's Tackle the Problem
What is your motivation?
If you are an OpenJDK contributor, feel free to ignore the above ;)
No idea? No benchmark!
Most performance problems are not longer about CPU usage rather about not using the CPU.
Build your code
Stop thinking about the CPU!
Shape the future outcome
Data creation and mutation can be challenging
Wrong conclusions can be drawn in seconds with this trick
Functional correctness before performance
No unit tests, no microbenchmark!
Never believe in your first results
Vary a little to feel confident
Luke, minimal disturbance to the force you must apply.
Use the power of JMH
-prof gc
-prof perf/perfnorm
-prof perfasm
-prof comp
-prof cl
-prof jfr
-prof async
You might have to google a lot.
Ask someone but ChatGPT
One shall not claim success before someone else said so.
Remember our experiments and more
A Summary of Things
Microbenchmarking is...
When and when not to do microbenchmarks
The JMH warning
REMEMBER: The numbers are just data. To gain reusable insights, you need to follow up on why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial experiments, perform baseline and negative tests that provide experimental control, make sure the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.
Because you have seen it on my slides, does not make it right!