the bytecode hocus pocus - javaone 2016

Post on 12-Apr-2017

574 Views

Category:

Engineering

2 Downloads

Preview:

Click to see full reader

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