Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Performance on Android

Kotlin Performance on Android

Александр Смирнов, Splyt

Сейчас сложно удивить фразой «мы не побоялись затащить в production новомодный Kotlin» и это здорово ведь количество приложений использующих Kotlin в качестве основного ЯП только растёт. По всегда полезно узнать про цену использования абстракции в виде Kotlin в Runtime, обсудим варианты, как улучшить картину мира. Смотреть будем с точки зрения производительности, синхронно углубляясь в особенности Android, а также подумаем, как можно использовать получившийся байткод.

MOSDROID

May 21, 2017
Tweet

More Decks by MOSDROID

Other Decks in Programming

Transcript

  1. ЩА ПОМЕРЯЕМ fun measure() : Long {
 val startTime =

    System.nanoTime()
 work()
 return System.nanoTime() - startTime
 } WRONG WAY
  2. 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
  3. 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
  4. 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)
  5. 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
  6. 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(); }
 }
  7. 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(); } }
  8. 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
  9. REAL STATIC !? object A {
 fun test() = 53


    } L3 LINENUMBER 23 L3 GETSTATIC kotlin/A.INSTANCE : Lkotlin/A; INVOKEVIRTUAL kotlin/A.test ()I POP
  10. NULLABILITY fun test(first: String, second: String?) : String {
 second

    ?: return first
 
 return "$first $second"
 }
  11. 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;
 }
  12. 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);
  13. AUTOBOXING val a: String? = null
 var b = a?.isBlank()

    == true if (a != null && a.isBlank()) true else false
  14. 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
  15. 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)
 }
  16. RANGES inline fun <reified T> List<T>.foreach(crossinline action: (T) -> Unit):

    Unit {
 val size = size 
 for(i in 0..size) {
 work(i * 2)
 } 
 }
  17. 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;
 }
 }
  18. 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
  19. BENCHMARKS 1.2 ГГЦ 4 ЯДРА – 1 ГБ ОЗУ –

    4.4.2 – 480X854 HUAWEI Y54 I-U02 ~25% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  20. BENCHMARKS 2.1 ГГЦ + 1.5 ГГЦ – 3 ГБ ОЗУ

    – 7.0 – 2560X1440 SAMSUNG GALAXY S6 ~40% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  21. BENCHMARKS 2.15 ГГЦ + 1.6 ГГЦ– 4 ГБ ОЗУ –

    7.1.2 – 1920X1080 GOOGLE PIXEL БЕЗ ИЗМЕНЕНИЙ ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  22. BENCHMARKS 1.3 ГГЦ– 1 ГБ ОЗУ – 4.4.2 – 960X540

    ONN K7 SUNNY ~20% ПРОФИТА ПОДРОБНОСТИ В СТАТЬЕ, ПОМНИМ ПРО МАГИЮ
 ПРОЦЕНТОВ НА МАЛЕНЬКИХ ЧИСЛАХ
  23. ИТОГО БЫСТРОДЕЙСТВИЕ ВАЖНО ТОЛЬКО НА UI ПОТОКЕ ОЧЕНЬ КРИТИЧНО ТОЛЬКО

    В ONMEASURE - ONLAYOUT - ONDRAW ПРАКТИЧЕСКИ ВСЕГДА МОЖНО НАПИСАТЬ С ИДЕНТИЧНОЙ СКОРОСТЬЮ РАБОТЫ ПРЕЖДЕВРЕМЕННЫЕ ОПТИМИЗАЦИИ ЗЛО