37. object ImmutableCalc {
case class Calculator(total : Int = 0) {
def add(i: Int) :Calculator = this.copy(total = total + i)
def get() : Int = total
}
}
38. object MutableCalc {
class Calculator {
var total = 0
def add(i: Int) : Unit = total+=i
def get() : Int = total
}
}
41. and ~ 20 other methods
//CODE decompiled using decompile Scala to Java
public final class ImmutableCalc {
public static class Calculator implements Product, Serializable {
private final int total;
public Iterator productElementNames() {
return Product.productElementNames$(this);
}
public int total() {
return this.total;
}
public ImmutableCalc.Calculator add(final int i) {
return this.copy(this.total() + i);
}
public int get() {
return this.total();
}
public ImmutableCalc.Calculator copy(final int total) {
45. INFOINFO
There is also lot of metadata in .class �les (not only bytecode)
No one needs to read bytecode - unless You work on a compiler
46. Run it
object CalcRun {
def main(args: Array[String]): Unit = {
var sum = 0L
for ( i <-0 to 100000) {
val calc = ImmutableCalc.Calculator()
sum+=(1 to 10000).foldLeft( calc)((c,i) => c.add(i)).get()
}
println(sum)
}
}
52. WHY BOTHER WITH PRINTCOMPILATION,WHY BOTHER WITH PRINTCOMPILATION,
INLININGINLINING
1. check if critical code was in fact JITed
2. sometimes problems with bytecode can be seen (method never
compiled)
3. look for uncommon traps
57. @Benchmark
def imperative: Int = {
val calc = new MutableCalc.Calculator()
(1 to numOps).foreach(calc.add)
calc.get()
}
@Benchmark
def immutable: Int = {
val calc = ImmutableCalc.Calculator()
(1 to numOps).foldLeft( calc)((c,i) => c.add(i)).get()
}
58. object ImmutableCalc {
case class Calculator(total : Int = 0) {
def add(i: Int) :Calculator = this.copy(total = total + i)
def get() : Int = total
}
}
object MutableCalc {
class Calculator {
var total = 0
def add(i: Int) : Unit = total+=i
def get() : Int = total
}
}
59. VM version: JDK 1.8.0_242, OpenJDK 64-Bit Server VM, 25.242-b08
67. The Java Flight Recorder (JFR) is a commercial feature. You can use it
for free on developer desktops/laptops, and for evaluation purposes in
test, development, and production environments. However, to enable
JFR on a production server, you require a commercial license. Using
JMC UI for other purposes on the JDK does not require a commercial
license.
68. Java Flight Recorder
low overhead,
detailed jvm events,
additional graphs and tools (for jfr) (intellij)
own events, (use for low overhead trace log)
only on some jvms
license - check your jvm version
-XX:+FlightRecorder
-XX:StartFlightRecording=duration=60s,filename=myrecording.j
74. jstack 91221 (java 8)
"main" #1 prio=5 os_prio=0 tid=0x00007f33b400d800 nid=0x14812 runnable [0x00007f33bdf38000]
java.lang.Thread.State: RUNNABLE
at calculator.immuable.ImmutableCalc$Calculator.<init>(ImmutableCalc.scala:4)
at calculator.immuable.ImmutableCalc$Calculator.copy(ImmutableCalc.scala:4)
at calculator.immuable.ImmutableCalc$Calculator.add(ImmutableCalc.scala:6)
at runners.CalcRun$.$anonfun$main$2(CalcRun.scala:10)
at runners.CalcRun$.$anonfun$main$2$adapted(CalcRun.scala:10)
at runners.CalcRun$$$Lambda$4/801197928.apply(Unknown Source)
at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:636)
at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:632)
at scala.collection.AbstractIterable.foldLeft(Iterable.scala:921)
at runners.CalcRun$.$anonfun$main$1(CalcRun.scala:10)
75. jstack 94038 (graal)
"main" #1 prio=5 os_prio=0 cpu=26791.23ms elapsed=26.89s tid=0x00007fafb0028800 nid=0x13d86 runnable [
java.lang.Thread.State: RUNNABLE
at scala.collection.IterableOnceOps.foldLeft(IterableOnce.scala:635)
at scala.collection.IterableOnceOps.foldLeft$(IterableOnce.scala:632)
at scala.collection.AbstractIterable.foldLeft(Iterable.scala:921)
at runners.CalcRun$.$anonfun$main$1(CalcRun.scala:10)
at runners.CalcRun$$$Lambda$17/0x00000008400d8040.apply$mcVI$sp(Unknown Source)
at scala.collection.immutable.Range.foreach$mVc$sp(Range.scala:190)
at runners.CalcRun$.main(CalcRun.scala:8)
at runners.CalcRun.main(CalcRun.scala)
"Reference Handler" #2 daemon prio=10 os_prio=0 cpu=0.32ms elapsed=26.87s tid=0x00007fafb024c800 nid=
java.lang.Thread.State: RUNNABLE
at java.lang.ref.Reference.waitForReferencePendingList(java.base@11.0.6/Native Method)
at java.lang.ref.Reference.processPendingReferences(java.base@11.0.6/Reference.java:241
at java.lang.ref.Reference$ReferenceHandler.run(java.base@11.0.6/Reference.java:213)
100. object OptimizedDB {
val connection = DB.initializeDB
def run = {
val count = Users.countParents()
count
}
object Users {
val userQuery = connection.prepareStatement("SELECT " +
"count(*) FROM USERS u1, USERS u2 WHERE u1.id>1 and u1.id < 100 AND u1.parentId = u2.id"
def countParents(): Int = {
userQuery.clearParameters()
val res = userQuery.executeQuery()
try {
if (res.next()) {
res.getInt(1)
} else {
throw new IllegalStateException("no count from DB")
}
107. simple for
val array = Array.ofDim[Long](sz + 1, sz + 1)
@Benchmark
def forBasedLoop: Long = {
var sum: Long = 0
for (i <- 0 to sz) {
for (j <- 0 to sz) {
sum += array(i)(j)
}
}
sum
}
108. while
@Benchmark
def whileLoopA: Long = {
var sum: Long = 0
var i = 0
while (i < sz) {
var j = 0
while (j < sz) {
sum += array(i)(j)
j = j + 1
}
i = i + 1
}
sum
}
109. while reversed (and transposed)
@Benchmark
def whileRevLoop: Long = {
var sum: Long = 0
var j = sz
while (j >= 0) {
var i = sz
while (i >= 0) {
sum += array(i)(j)
i = i - 1
}
j = j - 1
}
sum
}
121. ON A GOOD BENCHMARKSON A GOOD BENCHMARKS
Benchmark might be ok:
you test it for yourself
you read about the tools tested
you can �nd what causes di�erences
122. HINTSHINTS
Tools will not magically solve your problems
Tools let you feel more comfortable
Do not expect PrintAssembly or Performance counters will help you in
typical problems
123. REAL PROBLEMS I HAD ON PRODUCTIONREAL PROBLEMS I HAD ON PRODUCTION
hidden read of whole database in a dirty piece of code
static synchronized
hashCode bugs
jvm bugs (metaspace)
Lot of them could be spotted by using jstack