SlideShare a Scribd company logo
1 of 116
Download to read offline
Scala performance
под капотом
Гребенников Роман
sociohub.ru
@public_void_grv
2015, jpoint
Intro: Зачем это всё?
● В Scala много “необычного”:
○ FP, pattern matching, лень, коллекции.
○ Всё такое удобное и классное.
Intro: Зачем это всё?
● В Scala много “необычного”:
○ FP, pattern matching, лень, коллекции.
○ Всё такое удобное и классное.
Intro: горячее необычное
● ФП в горячих участках кода:
○ улучшает читабельность;
○ добавляет непредсказуемости.
Intro: горячее необычное
● ФП в горячих участках кода:
○ улучшает читабельность;
○ добавляет непредсказуемости.
● ФП-абстракции могут:
○ неявно создавать новые объекты;
○ делать дополнительные вычисления;
○ портить жизнь JVM JIT.
О чем доклад?
● Основы:
○ Измерять производительность сложно.
○ Что делает HotSpot и scalac под капотом.
○ JMH и как (не)правильно измерять.
● Scala в реальной жизни:
○ pattern matching;
○ рекурсия;
○ коллекции и лямбды.
● Как с этим жить.
А что тут сложного?
А что тут сложного?
● Что тут не так?
○ цикл может быть удалён оптимизирован целиком;
○ doSomeStuff может быть скомпилирован позже
1000-й итерации;
○ весь цикл может занять меньше 1мс;
○ и еще миллион проблем.
А что тут сложного?
● Что тут не так?
○ цикл может быть удалён оптимизирован целиком;
○ doSomeStuff может быть скомпилирован позже
1000-й итерации;
○ весь цикл может занять меньше 1мс;
○ и еще миллион проблем.
● Причина: HotSpot умнее тебя
Внутри HotSpot
Foo.scala
Foo.java
scalac
javac
Внутри HotSpot
Foo.scala
Foo.java
scalac
javac
МАГИЯ
Внутри HotSpot
Foo.scala
Foo.java
scalac
javac
МАГИЯ
Внутри HotSpot
● С0 -> C1 -> C2:
○ агрессивнее оптимизации ~ быстрее код;
○ больше времени на разогрев.
● Множество опасностей на каждом шагу
Foo.scala
Foo.java
scalac
javac
JVM/HotSpot
Bytecode
CPU
С0: интерпретация
С1
С2
маш.
код
Почему не надо делать это руками
● Надо обойти много ловушек JVM, чтобы
получить достоверный результат:
○ корректно измерять время;
○ бороться с dead-code-elimination;
○ избегать constant-folding;
○ победить loop-unrolling;
○ и еще два десятка особенностей.
Почему не надо делать это руками
● Надо обойти много ловушек JVM, чтобы
получить достоверный результат:
○ корректно измерять время;
○ бороться с dead-code-elimination;
○ избегать constant-folding;
○ победить loop-unrolling;
○ и еще два десятка особенностей.
● Не надо изобретать велосипед
JMH[1]
Harness для написания и запуска (микро)
бенчмарков:
● набор аннотаций;
● консольный интерфейс для запуска;
[1]: http://openjdk.java.net/projects/code-tools/jmh/
JMH и Scala
● плагин sbt-jmh [1]
● запускается из консоли sbt
[1]: https://github.com/ktoso/sbt-jmh
Если хочется подробностей
● Алексей Шипилёв:
○ Performance Methodology How-To[1];
○ Java Benchmarking, Timestamping Failures[2];
○ Nanotrusting the Nanotime[3].
● JMH code samples[4]
[1]: http://shipilev.net/#performance-101
[2]: http://shipilev.net/#benchmarking
[3]: http://shipilev.net/blog/2014/nanotrusting-nanotime/
Pattern matching
● сопоставление с образцом:
○ switch-case на стероидах;
○ экстракторы, regex, списки и т.п.
○ гордость ФП-фанатов, повод унижать Java.
Pattern matching
● сопоставление с образцом:
○ switch-case на стероидах;
○ экстракторы, regex, списки и т.п.
○ гордость ФП-фанатов, повод унижать Java.
● условия для тестовой задачи:
○ часто используется в реальной жизни;
○ простота и минимум дополнительной логики.
Выбор из нескольких вариантов
● базовый трейт и несколько наследников
● задача:
○ def select(value:Base)
○ какой дочерний тип реализует Base?
Есть две реализации...
● с матчингом и цепочкой сравнений:
Результаты
● результаты выглядят одинаково
● но одинаково ли то, что внутри?
Заглянем в машинный код
Это даст нам все ответы. Наверное.
Заглянем в машинный код
Это даст нам все ответы. Наверное.
Проблема:
● я не соображаю в x86_64 ассемблере;
● но я неплохо делаю вид, что соображаю[1].
[1]: Wikibooks: x86 Disassembly, http://en.wikibooks.org/wiki/X86_Disassembly
JMH perfasm profiler
● -XX:+PrintAssembly - заставить JVM
плеваться ассемблерными листингами:
○ много буков, тяжело читать.
JMH perfasm profiler
● -XX:+PrintAssembly - заставить JVM
плеваться ассемблерными листингами:
○ много буков, тяжело читать.
● perf, CPU performance counters[1]:
○ интерфейс ядра Linux;
○ надо следить за изменениями.
JMH perfasm profiler
● -XX:+PrintAssembly - заставить JVM
плеваться ассемблерными листингами:
○ много буков, тяжело читать.
● perf, CPU performance counters[1]:
○ интерфейс ядра Linux;
○ надо следить за изменениями.
● perfasm парсит выхлоп JVM+perf, а потом:
○ выделяет горячие регионы кода;
○ сводит их в единый человекочитаемый вид.
[1]: https://perf.wiki.kernel.org/index.php/Main_Page
def measurePatternMatch(v:Baz)
def measurePatternMatch(v:Baz)
def measurePatternMatch(v:Baz)
● указатель на структуру-описание класса
● по смещению 8 лежит classword
def measurePatternMatch(v:Baz)
● cmp: Compare, сравнить два значения.
● je: Jump-if-equals, перейти, если равны.
def measurePatternMatch(v:Baz)
● jne: Jump-if-Not-Equals
● учтён профиль выполнения кода
def measurePatternMatch(v:Baz)
● готовим аргументы для вызова consume()
● проглатываем результат $0x3
def measurePatternMatch(v:Baz)
def measureIf(v:Baz)
If-else vs match
Идентичный машинный код:
Option[T]
● типизированная замена null-check
● Option[T]:
○ Some(x:T) - если что-то есть,
○ None - если ничего нет.
● scalac не даст сконвертить Option[T] => T
● явная обработка None
Option[T] pattern matching
Option[T]: Результаты
● Задача и результаты весьма близки
● Но null-check чуть быстрее
● Как же так?
* - Scala 2.11.6, JMH 1.8, Oracle JDK 1.8_40
Внутри measureIfNull
Загрузить nullableString в %r11d
Если в %r11d лежит 0, то прыгнуть куда-то вдаль
Вернуть и проглотить nullableString
Внутри measureIfNull
Загрузить nullableString в %r11d
Если в %r11d лежит 0, то прыгнуть куда-то вдаль
Вернуть и проглотить nullableString
● HotSpot учел профиль выполнения:
○ nullableString почти никогда не бывает null;
○ обработка null вынесена за пределы горячего кода.
Внутри measureMatchOption
Проверка someString.getClass == classOf[Some]
Загрузить структуру, описывающую Some в %r10
Вынуть из нее поле x в регистр %r11d
Проверка x.getClass == classOf[String]
Вернуть и проглотить результат
В чём разница?
● measureIfNull - 1 проверка типа
● measureMatchOption - 2 проверки:
○ проклятие генериков и type erasure;
В чём разница?
● measureIfNull - 1 проверка типа
● measureMatchOption - 2 проверки:
○ проклятие генериков и type erasure;
○ JVM не может сразу определить тип объекта и
тип его содержимого;
○ Option[String] == Option[Int] == Option[Object]
○ приходится сравнивать дважды.
Выводы о pattern matching
● if-elseif-elseif-else ~= PM
○ PM значительно нагляднее if-else
● матчинг по генерикам: особенности JVM
○ одно лишнее сравнение - справедливая цена за
удобство;
○ JVM неплохо оптимизирует hot-code-path для PM.
Оптимизация хвостовой рекурсии
● трюк компилятора, замена рекурсивного
вызова функции на цикл
● работает не для любого рекурсивного
вызова, а только для хвостового
Оптимизация хвостовой рекурсии
● трюк компилятора, замена рекурсивного
вызова функции на цикл;
● работает не для любого рекурсивного
вызова, а только для хвостового;
● есть в scalac, нет в javac;
● предмет для гордости
у любителей ФП.
Тестовая задача с TCO
● вычисление N-го числа Фибоначчи:
● 0, 1, 1, 2, 3, 5, 8, 13, 21,…
Тестовая задача с TCO
● вычисление N-го числа Фибоначчи:
● 0, 1, 1, 2, 3, 5, 8, 13, 21,…
● Scala + TCO:
Числа Фибоначчи и Java
● Обычная рекурсия:
● Цикл:
Фибоначчи, результаты
● 10, 100, 1000-е число:
Фибоначчи, результаты
● 10, 100, 1000-е число:
● scala.measureTCO ~= java.measureLoop
● рекурсия без TCO ожидаемо медленнее
● но почему именно так?
Заглянем в байткод
● JVM байткод довольно прост, правда!
● javap - утилита из OpenJDK для
вивисекции class-файлов
● Есть встроенный “дизассемблер”:
○ $ javap -c JavaFibonacci.class
○ подходит и для работы с Scala
○ интегрирована в Scala REPL, :javap
Java recursion под капотом
Байткод для java-recursion:
Scala TCO под капотом
Байткод для @tailrec функции:
Scala TCO под капотом
Байткод для @tailrec функции:
● разница только в вызове invokespecial
● почему же она такая большая?
Вызов метода в JVM
● Несколько способов вызова методов:
○ invokevirtual - виртуальный метод;
○ invokestatic - статический метод;
○ invokespecial - private/instance метод.
Вызов метода в JVM
● Несколько способов вызова методов:
○ invokevirtual - виртуальный метод;
○ invokestatic - статический метод;
○ invokespecial - private/instance метод.
● Вызов метода:
○ передача контроля VM;
○ …
○ тыр-пыр, туда-сюда;
○ ...
○ передача контроля коду.
На дне
переход прямо в кишки JVM
Goto vs invokespecial
● x86 goto - переход по адресу
● invokespecial - инструкция для вызова
приватных/инстанс методов класса[1]:
○ выяснить, что требуемый метод - private;
○ найти код нужного метода по имени;
○ кинуть exception, если не нашлось ничего;
○ создать новый фрейм;
○ передать аргументы.
[1]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12
Goto vs invokespecial
● x86 goto - переход по адресу
● invokespecial - инструкция для вызова
приватных/инстанс методов класса:
○ выяснить, что требуемый метод - private;
○ найти код нужного метода по имени;
○ кинуть exception, если не нашлось ничего;
○ создать новый фрейм;
○ передать аргументы.
● JVM отлично оптимизирует вызов метода
● Но goto все равно быстрее
Инлайнинг
● -XX:+PrintInlining
Инлайнинг
● -XX:+PrintInlining
● всё может быть ещё сложнее:
○ JVM встроит рекурсивную функцию саму в себя;
○ через несколько итераций ему надоест;
○ и он начнет дергать invokespecial.
Подробнее о JVM и Scala рекурсии
● A.Shipilev, “Scala vs Java: divided we fail”[1]
● A.Shipilev, “The black magic of Java method
dispatch”[2]
● Oracle HotSpotInternals wiki[3]
[1]: http://shipilev.net/blog/2014/java-scala-divided-we-fail, 2014
[2]: http://shipilev.net/blog/2015/black-magic-method-dispatch, 2015
[3]: https://wiki.openjdk.java.net/dashboard.action
Выводы о рекурсии
● TCO работает так же быстро, как и цикл.
● Не бойтесь рекурсии, она классная.
● Необходим навык, чтобы:
○ перестать мыслить циклами;
○ перестать вычислять числа Фибоначчи;
○ начать писать понятные рекурсивные алгоритмы.
Scala collections
● Простой способ делать сложные вещи:
○ map, flatMap, fold, etc...
○ в Java7 подобные вещи надо делать руками
○ Java8 streams: шаг в сторону ФП
Scala collections
● Простой способ делать сложные вещи:
○ map, flatMap, fold, etc...
○ в Java7 подобные вещи надо делать руками
○ Java8 streams: шаг в сторону ФП
● За всё хорошее приходится платить:
○ есть ли накладные расходы?
○ почему они именно такие?
○ как с этим дальше жить.
Выбор задачи
● java.util.ArrayList[1] vs scala.Array*:
○ алгоритмически схожие;
○ одинаковые показатели алгоритмической
эффективности по памяти и объему вычислений.
[1]: http://www.programcreek.com/2014/09/top-100-classes-used-in-java-projects/
*: scala.ArrayOps
Выбор задачи
● java.util.ArrayList[1] vs scala.Array*:
○ алгоритмически схожие;
○ одинаковые показатели алгоритмической
эффективности по памяти и объему вычислений.
● Задача должна быть показательной:
○ использовать коллекции;
○ минимум накладных вычислений вне работы с
коллекциями.
[1]: http://www.programcreek.com/2014/09/top-100-classes-used-in-java-projects/
*: scala.ArrayOps
Сумма квадратов
● Дано: коллекция целых чисел
● Рассчитать сумму квадратов[1]
[1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
Сумма квадратов
● Дано: коллекция целых чисел
● Рассчитать сумму квадратов[1]
Проблемы:
● синтетический тест, далёк от жизни
● расходы на boxing/unboxing
примитивов
[1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
Сумма квадратов
● Дано: коллекция целых чисел
● Рассчитать сумму квадратов[1]
Проблемы:
● синтетический тест, далёк от жизни
● расходы на boxing/unboxing
примитивов
[1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
Scala way
● ФП и императивный вариант
Java way
● императивная классика:
Результаты
Результаты
1. тормоза на больших массивах
2. ФП vs императив
2
1
Императив vs императив
JavaSquares.imp ScalaSquares.imp
1: Императив vs императив
JavaSquares.imp ScalaSquares.imp
● imul и add иногда независимы по данным
● можно не исполнять их последовательно
Out-of-order execution
Так почему же тормозит?
● HotSpot - коллекция эвристиков.
● Эвристики иногда ошибаются,
○ особенно при виде Scala-кода
Так почему же тормозит?
● HotSpot - коллекция эвристиков.
● Эвристики иногда ошибаются,
○ особенно при виде Scala-кода
● немного разный байткод;
● разная размерность массива;
● разный профиль выполнения;
● разные решения по JIT-компиляции.
2: ФП vs императив
● подождите кидаться смотреть (байт)код!
● scalac делает много оптимизаций:
○ инлайнинг лямбд и замыканий;
○ dead code elimination;
○ упрощение box+unbox;
○ вот это всё.
2: ФП vs императив
● подождите кидаться смотреть (байт)код!
● scalac делает много оптимизаций:
○ инлайнинг лямбд и замыканий;
○ dead code elimination;
○ упрощение box+unbox;
○ вот это всё.
● scalac -print выведет непосредственно
всё то, что перегниёт в байткод:
○ всё неявное становится явным;
○ последствия оптимизаций уровня AST.
squaresFold без сахара
squaresFold без сахара
squaresFold без сахара
● явное создание лямбды;
● box/unbox;
● кровь, кишки, специализация.
squaresFold hottest methods
squaresFold hottest methods
● java.lang.Object::<init> ест 17% CPU
● похоже, мы активно плодим объекты:
JMH GC profiler[1]
● обрабатывает GC Notifications[2] через JMX
● почти не влияет на производительность
[1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html
[2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
JMH GC profiler[1]
● обрабатывает GC Notifications[2] через JMX
● почти не влияет на производительность
● результат:
[1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html
[2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
JMH GC profiler[1]
● обрабатывает GC Notifications[2] через JMX
● почти не влияет на производительность
● результат:
полтора гига мусора в секунду?!
[1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html
[2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
Сравнили теплое с мягким
Тесты не идентичны:
примитив
объект
Specialization: тернистый путь
@specialized - оптимизация scalac для
избежания боксинга
Specialization: тернистый путь
@specialized - оптимизация scalac для
избежания боксинга:
● для требуемого примитивного типа
создается своя копия метода:
● хотели как лучше, а вышло как всегда.
Мама, я генерик
● scala.collection.*:
○ не умеют в специализацию;
○ являются генериками, List[T] = List[Object]
○ все методы - тоже генерики,
list.fold(value:T)(...) == list.fold(value:Object)(...)
Мама, я генерик
● scala.collection.*:
○ не умеют в специализацию;
○ являются генериками, List[T] = List[Object]
○ все методы - тоже генерики,
list.fold(value:T)(...) == list.fold(value:Object)(...)
Вывод: без боксинга никак нельзя
(но в java N+2, возможно, будет можно[1])
[1]: Project Valhalla: http://cr.openjdk.java.net/~briangoetz/valhalla/specialization.html
Коллекции и примитивные типы
● хочешь быстрой работы с примитивами?
○ опасайся боксинга;
○ или перепиши все на С/С++.
Коллекции и примитивные типы
● хочешь быстрой работы с примитивами?
○ опасайся боксинга;
○ или перепиши все на С/С++.
● Коллекции в скале пока дженерики:
○ даже scala.Array этим иногда страдает[1];
○ боксинг и тормоза во все поля;
○ в далеких планах минибоксинг @miniboxed[2].
[1]: http://www.scala-lang.org/api/current/index.html#scala.Array
[2]: http://scala-miniboxing.org
Коллекции и примитивные типы
● хочешь быстрой работы с примитивами?
○ опасайся боксинга;
○ или перепиши все на С/С++.
● Коллекции в скале пока дженерики:
○ даже scala.Array этим иногда страдает[1];
○ боксинг и тормоза во все поля;
○ в далеких планах минибоксинг @miniboxed[2].
● Сторонние коллекции:
○ Debox: @specialized Buffer, Map, Set[3].
[1]: http://www.scala-lang.org/api/current/index.html#scala.Array
[2]: http://scala-miniboxing.org
[3]: https://github.com/non/debox
О коллекциях
● Если очень хочется, то жить можно
● Есть коллекции для примитивов: debox
● Можно написать свою: @specialized
О коллекциях
● Если очень хочется, то жить можно
● Есть коллекции для примитивов: debox
● Можно написать свою: @specialized
В итоге
● Scala медленная:
○ легко написать тормозной, но красивый код;
○ коллекции не дружат с примитивами;
○ scalac может нагенерить сумрачный байткод.
В итоге
● Scala медленная:
○ легко написать тормозной, но красивый код;
○ коллекции не дружат с примитивами;
○ scalac может нагенерить сумрачный байткод.
● Scala быстрая:
○ при понимании внутренностей, красивый код
может работать со скоростью Java;
○ коллекции можно подружить с примитивами при
помощи синей изоленты (а в Java - нельзя);
○ JVM из сумрачного байткода может сделать
эффективный машинный код.
Личный опыт
● Пишем на скале два года и ничё.
● Баланс быстроты кода и разработки:
○ пишешь быстро - работает медленно;
○ пишешь медленно - работает быстро.
● Все бенчмарки доступны на гитхабе:
○ https://github.com/shuttie/scala-perf-talk
Вопросы?
Коллекции и объекты
● найти сумму длин всех строк
● java.util.ArrayList vs scala.Array
Scala collections
Страх и ненависть в scala.Array
● scala.Array + ФП-примочки:
○ Array + ArrayOps
○ WrappedArray
○ ArraySeq
○ ArrayBuffer
Как жить с примитивными типами
Debox сильно упрощает жизнь:
● хитрый, канонический и наивный пример
Примитивы, результат тестов
Примитивы, результат тестов
● debox ~= while-цикл, yay!
● baseline ~3 нс*
● обработка 1 элемента - ~0.225 baseline.
* - 2.7GHz Core i5-3337U
Немного x86_64 assembly
Немного x86_64 assembly
● почему все инструкции повторяются?
● loop-unrolling и out-of-order execution!
Scala performance под капотом

More Related Content

What's hot

JVM: краткий курс общей анатомии
JVM: краткий курс общей анатомииJVM: краткий курс общей анатомии
JVM: краткий курс общей анатомииNikita Lipsky
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)Alexander Gornik
 
Поддержка Java 8 в Excelsior JET
Поддержка Java 8 в Excelsior JET Поддержка Java 8 в Excelsior JET
Поддержка Java 8 в Excelsior JET Nikita Lipsky
 
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionJVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionNikita Lipsky
 
CodeFest 2012. Аксёнов А. — Как мы разрабатываем Sphinx
CodeFest 2012. Аксёнов А. — Как мы разрабатываем SphinxCodeFest 2012. Аксёнов А. — Как мы разрабатываем Sphinx
CodeFest 2012. Аксёнов А. — Как мы разрабатываем SphinxCodeFest
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines Sergey Zubkov
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаSergey Platonov
 
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решения
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решенияДмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решения
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решенияFProg
 
Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)Ontico
 
Expert Java Day: Java concurrency
Expert Java Day: Java concurrencyExpert Java Day: Java concurrency
Expert Java Day: Java concurrencyPavel Titkov
 
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest
 
Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Nikita Lipsky
 
Секреты сборки мусора в Java
Секреты сборки мусора в JavaСекреты сборки мусора в Java
Секреты сборки мусора в Javaaragozin
 
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...corehard_by
 
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012Vladimir Ivanov
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокAndrey Karpov
 
Tech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyRegn
 

What's hot (20)

Garbage collection in V8 VM
Garbage collection in V8 VMGarbage collection in V8 VM
Garbage collection in V8 VM
 
JVM: краткий курс общей анатомии
JVM: краткий курс общей анатомииJVM: краткий курс общей анатомии
JVM: краткий курс общей анатомии
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
 
Поддержка Java 8 в Excelsior JET
Поддержка Java 8 в Excelsior JET Поддержка Java 8 в Excelsior JET
Поддержка Java 8 в Excelsior JET
 
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference EditionJVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
JVM: краткий курс общей анатомии, JPoint 2016 Conference Edition
 
CodeFest 2012. Аксёнов А. — Как мы разрабатываем Sphinx
CodeFest 2012. Аксёнов А. — Как мы разрабатываем SphinxCodeFest 2012. Аксёнов А. — Как мы разрабатываем Sphinx
CodeFest 2012. Аксёнов А. — Как мы разрабатываем Sphinx
 
C++ Core Guidelines
C++ Core Guidelines C++ Core Guidelines
C++ Core Guidelines
 
Андрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кодаАндрей Карпов, Приватные байки от разработчиков анализатора кода
Андрей Карпов, Приватные байки от разработчиков анализатора кода
 
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решения
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решенияДмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решения
Дмитрий Грошев, Фёдор Гоголев. Erlang и Haskell в production: проблемы и решения
 
Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)Алексей Рагозин (Deutsche Bank)
Алексей Рагозин (Deutsche Bank)
 
Expert Java Day: Java concurrency
Expert Java Day: Java concurrencyExpert Java Day: Java concurrency
Expert Java Day: Java concurrency
 
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
CodeFest 2012. Липский Н. — JIT vs. AOT. Единство и борьба динамического и ст...
 
TeaVM: dead code elimination and devirtualization
TeaVM: dead code elimination and devirtualizationTeaVM: dead code elimination and devirtualization
TeaVM: dead code elimination and devirtualization
 
Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?Верификация Java байткода: когда, как, а может отключить?
Верификация Java байткода: когда, как, а может отключить?
 
Секреты сборки мусора в Java
Секреты сборки мусора в JavaСекреты сборки мусора в Java
Секреты сборки мусора в Java
 
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
C++ CoreHard Autumn 2018. Что не умеет оптимизировать компилятор - Александр ...
 
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012
"G1 GC и Обзор сборки мусора в HotSpot JVM" @ JUG SPb, 31-05-2012
 
Статический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибокСтатический анализ кода: борьба с удорожанием ошибок
Статический анализ кода: борьба с удорожанием ошибок
 
Tech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция JavaTech Talks @NSU: AOT-компиляция Java
Tech Talks @NSU: AOT-компиляция Java
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на Groovy
 

Viewers also liked

Введение в Akka
Введение в AkkaВведение в Akka
Введение в AkkaZheka Kozlov
 
Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Alexander Podkhalyuzin
 
Backend: Пишем на Scala для браузера
Backend: Пишем на Scala для браузераBackend: Пишем на Scala для браузера
Backend: Пишем на Scala для браузераCodeFest
 
Under the hood of scala implicits (Scala eXchange 2014)
Under the hood of scala implicits (Scala eXchange 2014)Under the hood of scala implicits (Scala eXchange 2014)
Under the hood of scala implicits (Scala eXchange 2014)Alexander Podkhalyuzin
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013ScalaNsk
 
Distributed erlang
Distributed erlangDistributed erlang
Distributed erlangYuri Zhloba
 
Самурайский путь молодого Scala-программиста
Самурайский путь молодого Scala-программистаСамурайский путь молодого Scala-программиста
Самурайский путь молодого Scala-программистаSergey Lobin
 
Переход на Scala: босиком по граблям
Переход на Scala: босиком по граблямПереход на Scala: босиком по граблям
Переход на Scala: босиком по граблямSveta Bozhko
 

Viewers also liked (20)

Введение в Akka
Введение в AkkaВведение в Akka
Введение в Akka
 
Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)Under the hood of scala implicits (kl10tch 10.03.2015)
Under the hood of scala implicits (kl10tch 10.03.2015)
 
Backend: Пишем на Scala для браузера
Backend: Пишем на Scala для браузераBackend: Пишем на Scala для браузера
Backend: Пишем на Scala для браузера
 
Scala #5
Scala #5Scala #5
Scala #5
 
Scala training
Scala trainingScala training
Scala training
 
Scala lecture #4
Scala lecture #4Scala lecture #4
Scala lecture #4
 
Under the hood of scala implicits (Scala eXchange 2014)
Under the hood of scala implicits (Scala eXchange 2014)Under the hood of scala implicits (Scala eXchange 2014)
Under the hood of scala implicits (Scala eXchange 2014)
 
Scala #4
Scala #4Scala #4
Scala #4
 
Scala plugin for IntelliJ IDEA
Scala plugin for IntelliJ IDEAScala plugin for IntelliJ IDEA
Scala plugin for IntelliJ IDEA
 
Scala для всех (РИФ 2015)
Scala для всех (РИФ 2015)Scala для всех (РИФ 2015)
Scala для всех (РИФ 2015)
 
Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013Павел Павлов - Scala для профессионалов - Joker 2013
Павел Павлов - Scala для профессионалов - Joker 2013
 
Scala #3
Scala #3Scala #3
Scala #3
 
Erlang
ErlangErlang
Erlang
 
Feature suggester
Feature suggesterFeature suggester
Feature suggester
 
Scala #2
Scala #2Scala #2
Scala #2
 
Lec 2
Lec 2Lec 2
Lec 2
 
Scala magic
Scala magicScala magic
Scala magic
 
Distributed erlang
Distributed erlangDistributed erlang
Distributed erlang
 
Самурайский путь молодого Scala-программиста
Самурайский путь молодого Scala-программистаСамурайский путь молодого Scala-программиста
Самурайский путь молодого Scala-программиста
 
Переход на Scala: босиком по граблям
Переход на Scala: босиком по граблямПереход на Scala: босиком по граблям
Переход на Scala: босиком по граблям
 

Similar to Scala performance под капотом

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Platonov Sergey
 
How to cook a blockchain and not get burned
How to cook a blockchain and not get burned How to cook a blockchain and not get burned
How to cook a blockchain and not get burned Alexander Syrotenko
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
доклад про Llvm
доклад про Llvmдоклад про Llvm
доклад про LlvmVadim Evard
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекPython Meetup
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1Eduard Antsupov
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#Andrey Karpov
 
Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Alexander Syrotenko
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Кирилл Толкачёв
 
C++ в играх, больших и не очень
C++ в играх, больших и не оченьC++ в играх, больших и не очень
C++ в играх, больших и не оченьcorehard_by
 
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"Yandex
 
Java Ahead-Of-Time compilation
Java Ahead-Of-Time compilationJava Ahead-Of-Time compilation
Java Ahead-Of-Time compilationNikita Lipsky
 
Как сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееКак сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееRoman Dvornov
 
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014it-people
 
От Make к Ansible
От Make к AnsibleОт Make к Ansible
От Make к AnsibleIvan Grishaev
 
Opensource на .NET
Opensource на .NETOpensource на .NET
Opensource на .NETlugnsk
 
Алексей Федоров
Алексей ФедоровАлексей Федоров
Алексей ФедоровCodeFest
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиAndrey Karpov
 
Zero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeZero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeYehor Herasymchuk
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Ontico
 

Similar to Scala performance под капотом (20)

Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
Евгений Рыжков, Андрей Карпов Как потратить 10 лет на разработку анализатора ...
 
How to cook a blockchain and not get burned
How to cook a blockchain and not get burned How to cook a blockchain and not get burned
How to cook a blockchain and not get burned
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
доклад про Llvm
доклад про Llvmдоклад про Llvm
доклад про Llvm
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
 
Lift, play, akka, rails part1
Lift, play, akka, rails part1Lift, play, akka, rails part1
Lift, play, akka, rails part1
 
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
PVS-Studio. Статический анализатор кода. Windows/Linux, C/C++/C#
 
Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?Multithreading in JS. Myth or reality?
Multithreading in JS. Myth or reality?
 
Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016Эволюционный дизайн. Joker Students Day 2016
Эволюционный дизайн. Joker Students Day 2016
 
C++ в играх, больших и не очень
C++ в играх, больших и не оченьC++ в играх, больших и не очень
C++ в играх, больших и не очень
 
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
Владимир Алаев "Разработка на Node.js: инструменты, библиотеки, сервисы"
 
Java Ahead-Of-Time compilation
Java Ahead-Of-Time compilationJava Ahead-Of-Time compilation
Java Ahead-Of-Time compilation
 
Как сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрееКак сделать ваш JavaScript быстрее
Как сделать ваш JavaScript быстрее
 
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014
Я. Садовская "Управление конфигурациями и тестовой средой", DUMP-2014
 
От Make к Ansible
От Make к AnsibleОт Make к Ansible
От Make к Ansible
 
Opensource на .NET
Opensource на .NETOpensource на .NET
Opensource на .NET
 
Алексей Федоров
Алексей ФедоровАлексей Федоров
Алексей Федоров
 
Что могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщикиЧто могут статические анализаторы, чего не могут программисты и тестировщики
Что могут статические анализаторы, чего не могут программисты и тестировщики
 
Zero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And ForgeZero Downtime PHP Deployment with Envoyer And Forge
Zero Downtime PHP Deployment with Envoyer And Forge
 
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
Как сделать ваш JavaScript быстрее / Роман Дворнов (Авито)
 

Scala performance под капотом

  • 1. Scala performance под капотом Гребенников Роман sociohub.ru @public_void_grv 2015, jpoint
  • 2. Intro: Зачем это всё? ● В Scala много “необычного”: ○ FP, pattern matching, лень, коллекции. ○ Всё такое удобное и классное.
  • 3. Intro: Зачем это всё? ● В Scala много “необычного”: ○ FP, pattern matching, лень, коллекции. ○ Всё такое удобное и классное.
  • 4. Intro: горячее необычное ● ФП в горячих участках кода: ○ улучшает читабельность; ○ добавляет непредсказуемости.
  • 5. Intro: горячее необычное ● ФП в горячих участках кода: ○ улучшает читабельность; ○ добавляет непредсказуемости. ● ФП-абстракции могут: ○ неявно создавать новые объекты; ○ делать дополнительные вычисления; ○ портить жизнь JVM JIT.
  • 6. О чем доклад? ● Основы: ○ Измерять производительность сложно. ○ Что делает HotSpot и scalac под капотом. ○ JMH и как (не)правильно измерять. ● Scala в реальной жизни: ○ pattern matching; ○ рекурсия; ○ коллекции и лямбды. ● Как с этим жить.
  • 7. А что тут сложного?
  • 8. А что тут сложного? ● Что тут не так? ○ цикл может быть удалён оптимизирован целиком; ○ doSomeStuff может быть скомпилирован позже 1000-й итерации; ○ весь цикл может занять меньше 1мс; ○ и еще миллион проблем.
  • 9. А что тут сложного? ● Что тут не так? ○ цикл может быть удалён оптимизирован целиком; ○ doSomeStuff может быть скомпилирован позже 1000-й итерации; ○ весь цикл может занять меньше 1мс; ○ и еще миллион проблем. ● Причина: HotSpot умнее тебя
  • 13. Внутри HotSpot ● С0 -> C1 -> C2: ○ агрессивнее оптимизации ~ быстрее код; ○ больше времени на разогрев. ● Множество опасностей на каждом шагу Foo.scala Foo.java scalac javac JVM/HotSpot Bytecode CPU С0: интерпретация С1 С2 маш. код
  • 14. Почему не надо делать это руками ● Надо обойти много ловушек JVM, чтобы получить достоверный результат: ○ корректно измерять время; ○ бороться с dead-code-elimination; ○ избегать constant-folding; ○ победить loop-unrolling; ○ и еще два десятка особенностей.
  • 15. Почему не надо делать это руками ● Надо обойти много ловушек JVM, чтобы получить достоверный результат: ○ корректно измерять время; ○ бороться с dead-code-elimination; ○ избегать constant-folding; ○ победить loop-unrolling; ○ и еще два десятка особенностей. ● Не надо изобретать велосипед
  • 16. JMH[1] Harness для написания и запуска (микро) бенчмарков: ● набор аннотаций; ● консольный интерфейс для запуска; [1]: http://openjdk.java.net/projects/code-tools/jmh/
  • 17. JMH и Scala ● плагин sbt-jmh [1] ● запускается из консоли sbt [1]: https://github.com/ktoso/sbt-jmh
  • 18. Если хочется подробностей ● Алексей Шипилёв: ○ Performance Methodology How-To[1]; ○ Java Benchmarking, Timestamping Failures[2]; ○ Nanotrusting the Nanotime[3]. ● JMH code samples[4] [1]: http://shipilev.net/#performance-101 [2]: http://shipilev.net/#benchmarking [3]: http://shipilev.net/blog/2014/nanotrusting-nanotime/
  • 19. Pattern matching ● сопоставление с образцом: ○ switch-case на стероидах; ○ экстракторы, regex, списки и т.п. ○ гордость ФП-фанатов, повод унижать Java.
  • 20. Pattern matching ● сопоставление с образцом: ○ switch-case на стероидах; ○ экстракторы, regex, списки и т.п. ○ гордость ФП-фанатов, повод унижать Java. ● условия для тестовой задачи: ○ часто используется в реальной жизни; ○ простота и минимум дополнительной логики.
  • 21. Выбор из нескольких вариантов ● базовый трейт и несколько наследников ● задача: ○ def select(value:Base) ○ какой дочерний тип реализует Base?
  • 22. Есть две реализации... ● с матчингом и цепочкой сравнений:
  • 23. Результаты ● результаты выглядят одинаково ● но одинаково ли то, что внутри?
  • 24. Заглянем в машинный код Это даст нам все ответы. Наверное.
  • 25. Заглянем в машинный код Это даст нам все ответы. Наверное. Проблема: ● я не соображаю в x86_64 ассемблере; ● но я неплохо делаю вид, что соображаю[1]. [1]: Wikibooks: x86 Disassembly, http://en.wikibooks.org/wiki/X86_Disassembly
  • 26. JMH perfasm profiler ● -XX:+PrintAssembly - заставить JVM плеваться ассемблерными листингами: ○ много буков, тяжело читать.
  • 27. JMH perfasm profiler ● -XX:+PrintAssembly - заставить JVM плеваться ассемблерными листингами: ○ много буков, тяжело читать. ● perf, CPU performance counters[1]: ○ интерфейс ядра Linux; ○ надо следить за изменениями.
  • 28. JMH perfasm profiler ● -XX:+PrintAssembly - заставить JVM плеваться ассемблерными листингами: ○ много буков, тяжело читать. ● perf, CPU performance counters[1]: ○ интерфейс ядра Linux; ○ надо следить за изменениями. ● perfasm парсит выхлоп JVM+perf, а потом: ○ выделяет горячие регионы кода; ○ сводит их в единый человекочитаемый вид. [1]: https://perf.wiki.kernel.org/index.php/Main_Page
  • 31. def measurePatternMatch(v:Baz) ● указатель на структуру-описание класса ● по смещению 8 лежит classword
  • 32. def measurePatternMatch(v:Baz) ● cmp: Compare, сравнить два значения. ● je: Jump-if-equals, перейти, если равны.
  • 33. def measurePatternMatch(v:Baz) ● jne: Jump-if-Not-Equals ● учтён профиль выполнения кода
  • 34. def measurePatternMatch(v:Baz) ● готовим аргументы для вызова consume() ● проглатываем результат $0x3
  • 37. If-else vs match Идентичный машинный код:
  • 38. Option[T] ● типизированная замена null-check ● Option[T]: ○ Some(x:T) - если что-то есть, ○ None - если ничего нет. ● scalac не даст сконвертить Option[T] => T ● явная обработка None
  • 40. Option[T]: Результаты ● Задача и результаты весьма близки ● Но null-check чуть быстрее ● Как же так? * - Scala 2.11.6, JMH 1.8, Oracle JDK 1.8_40
  • 41. Внутри measureIfNull Загрузить nullableString в %r11d Если в %r11d лежит 0, то прыгнуть куда-то вдаль Вернуть и проглотить nullableString
  • 42. Внутри measureIfNull Загрузить nullableString в %r11d Если в %r11d лежит 0, то прыгнуть куда-то вдаль Вернуть и проглотить nullableString ● HotSpot учел профиль выполнения: ○ nullableString почти никогда не бывает null; ○ обработка null вынесена за пределы горячего кода.
  • 43. Внутри measureMatchOption Проверка someString.getClass == classOf[Some] Загрузить структуру, описывающую Some в %r10 Вынуть из нее поле x в регистр %r11d Проверка x.getClass == classOf[String] Вернуть и проглотить результат
  • 44. В чём разница? ● measureIfNull - 1 проверка типа ● measureMatchOption - 2 проверки: ○ проклятие генериков и type erasure;
  • 45. В чём разница? ● measureIfNull - 1 проверка типа ● measureMatchOption - 2 проверки: ○ проклятие генериков и type erasure; ○ JVM не может сразу определить тип объекта и тип его содержимого; ○ Option[String] == Option[Int] == Option[Object] ○ приходится сравнивать дважды.
  • 46. Выводы о pattern matching ● if-elseif-elseif-else ~= PM ○ PM значительно нагляднее if-else ● матчинг по генерикам: особенности JVM ○ одно лишнее сравнение - справедливая цена за удобство; ○ JVM неплохо оптимизирует hot-code-path для PM.
  • 47. Оптимизация хвостовой рекурсии ● трюк компилятора, замена рекурсивного вызова функции на цикл ● работает не для любого рекурсивного вызова, а только для хвостового
  • 48. Оптимизация хвостовой рекурсии ● трюк компилятора, замена рекурсивного вызова функции на цикл; ● работает не для любого рекурсивного вызова, а только для хвостового; ● есть в scalac, нет в javac; ● предмет для гордости у любителей ФП.
  • 49. Тестовая задача с TCO ● вычисление N-го числа Фибоначчи: ● 0, 1, 1, 2, 3, 5, 8, 13, 21,…
  • 50. Тестовая задача с TCO ● вычисление N-го числа Фибоначчи: ● 0, 1, 1, 2, 3, 5, 8, 13, 21,… ● Scala + TCO:
  • 51. Числа Фибоначчи и Java ● Обычная рекурсия: ● Цикл:
  • 53. Фибоначчи, результаты ● 10, 100, 1000-е число: ● scala.measureTCO ~= java.measureLoop ● рекурсия без TCO ожидаемо медленнее ● но почему именно так?
  • 54. Заглянем в байткод ● JVM байткод довольно прост, правда! ● javap - утилита из OpenJDK для вивисекции class-файлов ● Есть встроенный “дизассемблер”: ○ $ javap -c JavaFibonacci.class ○ подходит и для работы с Scala ○ интегрирована в Scala REPL, :javap
  • 55. Java recursion под капотом Байткод для java-recursion:
  • 56. Scala TCO под капотом Байткод для @tailrec функции:
  • 57. Scala TCO под капотом Байткод для @tailrec функции: ● разница только в вызове invokespecial ● почему же она такая большая?
  • 58. Вызов метода в JVM ● Несколько способов вызова методов: ○ invokevirtual - виртуальный метод; ○ invokestatic - статический метод; ○ invokespecial - private/instance метод.
  • 59. Вызов метода в JVM ● Несколько способов вызова методов: ○ invokevirtual - виртуальный метод; ○ invokestatic - статический метод; ○ invokespecial - private/instance метод. ● Вызов метода: ○ передача контроля VM; ○ … ○ тыр-пыр, туда-сюда; ○ ... ○ передача контроля коду.
  • 61. Goto vs invokespecial ● x86 goto - переход по адресу ● invokespecial - инструкция для вызова приватных/инстанс методов класса[1]: ○ выяснить, что требуемый метод - private; ○ найти код нужного метода по имени; ○ кинуть exception, если не нашлось ничего; ○ создать новый фрейм; ○ передать аргументы. [1]: http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12
  • 62. Goto vs invokespecial ● x86 goto - переход по адресу ● invokespecial - инструкция для вызова приватных/инстанс методов класса: ○ выяснить, что требуемый метод - private; ○ найти код нужного метода по имени; ○ кинуть exception, если не нашлось ничего; ○ создать новый фрейм; ○ передать аргументы. ● JVM отлично оптимизирует вызов метода ● Но goto все равно быстрее
  • 64. Инлайнинг ● -XX:+PrintInlining ● всё может быть ещё сложнее: ○ JVM встроит рекурсивную функцию саму в себя; ○ через несколько итераций ему надоест; ○ и он начнет дергать invokespecial.
  • 65. Подробнее о JVM и Scala рекурсии ● A.Shipilev, “Scala vs Java: divided we fail”[1] ● A.Shipilev, “The black magic of Java method dispatch”[2] ● Oracle HotSpotInternals wiki[3] [1]: http://shipilev.net/blog/2014/java-scala-divided-we-fail, 2014 [2]: http://shipilev.net/blog/2015/black-magic-method-dispatch, 2015 [3]: https://wiki.openjdk.java.net/dashboard.action
  • 66. Выводы о рекурсии ● TCO работает так же быстро, как и цикл. ● Не бойтесь рекурсии, она классная. ● Необходим навык, чтобы: ○ перестать мыслить циклами; ○ перестать вычислять числа Фибоначчи; ○ начать писать понятные рекурсивные алгоритмы.
  • 67. Scala collections ● Простой способ делать сложные вещи: ○ map, flatMap, fold, etc... ○ в Java7 подобные вещи надо делать руками ○ Java8 streams: шаг в сторону ФП
  • 68. Scala collections ● Простой способ делать сложные вещи: ○ map, flatMap, fold, etc... ○ в Java7 подобные вещи надо делать руками ○ Java8 streams: шаг в сторону ФП ● За всё хорошее приходится платить: ○ есть ли накладные расходы? ○ почему они именно такие? ○ как с этим дальше жить.
  • 69. Выбор задачи ● java.util.ArrayList[1] vs scala.Array*: ○ алгоритмически схожие; ○ одинаковые показатели алгоритмической эффективности по памяти и объему вычислений. [1]: http://www.programcreek.com/2014/09/top-100-classes-used-in-java-projects/ *: scala.ArrayOps
  • 70. Выбор задачи ● java.util.ArrayList[1] vs scala.Array*: ○ алгоритмически схожие; ○ одинаковые показатели алгоритмической эффективности по памяти и объему вычислений. ● Задача должна быть показательной: ○ использовать коллекции; ○ минимум накладных вычислений вне работы с коллекциями. [1]: http://www.programcreek.com/2014/09/top-100-classes-used-in-java-projects/ *: scala.ArrayOps
  • 71. Сумма квадратов ● Дано: коллекция целых чисел ● Рассчитать сумму квадратов[1] [1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
  • 72. Сумма квадратов ● Дано: коллекция целых чисел ● Рассчитать сумму квадратов[1] Проблемы: ● синтетический тест, далёк от жизни ● расходы на boxing/unboxing примитивов [1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
  • 73. Сумма квадратов ● Дано: коллекция целых чисел ● Рассчитать сумму квадратов[1] Проблемы: ● синтетический тест, далёк от жизни ● расходы на boxing/unboxing примитивов [1]: Clash of the lambdas, 2014: http://biboudis.github.io/clashofthelambdas/
  • 74. Scala way ● ФП и императивный вариант
  • 77. Результаты 1. тормоза на больших массивах 2. ФП vs императив 2 1
  • 79. 1: Императив vs императив JavaSquares.imp ScalaSquares.imp ● imul и add иногда независимы по данным ● можно не исполнять их последовательно
  • 81. Так почему же тормозит? ● HotSpot - коллекция эвристиков. ● Эвристики иногда ошибаются, ○ особенно при виде Scala-кода
  • 82. Так почему же тормозит? ● HotSpot - коллекция эвристиков. ● Эвристики иногда ошибаются, ○ особенно при виде Scala-кода ● немного разный байткод; ● разная размерность массива; ● разный профиль выполнения; ● разные решения по JIT-компиляции.
  • 83. 2: ФП vs императив ● подождите кидаться смотреть (байт)код! ● scalac делает много оптимизаций: ○ инлайнинг лямбд и замыканий; ○ dead code elimination; ○ упрощение box+unbox; ○ вот это всё.
  • 84. 2: ФП vs императив ● подождите кидаться смотреть (байт)код! ● scalac делает много оптимизаций: ○ инлайнинг лямбд и замыканий; ○ dead code elimination; ○ упрощение box+unbox; ○ вот это всё. ● scalac -print выведет непосредственно всё то, что перегниёт в байткод: ○ всё неявное становится явным; ○ последствия оптимизаций уровня AST.
  • 87. squaresFold без сахара ● явное создание лямбды; ● box/unbox; ● кровь, кишки, специализация.
  • 89. squaresFold hottest methods ● java.lang.Object::<init> ест 17% CPU ● похоже, мы активно плодим объекты:
  • 90. JMH GC profiler[1] ● обрабатывает GC Notifications[2] через JMX ● почти не влияет на производительность [1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html [2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
  • 91. JMH GC profiler[1] ● обрабатывает GC Notifications[2] через JMX ● почти не влияет на производительность ● результат: [1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html [2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
  • 92. JMH GC profiler[1] ● обрабатывает GC Notifications[2] через JMX ● почти не влияет на производительность ● результат: полтора гига мусора в секунду?! [1] http://mail.openjdk.java.net/pipermail/jmh-dev/2015-April/001785.html [2] https://docs.oracle.com/javase/8/docs/jre/api/management/extension/com/sun/management/GarbageCollectionNotificationInfo.html
  • 93. Сравнили теплое с мягким Тесты не идентичны: примитив объект
  • 94. Specialization: тернистый путь @specialized - оптимизация scalac для избежания боксинга
  • 95. Specialization: тернистый путь @specialized - оптимизация scalac для избежания боксинга: ● для требуемого примитивного типа создается своя копия метода: ● хотели как лучше, а вышло как всегда.
  • 96. Мама, я генерик ● scala.collection.*: ○ не умеют в специализацию; ○ являются генериками, List[T] = List[Object] ○ все методы - тоже генерики, list.fold(value:T)(...) == list.fold(value:Object)(...)
  • 97. Мама, я генерик ● scala.collection.*: ○ не умеют в специализацию; ○ являются генериками, List[T] = List[Object] ○ все методы - тоже генерики, list.fold(value:T)(...) == list.fold(value:Object)(...) Вывод: без боксинга никак нельзя (но в java N+2, возможно, будет можно[1]) [1]: Project Valhalla: http://cr.openjdk.java.net/~briangoetz/valhalla/specialization.html
  • 98. Коллекции и примитивные типы ● хочешь быстрой работы с примитивами? ○ опасайся боксинга; ○ или перепиши все на С/С++.
  • 99. Коллекции и примитивные типы ● хочешь быстрой работы с примитивами? ○ опасайся боксинга; ○ или перепиши все на С/С++. ● Коллекции в скале пока дженерики: ○ даже scala.Array этим иногда страдает[1]; ○ боксинг и тормоза во все поля; ○ в далеких планах минибоксинг @miniboxed[2]. [1]: http://www.scala-lang.org/api/current/index.html#scala.Array [2]: http://scala-miniboxing.org
  • 100. Коллекции и примитивные типы ● хочешь быстрой работы с примитивами? ○ опасайся боксинга; ○ или перепиши все на С/С++. ● Коллекции в скале пока дженерики: ○ даже scala.Array этим иногда страдает[1]; ○ боксинг и тормоза во все поля; ○ в далеких планах минибоксинг @miniboxed[2]. ● Сторонние коллекции: ○ Debox: @specialized Buffer, Map, Set[3]. [1]: http://www.scala-lang.org/api/current/index.html#scala.Array [2]: http://scala-miniboxing.org [3]: https://github.com/non/debox
  • 101. О коллекциях ● Если очень хочется, то жить можно ● Есть коллекции для примитивов: debox ● Можно написать свою: @specialized
  • 102. О коллекциях ● Если очень хочется, то жить можно ● Есть коллекции для примитивов: debox ● Можно написать свою: @specialized
  • 103. В итоге ● Scala медленная: ○ легко написать тормозной, но красивый код; ○ коллекции не дружат с примитивами; ○ scalac может нагенерить сумрачный байткод.
  • 104. В итоге ● Scala медленная: ○ легко написать тормозной, но красивый код; ○ коллекции не дружат с примитивами; ○ scalac может нагенерить сумрачный байткод. ● Scala быстрая: ○ при понимании внутренностей, красивый код может работать со скоростью Java; ○ коллекции можно подружить с примитивами при помощи синей изоленты (а в Java - нельзя); ○ JVM из сумрачного байткода может сделать эффективный машинный код.
  • 105. Личный опыт ● Пишем на скале два года и ничё. ● Баланс быстроты кода и разработки: ○ пишешь быстро - работает медленно; ○ пишешь медленно - работает быстро. ● Все бенчмарки доступны на гитхабе: ○ https://github.com/shuttie/scala-perf-talk
  • 107.
  • 108. Коллекции и объекты ● найти сумму длин всех строк ● java.util.ArrayList vs scala.Array
  • 110. Страх и ненависть в scala.Array ● scala.Array + ФП-примочки: ○ Array + ArrayOps ○ WrappedArray ○ ArraySeq ○ ArrayBuffer
  • 111. Как жить с примитивными типами Debox сильно упрощает жизнь: ● хитрый, канонический и наивный пример
  • 113. Примитивы, результат тестов ● debox ~= while-цикл, yay! ● baseline ~3 нс* ● обработка 1 элемента - ~0.225 baseline. * - 2.7GHz Core i5-3337U
  • 115. Немного x86_64 assembly ● почему все инструкции повторяются? ● loop-unrolling и out-of-order execution!