the bytecode hocus pocus - javaone 2016
Post on 12-Apr-2017
574 Views
Preview:
TRANSCRIPT
@rrafols
The bytecodehocus-pocus
#perfmatters
@rrafols
DisclaimerThis presentation contains bytecode
Content is my own experimentation and might differ on other environments
@rrafols
Competitions
Work
2015 Local winner2016 Ambassador
Runner up
Demoscene
Speaker
Author Entrerpreneurship
About me
@rrafols
Our friend the java compiler
@rrafols
*.java → [javac] → *.class
@rrafols
Or, for example, on Android
@rrafols
*.java → [javac] → *.class
*.class → [dx] → dex file
@rrafols
*.java → [javac] → *.class*.class → [dx] → dex
dex → [dexopt] → optimized dexdex → [dex2oat] → optimized native
@rrafols
but change is coming!Jack & Jill
@rrafols
*.java → [jack] → dex file
@rrafols
Let’s focus on javacJavac vs other compilers
@rrafols
Compilers
Produces optimized code for the target platform
@rrafols
Javac
Does not produce optimized code*
@rrafols
Javac
Does not know on which architecture the code will be
executed
@rrafols
Source: Oracle
@rrafols
For this reason
Java bytecode & operations are stack based
@rrafols
Easy to interpret
But not the most optimal solution
(regarding performance)
@rrafols
Quick example
Stack based integer addition
@rrafols
j = j + i
@rrafols
Java bytecode
@rrafols
iload_3
iload_2
iadd
istore_2
@rrafols
Register based approach
@rrafols
add r01, r02, r01
or
add eax, ebx
@rrafols
Let’s make things interesting…
j = j + i + k + w + h * 2 + p * p;
@rrafols
Java bytecode
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
0: iload_2 1: iload_1 2: iadd 3: iload_3 4: iadd 5: iload 4 7: iadd 8: iload 510: iconst_211: imul12: iadd13: iload 615: iload 617: imul18: iadd19: istore_2
j = j + i + k + w + h * 2 + p * p;
Local vars1: i2: j3: k4: w5: h6: p
@rrafols
Register based approach
@rrafols
add r01, r02, r01add r01, r03, r01add r01, r04, r01mul r07, r05, #2add r01, r07, r01mul r08, r06, r06add r02, r08, r01
j = j + i + k + w + h * 2 + p * p;
r01: ir02: jr03: kr04: wr05: hr06: p
@rrafols
Java VM (JVM)
Only the JVM knows on which architecture is running. In this
case, for example, we used up to 8 registers
@rrafols
Java VM (JVM)
All optimizations are left to be done by the JVM
@rrafols
Maybe takes this concept a bit too far...
@rrafols
Imagine this simple C code#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
printf("%d\n", b);
}
@rrafols
GCC compiler#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
printf("%d\n", b);
}
…
movl $31, %esicall _printf
…
* Using gcc & -O2 compiler option
@rrafols
javac
public static void main(String args[]) {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + 6 + a;
System.out.println(b);
}
0: bipush 10
2: istore_1
3: bipush 21
5: iload_1
6: iadd
7: istore_2
...
@rrafols
Let's do a small change#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
printf("%d\n", b);
}
@rrafols
GCC compiler#include <stdio.h>
int main() {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
printf("%d\n", b);
}
…
movl $31, %esicall _printf
…
* Using gcc & -O2 compiler option
@rrafols
javac
public static void main(String args[]) {
int a = 10;
int b = 1 + 2 + 3 + 4 + 5 + a + 6;
System.out.println(b);
}
0: bipush 10
2: istore_1
3: bipush 155: iload_1 6: iadd 7: bipush 69: iadd 10: istore_2
...
@rrafols
Let's do another quick change..
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
@rrafols
javac
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
0: bipush 10
2: istore_1
3: iload_1
4: iconst_1
5: iadd
6: iconst_2
7: iadd
8: iconst_3
9: iadd
10: iconst_4
11: iadd
12: iconst_5
13: iadd
14: bipush 6
16: iadd
17: istore_2
...
@rrafols
On Android there is jack to the rescue...
@rrafols
jack
public static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
...
0: const/16 v0, #int 312: sget-object v1, Ljava/lang/System;
4: invoke-virtual {v1, v0}
7: return-void
...
@rrafols
And on Java there is the JIT compiler to the rescue
@rrafols
JIT assembly outputpublic static void main(String args[]) {
int a = 10;
int b = a + 1 + 2 + 3 + 4 + 5 + 6;
System.out.println(b);
}
...
0x00000001104b2bff: mov eax, 0x000000000000001f...
0: bipush 10
2: istore_1
3: iload_1
4: iconst_1
5: iadd
6: iconst_2
7: iadd
8: iconst_3
9: iadd
10: iconst_4
11: iadd
12: iconst_5
13: iadd
14: bipush 6
16: iadd
17: istore_2
...
@rrafols
Compilers
Produces optimised code for target platform
@rrafols
Language additions
Thinks to consider
@rrafols
Autoboxing
Transparent to the developer but compiler adds some 'extra' code
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 421:
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
Autoboxinglong total = 0;for(int i = 0; i < N; i++) { total += i;}
0: lconst_0 1: lstore_1 2: iconst_0 3: istore_3 4: iload_3 5: ldc #8 // N 7: if_icmpge 2110: lload_111: iload_312: i2l13: ladd14: lstore_115: iinc 3, 118: goto 4
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingLong total = 0;for(Integer i = 0; i < N; i++) { total += i;}
// ?
0: lconst_0 1: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;4: astore_1 5: iconst_0 6: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;9: astore_2 10: aload_2 11: invokevirtual #9 // Method java/lang/Integer.intValue:()I14: sipush N17: if_icmpge 5420: aload_1 21: invokevirtual #10 // Method java/lang/Long.longValue:()J24: aload_2 25: invokevirtual #9 // Method java/lang/Integer.intValue:()I28: i2l 29: ladd 30: invokestatic #7 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;33: astore_1 34: aload_2 35: astore_3 36: aload_2 37: invokevirtual #9 // Method java/lang/Integer.intValue:()I40: iconst_1 41: iadd 42: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;45: dup 46: astore_2 47: astore 449: aload_3 50: pop 51: goto 10
@rrafols
AutoboxingThis is what that code is actually doing:
Long total = Long.valueOf(0);for(Integer i = Integer.valueOf(0); i.intValue() < N; i = Integer.valueOf(i.intValue() + 1)) { total = Long.valueOf(total.longValue() + (long)i.intValue())}
@rrafols
AutoboxingObject creation
Long total = Long.valueOf(0);for(Integer i = Integer.valueOf(0); i.intValue() < N; i = Integer.valueOf(i.intValue() + 1)) { total = Long.valueOf(total.longValue() + (long)i.intValue())}
@rrafols
Autoboxing
What about Jack?
@rrafols
Autoboxing
Jack does not help in this situation
@rrafols
Autoboxing
What about the JIT compiler?
@rrafols
Autoboxing
Let's run that loop
10.000.000.000 times
(on my desktop computer)
@rrafols
Autoboxing
@rrafols
Autoboxing
Let's run that loop 100.000.000
Times on two Nexus 5
KitKat (Dalvik VM) & Lollipop (ART)
@rrafols
Autoboxing
@rrafols
Language Additions
Use them wisely!
@rrafols
Sorting
No bytecode mumbo-jumbo here
@rrafols
Let's sort some numbers…
Arrays.sort(...)
@rrafols
Difference between sorting primitive types & objects
@rrafols
Using int & Integer
@rrafols
Sorting objects is a stable sort
Default java algorithm: TimSort adaptation
@rrafols
Sorting primitives does not require to be stable sort
Default java algorithm:
Dual-Pivot quicksort
@rrafols
Sorting
Use primitive types as much as possible
@rrafols
Loops
@rrafols
Loops
What is going on behind the scenes
@rrafols
Loops - ListArrayList<Integer> list = new …static long loopStandardList() {
long result = 0; for(int i = 0; i < list.size(); i++) {
result += list.get(i); }
return result;}
@rrafols
Loops - ListArrayList<Integer> list = new …static long loopStandardList() {
long result = 0; for(int i = 0; i < list.size(); i++) {
result += list.get(i); }
return result;}
7: lload_0
8: getstatic #26 // Field list:Ljava/util/ArrayList;
11: iload_2
12: invokevirtual #54 // Method java/util/ArrayList.get:(I)
15: checkcast #38 // class java/lang/Integer
18: invokevirtual #58 // Method java/lang/Integer.intValue:()I
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic #26 // Field list:Ljava/util/ArrayList;
31: invokevirtual #61 // Method java/util/ArrayList.size:()I
34: if_icmplt 7
@rrafols
Loops - ListArrayList<Integer> list = new …static long loopStandardList() {
long result = 0; for(int i = 0; i < list.size(); i++) {
result += list.get(i); }
return result;}
7: lload_0
8: getstatic #26 // Field list:Ljava/util/ArrayList;
11: iload_2
12: invokevirtual #54 // Method java/util/ArrayList.get:(I)
15: checkcast #38 // class java/lang/Integer
18: invokevirtual #58 // Method java/lang/Integer.intValue:()I
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic #26 // Field list:Ljava/util/ArrayList;
31: invokevirtual #61 // Method java/util/ArrayList.size:()I
34: if_icmplt 7
@rrafols
Loops - ListArrayList<Integer> list = new …static long loopStandardList() {
long result = 0; for(int i = 0; i < list.size(); i++) {
result += list.get(i); }
return result;}
7: lload_0
8: getstatic #26 // Field list:Ljava/util/ArrayList;
11: iload_2
12: invokevirtual #54 // Method java/util/ArrayList.get:(I)
15: checkcast #38 // class java/lang/Integer
18: invokevirtual #58 // Method java/lang/Integer.intValue:()I
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic #26 // Field list:Ljava/util/ArrayList;
31: invokevirtual #61 // Method java/util/ArrayList.size:()I
34: if_icmplt 7
@rrafols
Loops - ListArrayList<Integer> list = new …static long loopStandardList() {
long result = 0; for(int i = 0; i < list.size(); i++) {
result += list.get(i); }
return result;}
7: lload_0
8: getstatic #26 // Field list:Ljava/util/ArrayList;
11: iload_2
12: invokevirtual #54 // Method java/util/ArrayList.get:(I)
15: checkcast #38 // class java/lang/Integer
18: invokevirtual #58 // Method java/lang/Integer.intValue:()I
21: i2l
22: ladd
23: lstore_0
24: iinc 2, 1
27: iload_2
28: getstatic #26 // Field list:Ljava/util/ArrayList;
31: invokevirtual #61 // Method java/util/ArrayList.size:()I
34: if_icmplt 7
@rrafols
Loops - foreachArrayList<Integer> list = new …static long loopForeachList() {
long result = 0; for(int v : list) {
result += v; } return result;
}
@rrafols
Loops - foreachArrayList<Integer> list = new …static long loopForeachList() {
long result = 0; for(int v : list) {
result += v; } return result;
}
12: aload_3
13: invokeinterface #70, 1 // java/util/Iterator.next:()
18: checkcast #38 // class java/lang/Integer
21: invokevirtual #58 // Method java/lang/Integer.intValue:()I
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface #76, 1 // java/util/Iterator.hasNext:()Z
36: ifne 12
@rrafols
Loops - foreachArrayList<Integer> list = new …static long loopForeachList() {
long result = 0; for(int v : list) {
result += v; } return result;
}
12: aload_3
13: invokeinterface #70, 1 // java/util/Iterator.next:()
18: checkcast #38 // class java/lang/Integer
21: invokevirtual #58 // Method java/lang/Integer.intValue:()I
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface #76, 1 // java/util/Iterator.hasNext:()Z
36: ifne 12
@rrafols
Loops - foreachArrayList<Integer> list = new …static long loopForeachList() {
long result = 0; for(int v : list) {
result += v; } return result;
}
12: aload_3
13: invokeinterface #70, 1 // java/util/Iterator.next:()
18: checkcast #38 // class java/lang/Integer
21: invokevirtual #58 // Method java/lang/Integer.intValue:()I
24: istore_2
25: lload_0
26: iload_2
27: i2l
28: ladd
29: lstore_0
30: aload_3
31: invokeinterface #76, 1 // java/util/Iterator.hasNext:()Z
36: ifne 12
@rrafols
Loops - Arraystatic int[] array = new ...static long loopStandardArray() {
long result = 0; for(int i = 0; i < array.length; i++) {
result += array[i]; } return result;
}
@rrafols
Loops - Arraystatic int[] array = new ...static long loopStandardArray() {
long result = 0; for(int i = 0; i < array.length; i++) {
result += array[i]; } return result;
}
7: lload_0
8: getstatic #28 // Field array:[I
11: iload_2
12: iaload
13: i2l
14: ladd
15: lstore_0
16: iinc 2, 1
19: iload_2
20: getstatic #28 // Field array:[I
23: arraylength
24: if_icmplt 7
@rrafols
Loops - Arraystatic int[] array = new ...static long loopStandardArray() {
long result = 0; for(int i = 0; i < array.length; i++) {
result += array[i]; } return result;
}
7: lload_0 8: getstatic #28 // Field array:[I11: iload_2 12: iaload 13: i2l 14: ladd 15: lstore_0 16: iinc 2, 1
19: iload_2
20: getstatic #28 // Field array:[I
23: arraylength
24: if_icmplt 7
@rrafols
Loops - Arraystatic int[] array = new ...static long loopStandardArray() {
long result = 0; for(int i = 0; i < array.length; i++) {
result += array[i]; } return result;
}
7: lload_0 8: getstatic #28 // Field array:[I
11: iload_2
12: iaload
13: i2l
14: ladd
15: lstore_0
16: iinc 2, 1
19: iload_2 20: getstatic #28 // Field array:[I23: arraylength 24: if_icmplt 7
@rrafols
Loops - size cachedstatic int[] array = new ...static long loopStandardArray () {
long result = 0; int length = array.length;
for(int i = 0; i < length; i++) { result += array[i];
} return result;
}
@rrafols
Loops - size cachedstatic int[] array = new ...static long loopStandardArray () {
long result = 0; int length = array.length;
for(int i = 0; i < length; i++) { result += array[i];
} return result;
}
12: lload_0
13: getstatic #28 // Field array:[I
16: iload_3
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 3, 1
24: iload_3
25: iload_2
26: if_icmplt 12
@rrafols
Loops - size cachedstatic int[] array = new ...static long loopStandardArray () {
long result = 0; int length = array.length;
for(int i = 0; i < length; i++) { result += array[i];
} return result;
}
12: lload_0
13: getstatic #28 // Field array:[I
16: iload_3
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 3, 1
24: iload_3 25: iload_2 26: if_icmplt 12
@rrafols
Loops - backwardsstatic int[] array = new ...static long loopStandardArray () {
long result = 0;for(int i = array.length - 1; i >= 0; i--) {
result += array[i];}return result;
}
@rrafols
Loops - backwardsstatic int[] array = new ...static long loopStandardArray () {
long result = 0;for(int i = array.length - 1; i >= 0; i--) {
result += array[i];}return result;
}
12: lload_0
13: getstatic #28 // Field array:[I
16: iload_2
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 2, -1
24: iload_2
25: ifge 12
@rrafols
Loops - backwardsstatic int[] array = new ...static long loopStandardArray () {
long result = 0;for(int i = array.length - 1; i >= 0; i--) {
result += array[i];}return result;
}
12: lload_0 13: getstatic #28 // Field array:[I
16: iload_2
17: iaload
18: i2l
19: ladd
20: lstore_0
21: iinc 2, -1
24: iload_2 25: ifge 12
@rrafols
@rrafols
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 -
1 - 5 -
2 - 6 -
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 -
1 0 (result) 5 -
2 - 6 -
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 -
1 0 (result) 5 -
2 - 6 array
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 -
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 - 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 0 (loop index)
1 0 (result) 5 array.length
2 - 6 array
3 array[index] 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 0 (loop index)
1 0 + array[index] 5 array.length
2 - 6 array
3 array[index] 7 -
@rrafols
Loops – foreach IIstatic long loopForeachArray(int[] array) {
long result = 0; for(int v : array) {
result += v; } return result;
}
0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0 array 4 0 (loop index) + 1
1 0 + array[index] 5 array.length
2 - 6 array
3 array[index] 7 -
@rrafols
@rrafols
@rrafols
Loops
Use arrays instead of lists
@rrafols
Loops
When using lists, avoid foreach or iterator constructions if
performance is a requirement
@rrafols
Manual bytecode optimization
Worth it?
@rrafols
Loops – foreach II 0: lconst_0 1: lstore_1 2: aload_0 3: dup 4: astore 6 6: arraylength 7: istore 5 9: iconst_010: istore 412: goto 2915: aload 617: iload 419: iaload20: istore_321: lload_122: iload_323: i2l24: ladd25: lstore_126: iinc 4, 129: iload 431: iload 533: if_icmplt 15
0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Manual bytecode optimization
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 -
1 - 4 -
2 - 5 -
Stack
-
-
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 - 4 -
2 - 5 -
Stack
-
-
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
-
-
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 (result)
-
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 (result)
array[index]
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) 4 -
2 - 5 -
Stack
0 + array[index]
-
-
@rrafols
Manual bytecode optimization 0: aload_0 1: arraylength 2: istore_3 3: iconst_0 4: istore_1 5: lconst_0 6: goto 17 9: aload_010: iload_111: iaload12: i2l13: ladd14: iinc 1, 117: iload_118: iload_319: if_icmplt 9
Local variables
0 array 3 array.length
1 0 (index) + 1 4 -
2 - 5 -
Stack
0 + array[index]
-
-
@rrafols *reduced data set
@rrafols
Worth it?
Only in very specific, unique, peculiar cases.
Too much effort involved.
@rrafols
Calling a method
Is there an overhead?
@rrafols
Overhead of calling a methodfor(int i = 0; i < N; i++) {
setVal(getVal() + 1);
}
for(int i = 0; i < N; i++) {
val = val + 1;
}
vs
@rrafols
@rrafols
String concatenation
The evil + sign
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenationString str = "";for(int i = 0; i < N; i++) {
str += OTHER_STR;}
0: ldc #13 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: sipush N9: if_icmpge 4012: new #14 // class java/lang/StringBuilder15: dup 16: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V19: aload_1 20: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)23: aload_0 24: getfield #3 // Field OTHER_STR:Ljava/lang/String;27: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)30: invokevirtual #17 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;33: astore_1 34: iinc 2, 137: goto 5
@rrafols
String concatenation - equivalent String str = "";for(int i = 0; i < N; i++) { StringBuilder sb = new StringBuilder(); sb.append(str); sb.append(OTHER_STR); str = sb.toString();}
@rrafols
String concatenationObject creation:
String str = "";for(int i = 0; i < N; i++) { StringBuilder sb = new StringBuilder(); sb.append(str); sb.append(OTHER_STR); str = sb.toString();}
@rrafols
String concatenation
alternatives
@rrafols
String.concat()• Concat cost is O(N) + O(M)
• Concat returns a new String Object.
String str = "";for(int i = 0; i < N; i++) {
str = str.concat(OTHER_STR);}
@rrafols
String.concat()Object creation:
String str = "";for(int i = 0; i < N; i++) {
str = str.concat(OTHER_STR);}
@rrafols
StringBuilder• StringBuilder.append cost is O(M) [M being the length of
appended String]
StringBuilder sb = new StringBuilder()for(int i = 0; i < N; i++) { sb.append(OTHER_STR);}str = sb.toString();
@rrafols
StringBuilderStringBuilder sb = new StringBuilder()for(int i = 0; i < N; i++) { sb.append(OTHER_STR);}str = sb.toString();
0: ldc #13 // String 2: astore_1 3: new #14 // class java/lang/StringBuilder6: dup 7: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V10: astore_2 11: iconst_0 12: istore_3 13: iload_3 14: sipush N17: if_icmpge 3520: aload_2 21: aload_0 22: getfield #3 // Field OTHER_STR:Ljava/lang/String;25: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;28: pop 29: iinc 3, 132: goto 13
@rrafols
StringBuilderStringBuilder sb = new StringBuilder()for(int i = 0; i < N; i++) { sb.append(OTHER_STR);}str = sb.toString();
0: ldc #13 // String 2: astore_1 3: new #14 // class java/lang/StringBuilder6: dup 7: invokespecial #15 // Method java/lang/StringBuilder."<init>":()V10: astore_2 11: iconst_0 12: istore_3 13: iload_3 14: sipush N17: if_icmpge 3520: aload_2 21: aload_0 22: getfield #3 // Field OTHER_STR:Ljava/lang/String;25: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;28: pop 29: iinc 3, 132: goto 13
@rrafols
StringBuilderObject creation:
StringBuilder sb = new StringBuilder();for(int i = 0; i < N; i++) { sb.append(OTHER_STR);}str = sb.toString();
@rrafols
String concatenation
Use StringBuilder (properly) as much as possible. StringBuffer is the thread safe implementation.
@rrafols
Strings in case statements
@rrafols
public void taskStateMachine(String status) { switch(status) { case "PENDING": System.out.println("Status pending"); break;
case "EXECUTING": System.out.println("Status executing"); break; } }
@rrafols
@rrafols
@rrafols
Tooling
@rrafols
Tooling - DisassemblerJava• javap -c <classfile>
Android:•Dexdump -d <dexfile>
@rrafols
Tooling - AssemblerKrakatauhttps://github.com/Storyyeller/Krakatau
@rrafols
Tooling – Disassembler - ARTadb pull /data/dalvik-cache/arm/data@app@<package>-1@base apk@classes.dex
gobjdump -D <file>
@rrafols
Tooling – Disassembler - ART
adb shell oatdump --oat-file=/data/dalvik-cache/arm/data@app@<package>-1@base.apk@classes.dex
@rrafols
Tooling – PrintAssembly - JIT-XX:+UnlockDiagnosticVMOptions
-XX:+PrintAssembly
-XX:CompileCommand=print,com.raimon.test.Test::method
Under the Hood of the JVM: From Bytecode Through the JIT to Assembly [CON3808]
http://alblue.bandlem.com/2016/09/javaone-hotspot.html
@rrafols
Always measure
example - yuv2rgb optimization
@rrafols
Source: Wikipedia
@rrafols
@rrafols
Slightly optimized version
precalc tables, fixed point operations, 2 pixels per loop…
@rrafols
@rrafols
@rrafols
Lets compare:
Normal, minified, minified with optimizations & jack
Minified = obfuscated using Proguard
@rrafols
Normal Minified Minified & optimized Jack0
2000
4000
6000
8000
10000
12000
14000
16000
18000
20000
non-optimizedoptimized
@rrafols
Performance measurements
Avoid doing multiple tests in one run
JIT might be evil!
@rrafols
Thank you!
http://blog.rafols.org
@rrafols
https://es.linkedin.com/in/raimonrafols
top related