Java Benchmarking
как два таймстампа прочитать!
Алексей Шипилёв
aleksey.shipilev@oracle.com, @shipilev
The following is intended to outline our general product direction. It
is intended for information purposes only, and may ...
Введение
Slide 3/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
Введение: В качестве разогрева
«Сколько стоит создание одного String?»
long startTime = System.nanoTime ();
for (int i = 0...
Теория
Slide 5/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
Теория: Зачем люди делают бенчмарки?
1. Ради холивора: мой язык лучше твоего языка
2. Ради маркетинга: проверить, что мы в...
Теория: Ради холивора
Прекрасный пример – Computer Language Benchmarks Game:1
Многие реализации вообще не сравнимы: e.g. A...
Теория: Ради маркетинга
Прекрасный пример – SPEC benchmarks:
Референсные наборы бенчмарок, одинаково хороших/плохих
для бо...
Теория: Ради инжиниринга
«If you can’t measure it, you can’t optimize it»
Нужны лабораторные условия, в которых зафиксиров...
Теория: Ради науки
«Science Town PD: To Explain and Predict»
Извлечь из результатов тестов правдоподобную модель
производи...
Теория: Что интересно нам?
1. Ради холивора: мой язык лучше твоего языка
2. Ради маркетинга: проверить, что мы вкладываемс...
Теория: Бенчмарки – это эксперименты
Хорошие эксперименты отвечают на несколько групп вопросов:
1. Что измеряем: какие мет...
Что измеряем: Метрики
Две главные группы метрик:
Bandwidth (𝜆)
Сравнительно легко
измерить
Легко вводится в steady
state
С...
Что измеряем: путаем bandwidth и latency
Отличия в нагрузке:
– 𝜆 обычно измеряют под пиковой нагрузкой
– 𝜏 как правило изм...
Что измеряем: 𝜆 и 𝜏 – братья навек
Slide 15/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
Как измеряем: типы бенчмарок
Два главных подхода:
Time-based
Исполняем постоянное
время
Делаем операции одну за
одной
В из...
Как измеряем: Transients
Запомните
Мы имеем дело с динамическими системами.
«Прогрев» – это выжидание характерного времени...
Как измеряем: Transients
Запомните
Мы имеем дело с динамическими системами.
«Прогрев» – это выжидание характерного времени...
Как измеряем: Transients
Запомните
Мы имеем дело с динамическими системами.
«Прогрев» – это выжидание характерного времени...
Как измеряем: Steady state
Система пришла в устойчивое состояние (steady state), когда
все её переходные процессы устканил...
Как измеряем: Иногда steady state нет!
public class FibonacciGen {
BigInteger n1 = ONE; BigInteger n2 = ZERO;
public BigIn...
Как проверяем: Инженерный подход
Главный инженерный вопрос
Почему мой бенчмарк не может работать быстрее?
Ответ определяет...
Как проверяем: Научный подход
Главный научный вопрос
Как бенчмарк реагирует на изменение внешних условий?
Отвечаем, наскол...
Практика
Slide 22/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
Практика: JMH
У нас тоже есть очень хороший харнесс:
http://openjdk.java.net/projects/code-tools/jmh/
JMH is Serious Busin...
Практика: JMH
У нас тоже есть очень хороший харнесс:
http://openjdk.java.net/projects/code-tools/jmh/
JMH is Serious Busin...
Практика: Цель
Цель всего этого мероприятия в том,
чтобы вас как следует напугать
и заставить бросить:
(тупо) писать обёрт...
System: Задачка (A)
Давайте запустим простенький бенчмарк.
Система говорит, что у неё 4 CPU.
Threads Ops/nsec Scale
1 3.06...
System: Задачка (A)
Давайте запустим простенький бенчмарк.
Система говорит, что у неё 4 CPU.
Threads Ops/nsec Scale
1 3.06...
System: Задачка (A)
Давайте запустим простенький бенчмарк.
Система говорит, что у неё 4 CPU.
Threads Ops/nsec Scale
1 3.06...
System: Power management
Запускаем простой бенчмарк,
+ и зажимаем частоту CPU в 2 GHz:
Threads Ops/nsec Scale
1 1.97 ± 0.0...
System: Power management
Многие подсистемы балансируют power-vs-performance
(Ex.: cpufreq, SpeedStep, Cool&Quiet, TurboBoo...
System: OS Schedulers
Шедулеры OS балансируют affinity-vs-power
(Ex.: Solaris schedulers, Linux power-efficient taskqueues...
System: Time Sharing
Системы разделяемого времени балансируют
утилизацию.
(Ex.: тысячи их)
Засада: старт/останов потоков н...
System: Time Sharing, #2
JMH – synchronize iterations:
Slide 30/67. Copyright c○ 2013, Oracle and/or its affiliates. All r...
System: Time Sharing, Quiz (B)
public void measure () {
long startTime = System.nanoTime ();
while (! isDone) {
work ();
}...
System: Time Sharing, Задачка (B)
«Is there a problem, officer?»
public void measure () {
long realTime = 0;
while (! isDo...
System: Time Sharing, Задачка (B)
Измеряем количество вызовов в секунду, да?
0
200
400
600
0 10 20 30
# Threads
throughput...
System: Time Sharing, Задачка (B)
public void measure () {
long startTime = System.nanoTime ();
long realTime = 0;
while (...
System: Time Sharing
Разделение времени даёт иллюзию параллельной
работы нескольких потоков
Засада: эта иллюзия не всегда ...
VM: Задачка (C)
@GenerateMicroBenchmark
public void baseline () {
}
0.5 ± 0.1 ns
@GenerateMicroBenchmark
public void measu...
VM: Dead-code elimination
Оптимизаторы очень хорошо удаляют код без
наблюдаемых эффектов.
Засада: может снести часть бенчм...
VM: Задачка (D)
@GenerateMicroBenchmark
public void baseline () {
}
0.5 ± 0.1 ns
@GenerateMicroBenchmark
public double mea...
VM: Constant folding, etc.
Оптимизаторы довольно хороши в предвычислениях.
Засада: может предоптимизировать часть бенчмарк...
VM: CSE
JMH ломает спекуляцию о чтениях в разных вызовах @GMB
метода
double x;
@GenerateMicroBenchmark
double doWork () {
...
VM: DCE, CSE... одно и то же!
Потеря непредсказуемости что источника, что результата теряет
и часть бенчмарка. Тихо и неза...
VM: DCE, CSE... одно и то же!
Потеря непредсказуемости что источника, что результата теряет
и часть бенчмарка. Тихо и неза...
VM: DCE, CSE... одно и то же!
Потеря непредсказуемости что источника, что результата теряет
и часть бенчмарка. Тихо и неза...
VM: Задачка (E)
// changing N, will performance differ?
static int N = 100;
@GenerateMicroBenchmark
public int test () { r...
VM: Задачка (E), #2
N ns/call ns/add
1 1.5 ± 0.1 1.5 ± 0.1
10 2.0 ± 0.1 0.1 ± 0.01
100 2.7 ± 0.2 0.05 ± 0.02
1000 68.8 ± 0...
VM: Задачка (E), #2
N ns/call ns/add
1 1.5 ± 0.1 1.5 ± 0.1
10 2.0 ± 0.1 0.1 ± 0.01
100 2.7 ± 0.2 0.05 ± 0.02
1000 68.8 ± 0...
VM: Loop unrolling
Раскрутка циклов сильно расширяет диапазон
оптимизаций.
Засада: положим, одна итерация цикла занимает 𝑀...
VM: Задачка (F)
interface M {
void inc ();
}
abstract class AM implements M {
int c;
void inc() {
c++;
}
}
class M1 extend...
VM: Задачка (F), #2
M m1 = new M1();
M m2 = new M2();
@GenerateMicroBenchmark
public void testM1 () { test(m1); }
@Generat...
VM: Задачка (F), #3
test ns/op
testM1 4.6 ± 0.1
testM2 36.0 ± 0.4
Slide 47/67. Copyright c○ 2013, Oracle and/or its affili...
VM: Задачка (F), #3
test ns/op
testM1 4.6 ± 0.1
testM2 36.0 ± 0.4
repeat testM1 35.8 ± 0.4
Slide 47/67. Copyright c○ 2013,...
VM: Задачка (F), #3
test ns/op
testM1 4.6 ± 0.1
testM2 36.0 ± 0.4
repeat testM1 35.8 ± 0.4
forked testM1 4.5 ± 0.1
forked ...
VM: Profile feedback
Динамические оптимизации
могут использовать информацию времени исполнения
(Ex.: call profile, type pr...
VM: Задачка (G)
Slide 49/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
VM: Задачка (G), #2
Slide 50/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
VM: Run-to-run variance
Многие масштабируемые алгоритмы не
детерминированы!
(Ex.: memory allocators, profiler counters, no...
VM: Inlining budgets
Подстановка (inlining) – это убер-оптимизация
Засада: Всё заинлайнить нельзя ⇒ приходится думать о
то...
VM: сгенерированный JMH код
JIT-компиляция и подстановки начинаются с этого метода:
public void testLong_loop
(Loop loop ,...
CPU: Задачка (H)
@State
public class TreeMapBench {
Map <String , String > map = new TreeMap <>();
@Setup
public void setu...
CPU: Задачка (H), #2
@GenerateMicroBenchmark
public void test(BlackHole bh) {
for(String key : map.keySet ()) {
String val...
CPU: Задачка (H), #2
@GenerateMicroBenchmark
public void test(BlackHole bh) {
for(String key : map.keySet ()) {
String val...
CPU: Задачка (H), #2
@GenerateMicroBenchmark
public void test(BlackHole bh) {
for(String key : map.keySet ()) {
String val...
CPU: Задачка (H), #2
@GenerateMicroBenchmark
public void test(BlackHole bh) {
for(String key : map.keySet ()) {
String val...
CPU: Cache capacity
Основная память слишком далека.
Давайте кешировать всё прямо в проце!
Засада: Производительность замет...
CPU: Задачка (I)
Насколько хорошо скалируется этот код?
@State(Scope.Benchmark) class Shared {
final int[] c = new int [64...
CPU: Задачка (I), #2
Threads Average ns/call Hit
1 2.0 ± 0.1
2 18.5 ± 2.4 9x
4 32.9 ± 6.2 16x
8 85.4 ± 13.4 42x
16 208.9 ±...
CPU: Bulk method transfers
Система следит за когерентностью памяти по
кусочкам. Характерный размер кусочка: 32, 64, 128
ба...
CPU: Задачка (J)2
Exhibit B. Exhibit P.
int sum = 0;
for (int x : a) {
if (x < 0) {
sum -= x;
} else {
sum += x;
}
}
retur...
CPU: Задачка (J)
E. Branched E. Predicated
L0: mov 0xc(%ecx ,%ebp ,4) ,% ebx
test %ebx,%ebx
jl L1
add %ebx ,% eax
jmp L2
L...
CPU: Задачка (J)
Regular Pattern = (+, –)*
NHM Bldzr C-A9 SNB
branch_regular 0.9 0.8 5.0 0.5
branch_shuffled 6.2 2.8 9.4 1...
CPU: Branch Prediction
Out-of-Order процессоры очень много спекулируют.
Большую часть времени (99%+) делают это
корректно!...
Выводы
Slide 64/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
Выводы: Benchmarking is Serious Business
Огромное поле для ошибок.
Написание тестов требует экспертизы
Написание фреймворк...
Выводы: инструменты
1. Мозг
– Плагин «данунеможетбыть» для перепроверок фактов
– Плагин «щапридумаем» для построения гипот...
Выводы: прочие инструменты
1. Фреймворки
– JMH: http://openjdk.java.net/projects/code-tools/jmh/
2. Профилировщики
– Visua...
Upcoming SlideShare
Loading in …5
×

CodeFest 2014. Шипилёв А. — Java Benchmarking: как два таймстампа записать!

1,238 views
1,178 views

Published on

Published in: Internet
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,238
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

CodeFest 2014. Шипилёв А. — Java Benchmarking: как два таймстампа записать!

  1. 1. Java Benchmarking как два таймстампа прочитать! Алексей Шипилёв aleksey.shipilev@oracle.com, @shipilev
  2. 2. The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle. Slide 2/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  3. 3. Введение Slide 3/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  4. 4. Введение: В качестве разогрева «Сколько стоит создание одного String?» long startTime = System.nanoTime (); for (int i = 0; i < 1000; i++) { String s = new String(""); } long stopTime = System.nanoTime (); System.out.println("Time:" + (stopTime - startTime )); Slide 4/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  5. 5. Теория Slide 5/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  6. 6. Теория: Зачем люди делают бенчмарки? 1. Ради холивора: мой язык лучше твоего языка 2. Ради маркетинга: проверить, что мы вкладываемся в конкретные критерии 3. Ради инжиниринга: изолировать и зафиксировать перформансный феномен, чтобы была референсная точка для улучшения 4. Ради науки: понять, какой моделью описывается система, и на основании этой модели предсказать будущее поведение Slide 6/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  7. 7. Теория: Ради холивора Прекрасный пример – Computer Language Benchmarks Game:1 Многие реализации вообще не сравнимы: e.g. AOT vs. JIT Измеряют непонятно что: e.g. pidigits измеряет скорость интерфейса до GMP Куча дисклеймеров про то, что в реальной жизни всё может быть по-другому: и тогда этот проект нужен только ради лулзов Любят его потому, что CLBG даёт числа, которыми можно размахивать в холиворах 1 http://benchmarksgame.alioth.debian.org/ Slide 7/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  8. 8. Теория: Ради маркетинга Прекрасный пример – SPEC benchmarks: Референсные наборы бенчмарок, одинаково хороших/плохих для большинства вендоров Позволяют иметь референсные точки, против которых можно выставлять критерии успешности продукта, писать в рекламе и т.п. Ну и что, что они не всегда репрезентативны – главное, что они «золотые» Slide 8/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  9. 9. Теория: Ради инжиниринга «If you can’t measure it, you can’t optimize it» Нужны лабораторные условия, в которых зафиксировано конкретное состояние системы, чтобы можно было проверять внесённые изменения Обычно фокусируются на конкретных местах продукта, имеют бОльшую разрешающую способность, чем маркетинговые бенчи Размеры и охват этих бенчмарков зависит от укуренности инженеров Slide 9/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  10. 10. Теория: Ради науки «Science Town PD: To Explain and Predict» Извлечь из результатов тестов правдоподобную модель производительности Из модели получить предсказания о будущем поведении, проверить эти предсказания, спокойно вздохнуть и деплойнуть в прод Самая трудоёмкая, и самая надёжная цель бенчмаркинга Slide 10/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  11. 11. Теория: Что интересно нам? 1. Ради холивора: мой язык лучше твоего языка 2. Ради маркетинга: проверить, что мы вкладываемся в конкретные критерии 3. Ради инжиниринга: изолировать и зафиксировать перформансный феномен, чтобы была референсная точка для улучшения 4. Ради науки: понять, какой моделью описывается система, и на основании этой модели предсказать будущее поведение Slide 11/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  12. 12. Теория: Бенчмарки – это эксперименты Хорошие эксперименты отвечают на несколько групп вопросов: 1. Что измеряем: какие метрики используем? Что эти метрики нам говорят? 2. Как измеряем: какими способами мы измеряем метрики? какая точность у этих способов? какие подводные камни? 3. Как проверяем: как поверяем наши инструменты? как узнаём, что результатам можно доверять? Slide 12/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  13. 13. Что измеряем: Метрики Две главные группы метрик: Bandwidth (𝜆) Сравнительно легко измерить Легко вводится в steady state Скрывает большие задержки Упускает active-idle Latency (𝜏) Трудно измерить корректно Средняя latency как правило бессмыслена Нужно считать квантили Семплы меньше 1мкс получить не практично Slide 13/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  14. 14. Что измеряем: путаем bandwidth и latency Отличия в нагрузке: – 𝜆 обычно измеряют под пиковой нагрузкой – 𝜏 как правило измеряют под регулируемой нагрузкой – Нагрузка – это новая степень свободы! Отличия в подходах к измерению: – Средняя задержка – бессмысленная метрика, ибо 𝜏 𝑎𝑣𝑔 = 1 𝜆 – Нужно мерить каждое событие, и считать квантили! – События короче 1 мкс? Мухаха. Slide 14/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  15. 15. Что измеряем: 𝜆 и 𝜏 – братья навек Slide 15/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  16. 16. Как измеряем: типы бенчмарок Два главных подхода: Time-based Исполняем постоянное время Делаем операции одну за одной В измерение умещаем порядочное количество операций Fixed work Исполняем постоянное количество операций Чаще всего одну операцию Здорово экономит время! Slide 16/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  17. 17. Как измеряем: Transients Запомните Мы имеем дело с динамическими системами. «Прогрев» – это выжидание характерного времени переходного процесса. У нас полно переходных процессов. Slide 17/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  18. 18. Как измеряем: Transients Запомните Мы имеем дело с динамическими системами. «Прогрев» – это выжидание характерного времени переходного процесса. У нас полно переходных процессов. Компиляция кода – не единственный переходный процесс! Slide 17/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  19. 19. Как измеряем: Transients Запомните Мы имеем дело с динамическими системами. «Прогрев» – это выжидание характерного времени переходного процесса. У нас полно переходных процессов. Компиляция кода – не единственный переходный процесс! «Мудрость»: «Cледите за PrintCompilation». WTF? Slide 17/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  20. 20. Как измеряем: Steady state Система пришла в устойчивое состояние (steady state), когда все её переходные процессы устканились Любое изменение выбивает её из steady state Slide 18/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  21. 21. Как измеряем: Иногда steady state нет! public class FibonacciGen { BigInteger n1 = ONE; BigInteger n2 = ZERO; public BigInteger next () { BigInteger cur = n1.add(n2); n2 = n1; n1 = cur; return cur; } } Каждый вызов next() всё медленней и медленней Имеет смысл измерять первые N операций – а там transients! Slide 19/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  22. 22. Как проверяем: Инженерный подход Главный инженерный вопрос Почему мой бенчмарк не может работать быстрее? Ответ определяет качество эксперимента: 1. В какие ограничения упёрлись? 2. Работает та часть кода, которую мы «исследуем»? 3. Что сделать, чтобы исправить бенчмарк? Slide 20/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  23. 23. Как проверяем: Научный подход Главный научный вопрос Как бенчмарк реагирует на изменение внешних условий? Отвечаем, насколько актуальная модель разнится с ментальной: 1. Проверка на дурака: имеют ли смысл эти результаты? 2. Негативный контроль: меняется ли результат от варирования переменной 𝑋𝑖, хотя не должен? 3. Позитивный контроль: не меняется ли результат от варирования переменной 𝑌𝑖, хотя должен? Slide 21/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  24. 24. Практика Slide 22/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  25. 25. Практика: JMH У нас тоже есть очень хороший харнесс: http://openjdk.java.net/projects/code-tools/jmh/ JMH is Serious Business: – Он учитывает тонну VM-ных эффектов – Мы его периодически допиливаем, когда меняется VM – Мы его периодически фиксим, как растёт наша экспертиза – Всякий внешний бенч валидируется переписыванием под JMH Slide 23/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  26. 26. Практика: JMH У нас тоже есть очень хороший харнесс: http://openjdk.java.net/projects/code-tools/jmh/ JMH is Serious Business: – Он учитывает тонну VM-ных эффектов – Мы его периодически допиливаем, когда меняется VM – Мы его периодически фиксим, как растёт наша экспертиза – Всякий внешний бенч валидируется переписыванием под JMH Мы вынули столько неочевидных граблей из JMH, что не верим ни одному известному харнессу. Slide 23/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  27. 27. Практика: Цель Цель всего этого мероприятия в том, чтобы вас как следует напугать и заставить бросить: (тупо) писать обёртки для бенчмарок (тупо) доверять обёрткам для бенчмаркок (тупо) доверять бенчмаркам Slide 24/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  28. 28. System: Задачка (A) Давайте запустим простенький бенчмарк. Система говорит, что у неё 4 CPU. Threads Ops/nsec Scale 1 3.06 ± 0.10 2 5.72 ± 0.10 1.87 ± 0.03 4 5.87 ± 0.02 1.91 ± 0.03 Slide 25/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  29. 29. System: Задачка (A) Давайте запустим простенький бенчмарк. Система говорит, что у неё 4 CPU. Threads Ops/nsec Scale 1 3.06 ± 0.10 2 5.72 ± 0.10 1.87 ± 0.03 4 5.87 ± 0.02 1.91 ± 0.03 Вопрос 1: Почему переход 2 → 4 потока такой хилый? Slide 25/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  30. 30. System: Задачка (A) Давайте запустим простенький бенчмарк. Система говорит, что у неё 4 CPU. Threads Ops/nsec Scale 1 3.06 ± 0.10 2 5.72 ± 0.10 1.87 ± 0.03 4 5.87 ± 0.02 1.91 ± 0.03 Вопрос 1: Почему переход 2 → 4 потока такой хилый? Вопрос 2: Почему переход 1 → 2 потока всего 1.87x? Slide 25/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  31. 31. System: Power management Запускаем простой бенчмарк, + и зажимаем частоту CPU в 2 GHz: Threads Ops/nsec Scale 1 1.97 ± 0.02 2 3.94 ± 0.05 2.00 ± 0.02 4 4.03 ± 0.04 2.04 ± 0.02 Slide 26/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  32. 32. System: Power management Многие подсистемы балансируют power-vs-performance (Ex.: cpufreq, SpeedStep, Cool&Quiet, TurboBoost) Засада: ломает гомогенность времени Костыль: выключить PM, зажать частоту CPU JMH: работаем дольше, не паркуем потоки Slide 27/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  33. 33. System: OS Schedulers Шедулеры OS балансируют affinity-vs-power (Ex.: Solaris schedulers, Linux power-efficient taskqueues) Засада: ломает иллюзию симметричности CPU Костыль: зажать политики шедулинга JMH: работаем дольше, не паркуем потоки Slide 28/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  34. 34. System: Time Sharing Системы разделяемого времени балансируют утилизацию. (Ex.: тысячи их) Засада: старт/останов потоков не мгновенный, время работы потоков не детерминировано, загрузка во времени неоднородна Костыль: удостовериться, что все потоки начали исполнять работу JMH: «synchronize iterations» Slide 29/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  35. 35. System: Time Sharing, #2 JMH – synchronize iterations: Slide 30/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  36. 36. System: Time Sharing, Quiz (B) public void measure () { long startTime = System.nanoTime (); while (! isDone) { work (); } println(System.nanoTime () - startTime ); } Slide 31/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  37. 37. System: Time Sharing, Задачка (B) «Is there a problem, officer?» public void measure () { long realTime = 0; while (! isDone) { setup (); // skip this long time = System.nanoTime (); work (); realTime += (System.nanoTime () - time ); } println(realTime ); } Slide 32/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  38. 38. System: Time Sharing, Задачка (B) Измеряем количество вызовов в секунду, да? 0 200 400 600 0 10 20 30 # Threads throughput,ops/us Timing the entire loop Timing the sum[iterations] ...а оно растёт за количество CPU – WTF?! Slide 33/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  39. 39. System: Time Sharing, Задачка (B) public void measure () { long startTime = System.nanoTime (); long realTime = 0; while (! isDone) { setup (); // skip this long time = System.nanoTime (); work (); realTime += (System.nanoTime () - time ); ...WHOOPS, WE DE-SCHEDULE HERE... } println(realTime ); println(System.nanoTime () - startTime ); } Slide 34/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  40. 40. System: Time Sharing Разделение времени даёт иллюзию параллельной работы нескольких потоков Засада: эта иллюзия не всегда выполняется для производительности! Костыль: никогда не перегружать систему! JMH: большой красный флаг на въезде в страну Slide 35/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  41. 41. VM: Задачка (C) @GenerateMicroBenchmark public void baseline () { } 0.5 ± 0.1 ns @GenerateMicroBenchmark public void measureWrong () { Math.log(x); } 0.5 ± 0.1 ns @GenerateMicroBenchmark public double measureRight () { return Math.log(x); } 34.0 ± 1.0 ns Slide 36/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  42. 42. VM: Dead-code elimination Оптимизаторы очень хорошо удаляют код без наблюдаемых эффектов. Засада: может снести часть бенчмарка вдрабадан Костыль: наводим эффекты на результаты (суммируем, складываем, печатаем, и т.п.) JMH: поддержка в API Slide 37/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  43. 43. VM: Задачка (D) @GenerateMicroBenchmark public void baseline () { } 0.5 ± 0.1 ns @GenerateMicroBenchmark public double measureWrong () { return Math.log (42); } 1.0 ± 0.1 ns private double x = 42; @GenerateMicroBenchmark public double measureRight () { return Math.log(x); } 34.0 ± 1.0 ns Slide 38/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  44. 44. VM: Constant folding, etc. Оптимизаторы довольно хороши в предвычислениях. Засада: может предоптимизировать часть бенчмарка Костыль: сделать входные данные непредсказуемыми JMH: поддержка в API Slide 39/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  45. 45. VM: CSE JMH ломает спекуляцию о чтениях в разных вызовах @GMB метода double x; @GenerateMicroBenchmark double doWork () { doStuff(x); } volatile boolean done; void doMeasure () { while (! done) { doWork (); } } (Перевод: читаем всё из кучи ⇒ мы спасены!) Slide 40/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  46. 46. VM: DCE, CSE... одно и то же! Потеря непредсказуемости что источника, что результата теряет и часть бенчмарка. Тихо и незаметно. Slide 41/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  47. 47. VM: DCE, CSE... одно и то же! Потеря непредсказуемости что источника, что результата теряет и часть бенчмарка. Тихо и незаметно. Slide 41/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  48. 48. VM: DCE, CSE... одно и то же! Потеря непредсказуемости что источника, что результата теряет и часть бенчмарка. Тихо и незаметно. Slide 41/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  49. 49. VM: Задачка (E) // changing N, will performance differ? static int N = 100; @GenerateMicroBenchmark public int test () { return doWork(N); } int x = 1, y = 2; private int doWork(int reps) { int s = 0; for (int i = 0; i < reps; i++) s += (x + y); return s; } Slide 42/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  50. 50. VM: Задачка (E), #2 N ns/call ns/add 1 1.5 ± 0.1 1.5 ± 0.1 10 2.0 ± 0.1 0.1 ± 0.01 100 2.7 ± 0.2 0.05 ± 0.02 1000 68.8 ± 0.9 0.07 ± 0.01 10000 410.3 ± 2.1 0.04 ± 0.01 100000 3836.1 ± 40.6 0.04 ± 0.01 Slide 43/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  51. 51. VM: Задачка (E), #2 N ns/call ns/add 1 1.5 ± 0.1 1.5 ± 0.1 10 2.0 ± 0.1 0.1 ± 0.01 100 2.7 ± 0.2 0.05 ± 0.02 1000 68.8 ± 0.9 0.07 ± 0.01 10000 410.3 ± 2.1 0.04 ± 0.01 100000 3836.1 ± 40.6 0.04 ± 0.01 Ну и какой строчке верить? 0.04 ns/add ⇒ 25 adds/ns ⇒ GTFO! Slide 43/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  52. 52. VM: Loop unrolling Раскрутка циклов сильно расширяет диапазон оптимизаций. Засада: положим, одна итерация цикла занимает 𝑀 нс. Тогда после раскрутки цикла она эффективно занимает 𝛼𝑀 ns, где 𝛼 ∈ [0; +∞) Костыль: избегаем раскручиваемых циклов, минимизируем эффекты от раскрутки JMH: оказывается, что костыли для CSE/DCE так же ломают эффекты от раскрутки Slide 44/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  53. 53. VM: Задачка (F) interface M { void inc (); } abstract class AM implements M { int c; void inc() { c++; } } class M1 extends AM {} class M2 extends AM {} Slide 45/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  54. 54. VM: Задачка (F), #2 M m1 = new M1(); M m2 = new M2(); @GenerateMicroBenchmark public void testM1 () { test(m1); } @GenerateMicroBenchmark public void testM2 () { test(m2); } void test(M m) { for (int i = 0; i < 100; i++) m.inc (); } Slide 46/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  55. 55. VM: Задачка (F), #3 test ns/op testM1 4.6 ± 0.1 testM2 36.0 ± 0.4 Slide 47/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  56. 56. VM: Задачка (F), #3 test ns/op testM1 4.6 ± 0.1 testM2 36.0 ± 0.4 repeat testM1 35.8 ± 0.4 Slide 47/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  57. 57. VM: Задачка (F), #3 test ns/op testM1 4.6 ± 0.1 testM2 36.0 ± 0.4 repeat testM1 35.8 ± 0.4 forked testM1 4.5 ± 0.1 forked testM2 4.5 ± 0.1 Slide 47/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  58. 58. VM: Profile feedback Динамические оптимизации могут использовать информацию времени исполнения (Ex.: call profile, type profile, CHA info) Засада: Серьёзная разница между режимами «всё в одной VM» и «всё в отдельных VM» Костыль: Прогреваем все бенчмарки вместе, ИЛИ запускаем каждый бенчмарк в отдельной JVM JMH: поддержка bulk warmup; forking Slide 48/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  59. 59. VM: Задачка (G) Slide 49/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  60. 60. VM: Задачка (G), #2 Slide 50/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  61. 61. VM: Run-to-run variance Многие масштабируемые алгоритмы не детерминированы! (Ex.: memory allocators, profiler counters, non-fair locks, concurrent data structures, ...) Засада: (потенциально) (огромная) разница между запусками в одной конфигурации Костыль: протоколирование решений на каждом уровне (e.g. запись решений компилятора), несколько запусков JVM JMH: несколько запусков JVM Slide 51/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  62. 62. VM: Inlining budgets Подстановка (inlining) – это убер-оптимизация Засада: Всё заинлайнить нельзя ⇒ приходится думать о том, что инлайнится, а что нет Костыль: Методы мельче, циклы мельче, подглядываем в -XX:+PrintInlining, используем компиляторные хинты JMH: генерируем горячие циклы в мелкие методы, даём удобный @CompileControl Slide 52/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  63. 63. VM: сгенерированный JMH код JIT-компиляция и подстановки начинаются с этого метода: public void testLong_loop (Loop loop , Result r, MyBenchmark bench) { long ops = 0; r.start = System.nanoTime (); do { bench.testLong (); // @GenerateMicroBenchmark ops ++; } while (! loop.isDone ); r.end = System.nanoTime (); r.ops = ops; } Slide 53/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  64. 64. CPU: Задачка (H) @State public class TreeMapBench { Map <String , String > map = new TreeMap <>(); @Setup public void setup () { populate(map); } @GenerateMicroBenchmark public void test(BlackHole bh) { for(String key : map.keySet ()) { String value = map.get(key); bh.consume(value ); } } }Slide 54/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  65. 65. CPU: Задачка (H), #2 @GenerateMicroBenchmark public void test(BlackHole bh) { for(String key : map.keySet ()) { String value = map.get(key); bh.consume(value ); } } Exclusive Shared Throughput, op/sec 615 ± 12 828 ± 21 Slide 55/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  66. 66. CPU: Задачка (H), #2 @GenerateMicroBenchmark public void test(BlackHole bh) { for(String key : map.keySet ()) { String value = map.get(key); bh.consume(value ); } } Exclusive Shared Throughput, op/sec 615 ± 12 828 ± 21 Threads 4 4 Slide 55/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  67. 67. CPU: Задачка (H), #2 @GenerateMicroBenchmark public void test(BlackHole bh) { for(String key : map.keySet ()) { String value = map.get(key); bh.consume(value ); } } Exclusive Shared Throughput, op/sec 615 ± 12 828 ± 21 Threads 4 4 Maps 4 1 Slide 55/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  68. 68. CPU: Задачка (H), #2 @GenerateMicroBenchmark public void test(BlackHole bh) { for(String key : map.keySet ()) { String value = map.get(key); bh.consume(value ); } } Exclusive Shared Throughput, op/sec 615 ± 12 828 ± 21 Threads 4 4 Maps 4 1 Footprint, Kb 1024 256 Slide 55/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  69. 69. CPU: Cache capacity Основная память слишком далека. Давайте кешировать всё прямо в проце! Засада: Производительность заметно отличается в зависимости от футпринта, путей обхода памяти, да и банальной удачи Костыль: Следим за футпринтом; пробуем разные размеры данных; пробуем разные shared/unshared случаи JMH: @State sharing Slide 56/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  70. 70. CPU: Задачка (I) Насколько хорошо скалируется этот код? @State(Scope.Benchmark) class Shared { final int[] c = new int [64]; } @State(Scope.Thread) class Local { static final AtomicInteger COUNTER = ...; final int index = COUNTER.incrementAndGet (); } @GenerateMicroBenchmark void work(Shared s, Local l) { s.c[l.index ]++; }Slide 57/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  71. 71. CPU: Задачка (I), #2 Threads Average ns/call Hit 1 2.0 ± 0.1 2 18.5 ± 2.4 9x 4 32.9 ± 6.2 16x 8 85.4 ± 13.4 42x 16 208.9 ± 52.1 104x 32 464.2 ± 46.1 232x Почему? Slide 58/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  72. 72. CPU: Bulk method transfers Система следит за когерентностью памяти по кусочкам. Характерный размер кусочка: 32, 64, 128 байта. Засада: модификация рядом лежащих данных разными потоками даётся с трудом (false sharing) Костыль: паддинг, subclass juggling, @Contended JMH: все внутренние структуры отпажжены, @State-объекты паддятся автоматически Slide 59/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  73. 73. CPU: Задачка (J)2 Exhibit B. Exhibit P. int sum = 0; for (int x : a) { if (x < 0) { sum -= x; } else { sum += x; } } return sum; int sum = 0; for (int x : a) { sum += Math.abs(x); } return sum; Которая версия быстрее? 2 Credits: Sergey Kuksenko (@kuksenk0) Slide 60/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  74. 74. CPU: Задачка (J) E. Branched E. Predicated L0: mov 0xc(%ecx ,%ebp ,4) ,% ebx test %ebx,%ebx jl L1 add %ebx ,% eax jmp L2 L1: sub %ebx ,% eax L2: inc %ebp cmp %edx ,% ebp jl L0 L0: mov 0xc(%ecx ,%ebp ,4) ,% ebx mov %ebx ,%esi neg %esi test %ebx ,% ebx cmovl %esi,%ebx add %ebx ,%eax inc %ebp cmp %edx ,%ebp jl Loop Которая версия быстрее? Slide 61/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  75. 75. CPU: Задачка (J) Regular Pattern = (+, –)* NHM Bldzr C-A9 SNB branch_regular 0.9 0.8 5.0 0.5 branch_shuffled 6.2 2.8 9.4 1.0 branch_sorted 0.9 1.0 5.0 0.6 predicated_regular 2.0 1.0 5.3 0.8 predicated_shuffled 2.0 1.0 9.3 0.8 predicated_sorted 2.0 1.0 5.7 0.8 time, nsec/op Slide 62/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  76. 76. CPU: Branch Prediction Out-of-Order процессоры очень много спекулируют. Большую часть времени (99%+) делают это корректно! Засада: Провал в производительности, когда спекуляция проваливается Костыль: Реалистичные данные! Много, много разных наборов данных Slide 63/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  77. 77. Выводы Slide 64/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  78. 78. Выводы: Benchmarking is Serious Business Огромное поле для ошибок. Написание тестов требует экспертизы Написание фреймворков требует ещё большей экспертизы Не верьте красивым репортам, верьте логичным результатам Slide 65/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  79. 79. Выводы: инструменты 1. Мозг – Плагин «данунеможетбыть» для перепроверок фактов – Плагин «щапридумаем» для построения гипотез и экспериментов – Плагин «чётоянепонял» для проверки консистентности гипотез – Плагин «ядурак» для лёгкого отвержения ложных гипотез 2. Руки – Прямые, для постановки аккуратных экспериментов – Сильные, для обработки тонн экспериментальных данных 3. Язык, уши, глаза и прочее I/O – Для обмена результатами и peer review – Для доступа к предыдущим экспериментам Slide 66/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.
  80. 80. Выводы: прочие инструменты 1. Фреймворки – JMH: http://openjdk.java.net/projects/code-tools/jmh/ 2. Профилировщики – VisualVM, JRockit Mission Control, Oracle Studio Performance Analyzer – top, vmstat, mpstat, iostat, dtrace, strace 3. Дизассемблеры – -XX:+PrintAssembly – https: //wikis.sun.com/display/HotSpotInternals/PrintAssembly Slide 67/67. Copyright c○ 2013, Oracle and/or its affiliates. All rights reserved.

×