KOTLIN PERFOMANCE
ON ANDROID
ALEXANDER SMIRNOV
06.06.2017
WHOAMI
ANDROID DEVELOPER SINCE 2012
ANDROID В ЛИЦАХ (YOUTUBE – TELEGRAM)
WORKING IN SPLYT
MOSDROID
QUIZ: KOTLIN VS JAVA!?
1. МЕДЛЕННЕЕ
2. ОДИНАКОВО
3. БЫСТРЕЕ
ВСЁ ПОМЕРЯЕМ
fun measure() : Long {

val startTime = System.nanoTime()

work()

return System.nanoTime() - startTime

}
adb shell dumpsys gfxinfo %package_name%
QUIZ: ГДЕ ПЕРФОМАНС ВАЖЕН?
1. ОДНОЗНАЧНО ВЕЗДЕ
2. UITHREAD
3. CUSTOM VIEW + ANIMATIONS
VIEWS && UI THREAD
KOTLIN STYLE
COLLECTION API
METHOD DEFAULT PARAMETERS
DATA CLASSES
REIFIED TYPES
COROUTINES
class Test {



var a = 5

var b = 6

val c = B()



fun work() {

val d = a + b

val e = c.a + c.b

}

}



class B(@JvmField var a: Int = 5, 

var b: Int = 6)
FIELDS
L0
LINENUMBER 10 L0
ALOAD 0
GETFIELD kotlin/Test.a : I
ALOAD 0
GETFIELD kotlin/Test.b : I
IADD
ISTORE 1
FIELDS var a = 5

var b = 6



val d = a + b
L1
LINENUMBER 11 L1
ALOAD 0
GETFIELD kotlin/Test.c : Lkotlin/B;
GETFIELD kotlin/B.a : I
ALOAD 0
GETFIELD kotlin/Test.c : Lkotlin/B;
INVOKEVIRTUAL kotlin/B.getB ()I
IADD
ISTORE 2
FIELDS val e = c.a + c.b



class B(@JvmField var a: Int = 5, 

var b: Int = 6)
STATIC!?
companion object {

var k = 5



fun work2() : Int = 42

}
NOT STATIC
companion object {

var k = 5



fun work2() : Int = 42
}
val i = k + work2()
L2
LINENUMBER 21 L2
GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion;
INVOKEVIRTUAL kotlin/Test$Companion.getK ()I
GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion;
INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I
IADD
ISTORE 3
NOT STATIC private static int k = 5;

public static final Test.Companion Companion =
new Test.Companion((DefaultConstructorMarker)null);


public static final class Companion {

public final int getK() { return Test.k;}



public final void setK(int var1) {

Test.k = var1;

}



public final int work2() { return 42; }



private Companion() { }



// $FF: synthetic method

public Companion(DefaultConstructorMarker
$constructor_marker) { this(); }

}
NOT STATIC
val i = k + work2()
companion object {
@JvmField

var k = 5

@JvmStatic

fun work2() : Int = 42
}
private static int k = 5;

public static final Test.Companion Companion =
new Test.Companion((DefaultConstructorMarker)null);


public static final class Companion {

@JvmStatic

public final int work2() { return 42; }



private Companion() {}



// $FF: synthetic method

public Companion(DefaultConstructorMarker
$constructor_marker) { this(); }
}
NOT STATIC
val i = k + work2()
companion object {
@JvmField

var k = 5

@JvmStatic

fun work2() : Int = 42
}
L2
LINENUMBER 21 L2
GETSTATIC kotlin/Test.k : I
GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion;
INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I
IADD
ISTORE 3
REAL STATIC !? object A {

fun test() = 53

}
L3
LINENUMBER 23 L3
GETSTATIC kotlin/A.INSTANCE : Lkotlin/A;
INVOKEVIRTUAL kotlin/A.test ()I
POP
STATIC! fun test2() = 99
L4
LINENUMBER 24 L4
INVOKESTATIC kotlin/TestKt.test2 ()I
POP
NULLABILITY
fun test(first: String, second: String?) : String {

second ?: return first



return "$first $second"

}
NULLABILITY
fun test(first: String, second: String?) : String {

second ?: return first



return "$first $second"

}
@NotNull

public final String test(@NotNull String first,
@Nullable String second) {

Intrinsics.checkParameterIsNotNull(first, "first");

return second != null ? (first + " " + second) : first;

}
var a = 5

var b = 6

var bOption : Int? = 6
PRIMITIVES
private int a = 5;

private int b = 6;

@Nullable
private Integer bOption = Integer.valueOf(6);
AUTOBOXING
val a: String? = null

var b = a?.isBlank() == true
AUTOBOXING
val a: String? = null

var b = a?.isBlank() == true
if (a != null && a.isBlank()) true else false
AUTOBOXING
val a: String? = null

var b = a?.isBlank() == true
String a = (String)null;

boolean b = Intrinsics.areEqual(a != null ?
Boolean.valueOf(StringsKt.isBlank((CharSequence)a)) : null,
Boolean.valueOf(true));
if (a != null && a.isBlank()) true else false
LOOPS
list.forEach {

work(it * 2)

}
LOOPS
inline fun <reified T> List<T>.foreach(crossinline action: (T)
-> Unit): Unit {

val size = size

var i = 0


while (i < size) {

action(get(i))

i++

}

} list.foreach {

work(it * 2)

}
RANGES
inline fun <reified T> List<T>.foreach(crossinline action: (T)
-> Unit): Unit {

val size = size


for(i in 0..size) {

work(i * 2)

}


}
INTRINSICS
INTRINSICS
class Test {



fun concat(first: String, second: String) = 

"$first $second"



}
INTRINSICS
public final class Test {

@NotNull

public final String concat(@NotNull String first,

@NotNull String second) {

Intrinsics.checkParameterIsNotNull(first, "first");

Intrinsics.checkParameterIsNotNull(second, "second");

return first + " " + second;

}

}
INTRINSICS
public final class Test {

@NotNull

public final String concat(@NotNull String first, 

@NotNull String second) {

return first + " " + second;

}

}
kotlinc -Xno-call-assertions -Xno-param-assertions Test.kt
REDEX
ИНЛАЙНИТ, НО НЕ ВСЁ
ДЕЛАЕТ ДРУГИЕ ОПТИМИЗАЦИИ – 7% К ВЕСУ APK
РЕШЕНИЕ ОТ FACEBOOK
BENCHMARKS
PARTICLES DRAWABLE
BY YAROSLAV MYTKALYK (DOCTOROR)
4 DIFFERENT PHONES
DUMPSYS GFXINFO + MANY BENCHMARKING
HTTPS://GITHUB.COM/SMRED
0
3,75
7,5
11,25
15
Java Kotlin Kotlin+
Min Median Mean
BENCHMARKS
1.2 ГГЦ – 1 ГБ ОЗУ
4.4.2 – 480X854
HUAWEI Y54 I-U02
BENCHMARKS
1.2 ГГЦ – 1 ГБ ОЗУ
4.4.2 – 480X854
HUAWEI Y54 I-U02
JAVA KOTLIN KOTLIN+
Min 9,82 9,64 9,24
Median 13,667 13,98 13,58
Mean 14,375 14,875 14,524
BENCHMARKS
1.3 ГГЦ – 1 ГБ ОЗУ

4.4.2 – 960X540
ONN K7 SUNNY
JAVA KOTLIN KOTLIN+
Min 9,73 10,01 9,75
Median 13,31 13,58 13,31
Mean 13,549 13,847 13,625
BENCHMARKS
2.1 ГГЦ + 1.5 ГГЦ – 3 ГБ ОЗУ 

7.0 – 2560X1440
SAMSUNG GALAXY S6
JAVA KOTLIN KOTLIN+
Min 13,62 13 13,12
Median 24,155 24,675 23,53
Mean 23,924 25,567 23,753
BENCHMARKS
2.15 ГГЦ + 1.6 ГГЦ– 4 ГБ ОЗУ

7.1.2 – 1920X1080
GOOGLE PIXEL
JAVA KOTLIN KOTLIN+
Min 7,56 7,37 7,3
Median 12,96 12,89 12,9
Mean 13,579 13,624 13,553
ИТОГО
БЫСТРОДЕЙСТВИЕ ВАЖНО ТОЛЬКО НА UI ПОТОКЕ
ОЧЕНЬ КРИТИЧНО ТОЛЬКО В ONMEASURE - ONLAYOUT - ONDRAW
ПРАКТИЧЕСКИ ВСЕГДА МОЖНО НАПИСАТЬ С ИДЕНТИЧНОЙ СКОРОСТЬ
РАБОТЫ
ПРЕЖДЕВРЕМЕННЫЕ ОПТИМИЗАЦИИ ЗЛО
ENJOY
alexander.smirnov@splyt.com
@_smred
@smred

Kotlin Perfomance on Android / Александр Смирнов (Splyt)

  • 1.
  • 2.
    WHOAMI ANDROID DEVELOPER SINCE2012 ANDROID В ЛИЦАХ (YOUTUBE – TELEGRAM) WORKING IN SPLYT MOSDROID
  • 3.
    QUIZ: KOTLIN VSJAVA!? 1. МЕДЛЕННЕЕ 2. ОДИНАКОВО 3. БЫСТРЕЕ
  • 4.
    ВСЁ ПОМЕРЯЕМ fun measure(): Long {
 val startTime = System.nanoTime()
 work()
 return System.nanoTime() - startTime
 } adb shell dumpsys gfxinfo %package_name%
  • 5.
    QUIZ: ГДЕ ПЕРФОМАНСВАЖЕН? 1. ОДНОЗНАЧНО ВЕЗДЕ 2. UITHREAD 3. CUSTOM VIEW + ANIMATIONS
  • 6.
  • 7.
    KOTLIN STYLE COLLECTION API METHODDEFAULT PARAMETERS DATA CLASSES REIFIED TYPES COROUTINES
  • 8.
    class Test {
 
 vara = 5
 var b = 6
 val c = B()
 
 fun work() {
 val d = a + b
 val e = c.a + c.b
 }
 }
 
 class B(@JvmField var a: Int = 5, 
 var b: Int = 6) FIELDS
  • 9.
    L0 LINENUMBER 10 L0 ALOAD0 GETFIELD kotlin/Test.a : I ALOAD 0 GETFIELD kotlin/Test.b : I IADD ISTORE 1 FIELDS var a = 5
 var b = 6
 
 val d = a + b
  • 10.
    L1 LINENUMBER 11 L1 ALOAD0 GETFIELD kotlin/Test.c : Lkotlin/B; GETFIELD kotlin/B.a : I ALOAD 0 GETFIELD kotlin/Test.c : Lkotlin/B; INVOKEVIRTUAL kotlin/B.getB ()I IADD ISTORE 2 FIELDS val e = c.a + c.b
 
 class B(@JvmField var a: Int = 5, 
 var b: Int = 6)
  • 11.
    STATIC!? companion object {
 vark = 5
 
 fun work2() : Int = 42
 }
  • 12.
    NOT STATIC companion object{
 var k = 5
 
 fun work2() : Int = 42 } val i = k + work2() L2 LINENUMBER 21 L2 GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.getK ()I GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I IADD ISTORE 3
  • 13.
    NOT STATIC privatestatic int k = 5;
 public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null); 
 public static final class Companion {
 public final int getK() { return Test.k;}
 
 public final void setK(int var1) {
 Test.k = var1;
 }
 
 public final int work2() { return 42; }
 
 private Companion() { }
 
 // $FF: synthetic method
 public Companion(DefaultConstructorMarker $constructor_marker) { this(); }
 }
  • 14.
    NOT STATIC val i= k + work2() companion object { @JvmField
 var k = 5
 @JvmStatic
 fun work2() : Int = 42 } private static int k = 5;
 public static final Test.Companion Companion = new Test.Companion((DefaultConstructorMarker)null); 
 public static final class Companion {
 @JvmStatic
 public final int work2() { return 42; }
 
 private Companion() {}
 
 // $FF: synthetic method
 public Companion(DefaultConstructorMarker $constructor_marker) { this(); } }
  • 15.
    NOT STATIC val i= k + work2() companion object { @JvmField
 var k = 5
 @JvmStatic
 fun work2() : Int = 42 } L2 LINENUMBER 21 L2 GETSTATIC kotlin/Test.k : I GETSTATIC kotlin/Test.Companion : Lkotlin/Test$Companion; INVOKEVIRTUAL kotlin/Test$Companion.work2 ()I IADD ISTORE 3
  • 16.
    REAL STATIC !?object A {
 fun test() = 53
 } L3 LINENUMBER 23 L3 GETSTATIC kotlin/A.INSTANCE : Lkotlin/A; INVOKEVIRTUAL kotlin/A.test ()I POP
  • 17.
    STATIC! fun test2()= 99 L4 LINENUMBER 24 L4 INVOKESTATIC kotlin/TestKt.test2 ()I POP
  • 18.
    NULLABILITY fun test(first: String,second: String?) : String {
 second ?: return first
 
 return "$first $second"
 }
  • 19.
    NULLABILITY fun test(first: String,second: String?) : String {
 second ?: return first
 
 return "$first $second"
 } @NotNull
 public final String test(@NotNull String first, @Nullable String second) {
 Intrinsics.checkParameterIsNotNull(first, "first");
 return second != null ? (first + " " + second) : first;
 }
  • 20.
    var a =5
 var b = 6
 var bOption : Int? = 6 PRIMITIVES private int a = 5;
 private int b = 6;
 @Nullable private Integer bOption = Integer.valueOf(6);
  • 21.
    AUTOBOXING val a: String?= null
 var b = a?.isBlank() == true
  • 22.
    AUTOBOXING val a: String?= null
 var b = a?.isBlank() == true if (a != null && a.isBlank()) true else false
  • 23.
    AUTOBOXING val a: String?= null
 var b = a?.isBlank() == true String a = (String)null;
 boolean b = Intrinsics.areEqual(a != null ? Boolean.valueOf(StringsKt.isBlank((CharSequence)a)) : null, Boolean.valueOf(true)); if (a != null && a.isBlank()) true else false
  • 24.
  • 25.
    LOOPS inline fun <reifiedT> List<T>.foreach(crossinline action: (T) -> Unit): Unit {
 val size = size
 var i = 0 
 while (i < size) {
 action(get(i))
 i++
 }
 } list.foreach {
 work(it * 2)
 }
  • 26.
    RANGES inline fun <reifiedT> List<T>.foreach(crossinline action: (T) -> Unit): Unit {
 val size = size 
 for(i in 0..size) {
 work(i * 2)
 } 
 }
  • 27.
  • 28.
    INTRINSICS class Test {
 
 funconcat(first: String, second: String) = 
 "$first $second"
 
 }
  • 29.
    INTRINSICS public final classTest {
 @NotNull
 public final String concat(@NotNull String first,
 @NotNull String second) {
 Intrinsics.checkParameterIsNotNull(first, "first");
 Intrinsics.checkParameterIsNotNull(second, "second");
 return first + " " + second;
 }
 }
  • 30.
    INTRINSICS public final classTest {
 @NotNull
 public final String concat(@NotNull String first, 
 @NotNull String second) {
 return first + " " + second;
 }
 } kotlinc -Xno-call-assertions -Xno-param-assertions Test.kt
  • 31.
    REDEX ИНЛАЙНИТ, НО НЕВСЁ ДЕЛАЕТ ДРУГИЕ ОПТИМИЗАЦИИ – 7% К ВЕСУ APK РЕШЕНИЕ ОТ FACEBOOK
  • 32.
    BENCHMARKS PARTICLES DRAWABLE BY YAROSLAVMYTKALYK (DOCTOROR) 4 DIFFERENT PHONES DUMPSYS GFXINFO + MANY BENCHMARKING HTTPS://GITHUB.COM/SMRED
  • 33.
    0 3,75 7,5 11,25 15 Java Kotlin Kotlin+ MinMedian Mean BENCHMARKS 1.2 ГГЦ – 1 ГБ ОЗУ 4.4.2 – 480X854 HUAWEI Y54 I-U02
  • 34.
    BENCHMARKS 1.2 ГГЦ –1 ГБ ОЗУ 4.4.2 – 480X854 HUAWEI Y54 I-U02 JAVA KOTLIN KOTLIN+ Min 9,82 9,64 9,24 Median 13,667 13,98 13,58 Mean 14,375 14,875 14,524
  • 35.
    BENCHMARKS 1.3 ГГЦ –1 ГБ ОЗУ
 4.4.2 – 960X540 ONN K7 SUNNY JAVA KOTLIN KOTLIN+ Min 9,73 10,01 9,75 Median 13,31 13,58 13,31 Mean 13,549 13,847 13,625
  • 36.
    BENCHMARKS 2.1 ГГЦ +1.5 ГГЦ – 3 ГБ ОЗУ 
 7.0 – 2560X1440 SAMSUNG GALAXY S6 JAVA KOTLIN KOTLIN+ Min 13,62 13 13,12 Median 24,155 24,675 23,53 Mean 23,924 25,567 23,753
  • 37.
    BENCHMARKS 2.15 ГГЦ +1.6 ГГЦ– 4 ГБ ОЗУ
 7.1.2 – 1920X1080 GOOGLE PIXEL JAVA KOTLIN KOTLIN+ Min 7,56 7,37 7,3 Median 12,96 12,89 12,9 Mean 13,579 13,624 13,553
  • 38.
    ИТОГО БЫСТРОДЕЙСТВИЕ ВАЖНО ТОЛЬКОНА UI ПОТОКЕ ОЧЕНЬ КРИТИЧНО ТОЛЬКО В ONMEASURE - ONLAYOUT - ONDRAW ПРАКТИЧЕСКИ ВСЕГДА МОЖНО НАПИСАТЬ С ИДЕНТИЧНОЙ СКОРОСТЬ РАБОТЫ ПРЕЖДЕВРЕМЕННЫЕ ОПТИМИЗАЦИИ ЗЛО
  • 39.