103
Micro optimizations

Java micro optimizations 2017

Embed Size (px)

Citation preview

Page 1: Java micro optimizations 2017

Micro optimizations

Page 2: Java micro optimizations 2017

Dmitriy DumanskiyBlynk, CTO

Java blog : https://habrahabr.ru/users/doom369/topicsDOU : https://dou.ua/users/DOOM/articles/

Page 3: Java micro optimizations 2017

Makers problem

+ = ?

Page 4: Java micro optimizations 2017

Blynk

10000 req/sec3 VM * 2 cores, 60$

25% load10k of local installations

Page 5: Java micro optimizations 2017

Typical Env.

Worst case 256 RAM (~40Mb for heap)700 MHz, 1 core, ARM

Page 6: Java micro optimizations 2017

● Typical code● Plain java● System is under “highload”● All “issues” are from open-source

Today talk

Page 7: Java micro optimizations 2017

Problems everybody knows about

Page 8: Java micro optimizations 2017

● Primitive wrappers

Typical issues

Page 9: Java micro optimizations 2017

● Primitive wrappers● Boxing / Unboxing

Typical issues

Page 10: Java micro optimizations 2017

● Primitive wrappers● Boxing / Unboxing● Regex / Pattern matching

Typical issues

Page 11: Java micro optimizations 2017

● Primitive wrappers● Boxing / Unboxing● Regex / Pattern matching● String concatenation in loops

Typical issues

Page 12: Java micro optimizations 2017

● Primitive wrappers● Boxing / Unboxing● Regex / Pattern matching● String concatenation in loops● Reflection

Typical issues

Page 13: Java micro optimizations 2017
Page 14: Java micro optimizations 2017

class User { Date createdAt;}

What is wrong here?

Page 15: Java micro optimizations 2017

class User { Date createdAt;}

Memory consumption

Page 16: Java micro optimizations 2017

class Date { private transient long fastTime; private BaseCalendar.Date cdate;}

More memory

Page 17: Java micro optimizations 2017

class User { long createdAt;}

Solution

Page 18: Java micro optimizations 2017

for (String name : list) { //do something}

What is wrong here?

Page 19: Java micro optimizations 2017

for (String name : list) { //do something}

Iterator allocation

Page 20: Java micro optimizations 2017

Iterator<String> iter = list.iterator();while (iter.hasNext()) { String name = iter.next();}

Iterator allocation

Page 21: Java micro optimizations 2017

Scalar replacement. Could be.

Or could be not.

Iterator allocation

Page 22: Java micro optimizations 2017

for (int i = 0; i < list.size(); i++) { Data data = list.get(i);}

Solution 1

Page 23: Java micro optimizations 2017

for (String s : array) { //do something}

Solution 2

Page 24: Java micro optimizations 2017

iterateArray thrpt 168298 ops/siterateListWGet thrpt 132292 ops/siterateList thrpt 110188 ops/s

Iterator

+50%

Page 25: Java micro optimizations 2017

List<Device> devices = ...;return devices.get(0);

What is wrong here?

Page 26: Java micro optimizations 2017

List<Device> devices = ...;return devices.get(0);

Polymorphism

Page 27: Java micro optimizations 2017

invokeInterface

Polymorphism

Page 28: Java micro optimizations 2017

ArrayList<Device> devices = ...;return devices.get(0);

Solution

Page 29: Java micro optimizations 2017

arrayListGet thrpt 268418 ops/slistGet thrpt 249005 ops/s

Polymorphism

+7%

Page 30: Java micro optimizations 2017

class User { Device[] devices = {}; }

What is wrong here?

Page 31: Java micro optimizations 2017

class User { Device[] devices = {}; }

Allocations

Page 32: Java micro optimizations 2017

{} is new Device[0]

Allocations

Page 33: Java micro optimizations 2017

class User { final static Device[] EMPTY = {}; Device[] devices = EMPTY; }

Solution

Page 34: Java micro optimizations 2017

preAllocatedArray thrpt 209423 ops/snewArrayAllocation thrpt 104293 ops/s

Allocations

+50%

Page 35: Java micro optimizations 2017

void make(String… params)

What is wrong here?

Page 36: Java micro optimizations 2017

void make(String… params)

Allocations

Page 37: Java micro optimizations 2017

String… is new String[] {params}

Allocations

Page 38: Java micro optimizations 2017

void make(String p1)void make(String p1, String p2)void make(String p1, String p2, Str p3)

Solution

Page 39: Java micro optimizations 2017

noVarArgs thrpt 7947138 ops/svarArgs thrpt 4265333 ops/s

Allocations

+2x

Page 40: Java micro optimizations 2017

If (email == null || email.equals(“”)) { ...}

What is wrong here?

Page 41: Java micro optimizations 2017

If (email == null || email.equals(“”)) { ...}

Solution

Page 42: Java micro optimizations 2017

If (email == null || email.isEmpty()) { ...}

Slow equals

Page 43: Java micro optimizations 2017

isEmpty thrpt 364123 ops/sequals thrpt 231075 ops/s

Slow equals

+60%

Page 44: Java micro optimizations 2017

val.equals(input.toLowerCase());

What is wrong here?

Page 45: Java micro optimizations 2017

val.equals(input.toLowerCase());

Allocations

Page 46: Java micro optimizations 2017

val.equalsIgnoreCase(input);

Solution

Page 47: Java micro optimizations 2017

ignoreCase thrpt 47550 ops/stoLowerCase thrpt 20339 ops/s

Allocations

+2.3x

Page 48: Java micro optimizations 2017

val.startsWith(input.toLowerCase());

One more case

Page 49: Java micro optimizations 2017

val.regionMatches(true, 0, input, 0, len);

Solution

Page 50: Java micro optimizations 2017

regionMatch thrpt 54924 ops/sstartWithToLowerCase thrpt 14447 ops/s

Allocations

+4x

Page 51: Java micro optimizations 2017

Use strict equals

Solution 2

Page 52: Java micro optimizations 2017

val.split(“\0”);

What is wrong here?

Page 53: Java micro optimizations 2017

val.split(“\0”);

Split is slow

Page 54: Java micro optimizations 2017

Utils.split(val, ‘\0’);

Solution

Page 55: Java micro optimizations 2017

String[] split2(char separator, String body) { final int i1 = body.indexOf(separator, 1); if (i1 == -1) { return new String[] {body}; }

return new String[] { body.substring(0, i1), body.substring(i1 + 1, body.length()) }; }

Solution

Page 56: Java micro optimizations 2017

customSplit avgt 46 ns/opsplit avgt 115 ns/op

Split is slow

+3x

Page 57: Java micro optimizations 2017

return body1.trim() + SEPARATOR + body2.trim();

What is wrong here?

Page 58: Java micro optimizations 2017

return new StringBuilder().append(body1.trim()).append(SEPARATOR).append(body2.trim()).toString();

What is wrong here?

Page 59: Java micro optimizations 2017

return new StringBuilder().append(body1.trim()).append(SEPARATOR).append(body2.trim()).toString();

Concat optimization

Page 60: Java micro optimizations 2017

String trimmed1 = body1.trim();String trimmed2 = body2.trim();return trimmed1 + SEPARATOR + trimmed2;

Solution 1

Page 61: Java micro optimizations 2017

String trimmed1 = body1.trim();String trimmed2 = body2.trim();return new StringBuilder().append(trimmed1).append(SEPARATOR).append(trimmed2).toString();

Solution 2

Page 62: Java micro optimizations 2017

optimizedConcat thrpt 44888 ops/snaiveConcat thrpt 12866 ops/s

Concat optimization

+4x

Page 63: Java micro optimizations 2017

StringBuilder sb = new StringBuilder();sb.append(body1)sb.append(SEPARATOR)sb.append(body2)return sb.toString();

What is wrong here?

Page 64: Java micro optimizations 2017

StringBuilder sb = new StringBuilder();sb.append(body1)sb.append(SEPARATOR)sb.append(body2)return sb.toString();

No chaining

Page 65: Java micro optimizations 2017

return new StringBuilder().append(body1).append(SEPARATOR).append(body2).toString();

Solution

Page 66: Java micro optimizations 2017

chained thrpt 46279 ops/snotChained thrpt 27746 ops/s

Chaining

+70%

Page 67: Java micro optimizations 2017

String data = …;data.getBytes(charset);

What is wrong here?

Page 68: Java micro optimizations 2017

String data = …;data.getBytes(charset);

Generic Encoding

Page 69: Java micro optimizations 2017

if (charset == UTF_8) { return decodeUTF8(data);} else if (charset == US_ASCII) { return decodeASCII(data);} else { return data.getBytes(charset);}

Solution

Page 70: Java micro optimizations 2017

customGetBytes avgt 155 ns/opjavaGetBytes avgt 233 ns/op

Generic Encoding

+30%

Page 71: Java micro optimizations 2017

if (data == null) { throw new NoDataException();}

What is wrong here?

Page 72: Java micro optimizations 2017

if (data == null) { throw new NoDataException();}

Exception is expensive

Page 73: Java micro optimizations 2017

Double.parseDouble thrpt 22968 ops/sDouble.parseErr thrpt 737 ops/s

Exception Cost

+30x

Page 74: Java micro optimizations 2017

public Throwable(String message) { fillInStackTrace(); detailMessage = message;}

Exception Cost

Page 75: Java micro optimizations 2017

Throwable(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)

Exception Cost

Page 76: Java micro optimizations 2017

class MyException extends Exception { MyException(String message) {

super(message, null, true, false); }}

Solution 1

Page 77: Java micro optimizations 2017

final static MyException cache = new MyException();

Solution 2

Page 78: Java micro optimizations 2017

if (data == null) { return; //or return code}

Solution 3

Page 79: Java micro optimizations 2017

try { double d = Double.parseDouble(s);} catch (NumberFormatException e) {}

What is wrong here?

Page 80: Java micro optimizations 2017

try { double d = Double.parseDouble(s);} catch (NumberFormatException e) {}

Allocations

Page 81: Java micro optimizations 2017

● Does trim()● Spams ASCIIToBinaryConverter● Spams exceptions● Slow

Allocations

Page 82: Java micro optimizations 2017

try { double d = Utils.parseDouble(s);} catch (NumberFormatException e) {}

Solution

Page 83: Java micro optimizations 2017

parseDouble thrpt 22889 ops/sparseDoubleUtils thrpt 48331 ops/s

Custom parseDouble

+2.2x

Page 84: Java micro optimizations 2017

double d = 11.2321D;return Math.round(val);

What is wrong here?

Page 85: Java micro optimizations 2017

double d = 11.2321D;return Math.round(val);

Slow round

Page 86: Java micro optimizations 2017

double d = 11.2321D;return (int) (val + 0.5);

Solution

Page 87: Java micro optimizations 2017

Slow round

optimizedRound thrpt 383251 ops/smathRound thrpt 258123 ops/s

+50%

Page 88: Java micro optimizations 2017

public static int bitCount(int i) { i = i - ((i >>> 1) & 0x55555555); i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); i = (i + (i >>> 4)) & 0x0f0f0f0f; i = i + (i >>> 8); i = i + (i >>> 16); return i & 0x3f; }

What is wrong here?

Page 89: Java micro optimizations 2017
Page 90: Java micro optimizations 2017

Integer.bitCount(val);

Solution

Page 91: Java micro optimizations 2017

javaBitCount thrpt 413996 ops/smanualBitCount thrpt 232490 ops/s

Intrinsics

+80%

Page 92: Java micro optimizations 2017

http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/87ee5ee27509/src/share/vm/classfile/vmSymbols.hpp

Intrinsics

Page 93: Java micro optimizations 2017

int[] ar = new int[] {1, -32, 1, 1, 5, 6, 7};return IntStream.of(ar).anyMatch(i -> i == val)

What is wrong here?

Page 94: Java micro optimizations 2017

int[] ar = new int[] {1, -32, 1, 1, 5, 6, 7};return IntStream.of(ar).anyMatch(i -> i == val)

Lambda/Stream cost

Page 95: Java micro optimizations 2017

naive thrpt 228002 ops/slambda thrpt 22983 ops/s

Lambda/Stream cost

~10x

Page 96: Java micro optimizations 2017

boolean contains(int[] ar, int value) { for (int arVal : ar) { if (arVal == value) { return true; } } return false; }

Solution

Page 97: Java micro optimizations 2017

E get(int index) { if (index >= size) { throw new IndexOutOfBoundsException(); } return (E) elementData[index];}

What is wrong here?

Page 98: Java micro optimizations 2017

E get(int index) { if (index >= size) { throw new IndexOutOfBoundsException(); } return (E) elementData[index];}

Bounds-checking

Page 99: Java micro optimizations 2017

noCheck thrpt 388332 ops/sboundCheck thrpt 341232 ops/s

Bounds-checking

+12%

Page 100: Java micro optimizations 2017

E get(int index) { return (E) elementData[index];}

Solution

Page 101: Java micro optimizations 2017

● Know your data (jmap, logs, db)● Know your flows (metrics, jstack)● Don’t rely on JIT● Don’t trust java :)● Always stress test your code● 1% vs 99%

Summary

Page 102: Java micro optimizations 2017

https://github.com/blynkkk/blynk-server

Page 103: Java micro optimizations 2017

https://github.com/doom369/java-microbenchmarks