Теория и практика .net-бенчмаркинга (25.01.2017, Москва)

153
Теория и практика .NET-бенчмаркинга Андрей Акиньшин, JetBrains Москва, 25.01.2017 1/81

Upload: andrey-akinshin

Post on 08-Feb-2017

96 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Теория и практика .NET-бенчмаркинга

Андрей Акиньшин, JetBrains

Москва, 25.01.2017

1/81

Page 2: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1Теория

2/81 1. Теория

Page 3: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1.1Почему мы об этом говорим?

3/81 1.1 Теория: Почему мы об этом говорим?

Page 4: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

StackOverflow

Люди любят бенчмаркать

4/81 1.1 Теория: Почему мы об этом говорим?

Page 5: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

StackOverflowТипичный вопрос

5/81 1.1 Теория: Почему мы об этом говорим?

Page 6: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

HabrahabrНекоторые делают выводы и пишут статьи

6/81 1.1 Теория: Почему мы об этом говорим?

Page 7: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 8: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis

• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 9: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов

• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 10: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности

• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 11: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии

• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 12: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 13: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес

• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 14: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг

• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 15: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Применения бенчмарков

• Performance analysis• Сравнение алгоритмов• Оценка улучшений производительности• Анализ регрессии• . . .

• Научный интерес• Маркетинг• Весёлое времяпрепровождение ,

7/81 1.1 Теория: Почему мы об этом говорим?

Page 16: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1.2Общая методология

8/81 1.2 Теория: Общая методология

Page 17: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 18: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу

2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 19: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики

3 Выбрать инструмент4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 20: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент

4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 21: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент

5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 22: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент5 Получить результаты

6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 23: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 24: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

План performance-работ

1 Поставить задачу2 Выбрать метрики3 Выбрать инструмент4 Провести эксперимент5 Получить результаты6 Выполнить анализ и сделать выводы

Анализ полученных данных — самый важный этап

9/81 1.2 Теория: Общая методология

Page 25: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling• Monitoring• Performance tests• Benchmarking (micro/macro)• . . .

10/81 1.2 Теория: Общая методология

Page 26: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling

• Monitoring• Performance tests• Benchmarking (micro/macro)• . . .

10/81 1.2 Теория: Общая методология

Page 27: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling• Monitoring

• Performance tests• Benchmarking (micro/macro)• . . .

10/81 1.2 Теория: Общая методология

Page 28: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling• Monitoring• Performance tests

• Benchmarking (micro/macro)• . . .

10/81 1.2 Теория: Общая методология

Page 29: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling• Monitoring• Performance tests• Benchmarking (micro/macro)

• . . .

10/81 1.2 Теория: Общая методология

Page 30: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Виды performance-работ

• Profiling• Monitoring• Performance tests• Benchmarking (micro/macro)• . . .

10/81 1.2 Теория: Общая методология

Page 31: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Исходный код

X

Окружение

X

Входные данные

Распределение

11/81 1.2 Теория: Общая методология

Page 32: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Исходный код

X

Окружение

X

Входные данные

Распределение

11/81 1.2 Теория: Общая методология

Page 33: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Исходный код

X

Окружение

X

Входные данные

Распределение

11/81 1.2 Теория: Общая методология

Page 34: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Исходный код

X

Окружение

X

Входные данные

Распределение

11/81 1.2 Теория: Общая методология

Page 35: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Исходный код

X

Окружение

X

Входные данные

Распределение11/81 1.2 Теория: Общая методология

Page 36: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Непонимание проблематики влечёт за собой следующиепроблемы:

• Легко обмануть себя, сделать неправильные выводы,принять вредные бизнес-решения

• Легко пропустить важную конфигурацию, которая испортитжизнь в продакшене

• Легко повестись на кривые бенчмарки или чёрныймаркетинг

12/81 1.2 Теория: Общая методология

Page 37: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Непонимание проблематики влечёт за собой следующиепроблемы:

• Легко обмануть себя, сделать неправильные выводы,принять вредные бизнес-решения

• Легко пропустить важную конфигурацию, которая испортитжизнь в продакшене

• Легко повестись на кривые бенчмарки или чёрныймаркетинг

12/81 1.2 Теория: Общая методология

Page 38: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Непонимание проблематики влечёт за собой следующиепроблемы:

• Легко обмануть себя, сделать неправильные выводы,принять вредные бизнес-решения

• Легко пропустить важную конфигурацию, которая испортитжизнь в продакшене

• Легко повестись на кривые бенчмарки или чёрныймаркетинг

12/81 1.2 Теория: Общая методология

Page 39: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Performance spaces

Непонимание проблематики влечёт за собой следующиепроблемы:

• Легко обмануть себя, сделать неправильные выводы,принять вредные бизнес-решения

• Легко пропустить важную конфигурацию, которая испортитжизнь в продакшене

• Легко повестись на кривые бенчмарки или чёрныймаркетинг

12/81 1.2 Теория: Общая методология

Page 40: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение

C# compiler старый csc / RoslynCLR CLR2 / CLR4 / CoreCLR / MonoOS Windows / Linux / MacOS / FreeBSDJIT LegacyJIT-x86 / LegacyJIT-x64 / RyuJIT-x64GC MS (разные CLR) / Mono (Boehm/Sgen)Toolchain JIT / NGen / .NET NativeHardware тысячи его. . . . . .

И не забываем про версии, много-много версий

13/81 1.2 Теория: Общая методология

Page 41: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение

C# compiler старый csc / RoslynCLR CLR2 / CLR4 / CoreCLR / MonoOS Windows / Linux / MacOS / FreeBSDJIT LegacyJIT-x86 / LegacyJIT-x64 / RyuJIT-x64GC MS (разные CLR) / Mono (Boehm/Sgen)Toolchain JIT / NGen / .NET NativeHardware тысячи его. . . . . .

И не забываем про версии, много-много версий

13/81 1.2 Теория: Общая методология

Page 42: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Интересное про Skylake

Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual:

2.1.3 THE SKYLAKE MICROARCHITECTURE: Cache and Memory Subsystem

• Simultaneous handling of more loads and stores enabled by enlargedbuffers.

• Page split load penalty down from 100 cycles in previous generationto 5 cycles.

• L3 write bandwidth increased from 4 cycles per line in previousgeneration to 2 per line.

• L2 associativity changed from 8 ways to 4 ways.

14/81 1.2 Теория: Общая методология

Page 43: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)• Без дебаггера• Выключите другие приложения• Используйте максимальную производительность

Загруженность CPU:

15/81 1.2 Теория: Общая методология

Page 44: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)

• Без дебаггера• Выключите другие приложения• Используйте максимальную производительность

Загруженность CPU:

15/81 1.2 Теория: Общая методология

Page 45: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)• Без дебаггера

• Выключите другие приложения• Используйте максимальную производительность

Загруженность CPU:

15/81 1.2 Теория: Общая методология

Page 46: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)• Без дебаггера• Выключите другие приложения

• Используйте максимальную производительностьЗагруженность CPU:

15/81 1.2 Теория: Общая методология

Page 47: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)• Без дебаггера• Выключите другие приложения• Используйте максимальную производительность

Загруженность CPU:

15/81 1.2 Теория: Общая методология

Page 48: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Окружение и запускСоветы по запуску бенчмарков:

• Release build (Top 1 бенчмарк-ошибок)• Без дебаггера• Выключите другие приложения• Используйте максимальную производительность

Загруженность CPU:

15/81 1.2 Теория: Общая методология

Page 49: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость• Изолированность• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 50: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность

• Точность• Воспроизводимость• Изолированность• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 51: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность

• Воспроизводимость• Изолированность• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 52: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость

• Изолированность• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 53: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость• Изолированность

• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 54: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость• Изолированность• Переносимость

• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 55: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость• Изолированность• Переносимость• Простота

• Честность

16/81 1.2 Теория: Общая методология

Page 56: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Требования к бенчмарку

• Надёжность• Точность• Воспроизводимость• Изолированность• Переносимость• Простота• Честность

16/81 1.2 Теория: Общая методология

Page 57: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

BenchmarkDotNet

17/81 1.2 Теория: Общая методология

Page 58: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1.3Таймеры

18/81 1.3 Теория: Таймеры

Page 59: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime vs Stopwatch

var start = DateTime.Now;Foo();var finish = DateTime.Now;var time = (finish - start).TotalMilliseconds;

vs

var sw = Stopwatch.StartNew();Foo();sw.Stop();var time = sw.ElapsedMilliseconds;

19/81 1.3 Теория: Таймеры

Page 60: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Характеристики таймеров

• Монотонностьзамеры должны неуменьшаться

• Resolutionминимальное положительное время между замерами

• Latencyвремя на получение замера

20/81 1.3 Теория: Таймеры

Page 61: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Характеристики таймеров

• Монотонностьзамеры должны неуменьшаться

• Resolutionминимальное положительное время между замерами

• Latencyвремя на получение замера

20/81 1.3 Теория: Таймеры

Page 62: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Характеристики таймеров

• Монотонностьзамеры должны неуменьшаться

• Resolutionминимальное положительное время между замерами

• Latencyвремя на получение замера

20/81 1.3 Теория: Таймеры

Page 63: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Характеристики таймеров

• Монотонностьзамеры должны неуменьшаться

• Resolutionминимальное положительное время между замерами

• Latencyвремя на получение замера

20/81 1.3 Теория: Таймеры

Page 64: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime.UtcNow

OS ImplementationWindows GetSystemTimeAsFileTimeLinux gettimeofday

OS Runtime Time∗

Latency Windows Full/Core ≈7–8nsLatency Windows Mono ≈30–31nsResolution Windows Any ≈0.5..15.625msLatency Linux Mono ≈26–30nsResolution Linux Mono ≈1µs

∗Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/datetime/

21/81 1.3 Теория: Таймеры

Page 65: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime.UtcNow

OS ImplementationWindows GetSystemTimeAsFileTimeLinux gettimeofday

OS Runtime Time∗

Latency Windows Full/Core ≈7–8nsLatency Windows Mono ≈30–31nsResolution Windows Any ≈0.5..15.625msLatency Linux Mono ≈26–30nsResolution Linux Mono ≈1µs

∗Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/datetime/

21/81 1.3 Теория: Таймеры

Page 66: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime.UtcNow

OS ImplementationWindows GetSystemTimeAsFileTimeLinux gettimeofday

OS Runtime Time∗

Latency Windows Full/Core ≈7–8nsLatency Windows Mono ≈30–31nsResolution Windows Any ≈0.5..15.625ms

Latency Linux Mono ≈26–30nsResolution Linux Mono ≈1µs

∗Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/datetime/

21/81 1.3 Теория: Таймеры

Page 67: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime.UtcNow

OS ImplementationWindows GetSystemTimeAsFileTimeLinux gettimeofday

OS Runtime Time∗

Latency Windows Full/Core ≈7–8nsLatency Windows Mono ≈30–31nsResolution Windows Any ≈0.5..15.625msLatency Linux Mono ≈26–30nsResolution Linux Mono ≈1µs

∗Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/datetime/

21/81 1.3 Теория: Таймеры

Page 68: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

DateTime.UtcNow

OS ImplementationWindows GetSystemTimeAsFileTimeLinux gettimeofday

OS Runtime Time∗

Latency Windows Full/Core ≈7–8nsLatency Windows Mono ≈30–31nsResolution Windows Any ≈0.5..15.625msLatency Linux Mono ≈26–30nsResolution Linux Mono ≈1µs

∗Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/datetime/21/81 1.3 Теория: Таймеры

Page 69: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Stopwatch.GetTimestamp()

Hardware timers

• NA• TSC (Variant / Constant / Invariant)• ACPI PM (Freq = 3.579545 MHz)• HPET (Freq = 14.31818 MHz)

Implementation

• Windows: QueryPerformanceCounter• Linux: clock_gettime / mach_absolute_time /gettimeofday

22/81 1.3 Теория: Таймеры

Page 70: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Stopwatch.GetTimestamp()

Hardware timers

• NA• TSC (Variant / Constant / Invariant)• ACPI PM (Freq = 3.579545 MHz)• HPET (Freq = 14.31818 MHz)

Implementation

• Windows: QueryPerformanceCounter• Linux: clock_gettime / mach_absolute_time /gettimeofday

22/81 1.3 Теория: Таймеры

Page 71: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Stopwatch.GetTimestamp()

Hardware timers

• NA• TSC (Variant / Constant / Invariant)• ACPI PM (Freq = 3.579545 MHz)• HPET (Freq = 14.31818 MHz)

Implementation

• Windows: QueryPerformanceCounter• Linux: clock_gettime / mach_absolute_time /gettimeofday

22/81 1.3 Теория: Таймеры

Page 72: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Stopwatch.GetTimestamp()Runtime OS Timer 1 tick Latency ResolutionFull Win TSC 300-400ns 15-18ns 300-400nsFull Win HPET 69.8ns 500-800ns ≈LatencyFull Win NA 100ns 7-10ns 0.5-55msMono Win TSC 100ns 35-45ns 300-400nsMono Win HPET 100ns 500-800ns ≈LatencyMono Win NA 100ns 30-40ns 0.5-55msCore Linux TSC 1ns 30-35ns ≈LatencyCore Linux HPET/ACPI 1ns 500-800ns ≈LatencyMono Linux TSC 100ns 20-25ns 100nsMono Linux HPET/ACPI 100ns 500-800ns ≈Latency

Intel i7-4702MQ CPU 2.20GHz

См. также: http://aakinshin.net/en/blog/dotnet/stopwatch/

23/81 1.3 Теория: Таймеры

Page 73: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры

• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 74: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 75: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 76: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 77: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 78: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 79: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Важно помнить про таймеры• Важно понимать значения Latency и Resolution

• 1 tick ≠ Resolution

• Время может идти назад /

• Два последовательных замера могут быть равны

• Два последовательных замера могут различаться на миллисекунды

Тем временем...

24/81 1.3 Теория: Таймеры

Page 80: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1.4Количество итераций

25/81 1.4 Теория: Количество итераций

Page 81: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

МикробенчмаркингПлохой бенчмарк

// Resolution(Stopwatch) = 466 ns// Latency(Stopwatch) = 18 nsvar sw = Stopwatch.StartNew();Foo(); // 100 nssw.Stop();WriteLine(sw.ElapsedMilliseconds);

Небольшое улучшениеvar sw = Stopwatch.StartNew();for (int i = 0; i < N; i++) // (N * 100 + eps) ns

Foo();sw.Stop();var total = sw.ElapsedTicks / Stopwatch.Frequency;WriteLine(total / N);

26/81 1.4 Теория: Количество итераций

Page 82: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

МикробенчмаркингПлохой бенчмарк

// Resolution(Stopwatch) = 466 ns// Latency(Stopwatch) = 18 nsvar sw = Stopwatch.StartNew();Foo(); // 100 nssw.Stop();WriteLine(sw.ElapsedMilliseconds);

Небольшое улучшениеvar sw = Stopwatch.StartNew();for (int i = 0; i < N; i++) // (N * 100 + eps) ns

Foo();sw.Stop();var total = sw.ElapsedTicks / Stopwatch.Frequency;WriteLine(total / N);

26/81 1.4 Теория: Количество итераций

Page 83: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

ПрогревЗапустим бенчмарк несколько раз:int[] x = new int[128 * 1024 * 1024];for (int iter = 0; iter < 5; iter++){

var sw = Stopwatch.StartNew();for (int i = 0; i < x.Length; i += 16)

x[i]++;sw.Stop();Console.WriteLine(sw.ElapsedMilliseconds);

}

Результат:17681626262

27/81 1.4 Теория: Количество итераций

Page 84: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

ПрогревЗапустим бенчмарк несколько раз:int[] x = new int[128 * 1024 * 1024];for (int iter = 0; iter < 5; iter++){

var sw = Stopwatch.StartNew();for (int i = 0; i < x.Length; i += 16)

x[i]++;sw.Stop();Console.WriteLine(sw.ElapsedMilliseconds);

}

Результат:17681626262

27/81 1.4 Теория: Количество итераций

Page 85: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Несколько запусков метода

Run 01 : 529.8674 ns/opRun 02 : 532.7541 ns/opRun 03 : 558.7448 ns/opRun 04 : 555.6647 ns/opRun 05 : 539.6401 ns/opRun 06 : 539.3494 ns/opRun 07 : 564.3222 ns/opRun 08 : 551.9544 ns/opRun 09 : 550.1608 ns/opRun 10 : 533.0634 ns/op

28/81 1.4 Теория: Количество итераций

Page 86: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Несколько запусков бенчмарка

29/81 1.4 Теория: Количество итераций

Page 87: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Простой случайЦентральная предельная теорема

спешит на помощь!

30/81 1.4 Теория: Количество итераций

Page 88: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Но есть и сложные случаи

31/81 1.4 Теория: Количество итераций

Page 89: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 1.5Различные сложности

32/81 1.5 Теория: Различные сложности

Page 90: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Накладные расходы

var sw = Stopwatch.StartNew();int x = 0;for (int i = 0; i < N; i++) // overhead

x++; // target operationsw.Stop();

33/81 1.5 Теория: Различные сложности

Page 91: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Изоляция бенчмарков

Плохой бенчмарк

var sw1 = Stopwatch.StartNew();Foo();sw1.Stop();var sw2 = Stopwatch.StartNew();Bar();sw2.Stop();

Вспомним про:• Interface method dispatch• Garbage collector and autotuning• Conditional jitting

34/81 1.5 Теория: Различные сложности

Page 92: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Изоляция бенчмарков

Плохой бенчмарк

var sw1 = Stopwatch.StartNew();Foo();sw1.Stop();var sw2 = Stopwatch.StartNew();Bar();sw2.Stop();

Вспомним про:• Interface method dispatch• Garbage collector and autotuning• Conditional jitting

34/81 1.5 Теория: Различные сложности

Page 93: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Борьба с оптимизациями

• Dead code elimination• Inlining• Constant folding• Instruction Level Parallelism• Branch prediction• . . .

35/81 1.5 Теория: Различные сложности

Page 94: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Знай Latency операций!

Event Latency1 CPU cycle 0.3 nsLevel 1 cache access 0.9 nsLevel 2 cache access 2.8 nsLevel 3 cache access 12.9 nsMain memory access 120 nsSolid-state disk I/O 50-150 µsRotational disk I/O 1-10 msHardware virtualization reboot 40 secPhysical system reboot 5 min

© Systems Performance: Enterprise and the Cloud

36/81 1.5 Теория: Различные сложности

Page 95: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Processor affinity

37/81 1.5 Теория: Различные сложности

Page 96: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

True sharing

38/81 1.5 Теория: Различные сложности

Page 97: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

False sharing

39/81 1.5 Теория: Различные сложности

Page 98: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

False sharing в действииprivate static int[] x = new int[1024];

private void Inc(int p){

for (int i = 0; i < 10000001; i++)x[p]++;

}

private void Run(int step){

var sw = Stopwatch.StartNew();Task.WaitAll(

Task.Factory.StartNew(() => Inc(0 * step)),Task.Factory.StartNew(() => Inc(1 * step)),Task.Factory.StartNew(() => Inc(2 * step)),Task.Factory.StartNew(() => Inc(3 * step)));

Console.WriteLine(sw.ElapsedMilliseconds);}

Run(1) Run(256)≈400ms ≈150ms

40/81 1.5 Теория: Различные сложности

Page 99: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

False sharing в действииprivate static int[] x = new int[1024];

private void Inc(int p){

for (int i = 0; i < 10000001; i++)x[p]++;

}

private void Run(int step){

var sw = Stopwatch.StartNew();Task.WaitAll(

Task.Factory.StartNew(() => Inc(0 * step)),Task.Factory.StartNew(() => Inc(1 * step)),Task.Factory.StartNew(() => Inc(2 * step)),Task.Factory.StartNew(() => Inc(3 * step)));

Console.WriteLine(sw.ElapsedMilliseconds);}

Run(1) Run(256)≈400ms ≈150ms

40/81 1.5 Теория: Различные сложности

Page 100: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Бенчмаркинг — это сложно

Anon et al., “A Measure of Transaction Processing Power”

There are lies, damn lies and then there are performance measures.

41/81 1.5 Теория: Различные сложности

Page 101: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2Практика

42/81 2. Практика

Page 102: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.1Сложности нанобенчмаркинга

43/81 2.1 Практика: Сложности нанобенчмаркинга

Page 103: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Из интернетов

44/81 2.1 Практика: Сложности нанобенчмаркинга

Page 104: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Из интернетов

44/81 2.1 Практика: Сложности нанобенчмаркинга

Page 105: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Из интернетов

44/81 2.1 Практика: Сложности нанобенчмаркинга

Page 106: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

ЗадачаКакой из методов работает быстрее?

[MethodImpl(MethodImplOptions.NoInlining)]public void Empty0() {}

[MethodImpl(MethodImplOptions.NoInlining)]public void Empty1() {}

[MethodImpl(MethodImplOptions.NoInlining)]public void Empty2() {}

[MethodImpl(MethodImplOptions.NoInlining)]public void Empty3() {}

45/81 2.1 Практика: Сложности нанобенчмаркинга

Page 107: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Попытка решенияДавайте забенчмаркаем!

private void MeasureX() // X = 0, 1, 2, 3{

for (int i = 0; i < Rep; i++){

var sw = Stopwatch.StartNew();for (int j = 0; j < N; j++)

EmptyX(); // X = 0, 1, 2, 3sw.Stop();Write(sw.ElapsedMilliseconds + " ");

}}

Empty0: 242 253 245 253 242 244 245 255 245 245 // SlowEmpty1: 241 240 237 244 242 241 238 245 239 239 // SlowEmpty2: 224 228 229 224 223 224 227 222 228 222 // FastEmpty3: 229 222 226 222 224 226 227 229 225 230 // Fast

Intel Core i7 Haswell, RyuJIT-x64

46/81 2.1 Практика: Сложности нанобенчмаркинга

Page 108: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Попытка решенияДавайте забенчмаркаем!

private void MeasureX() // X = 0, 1, 2, 3{

for (int i = 0; i < Rep; i++){

var sw = Stopwatch.StartNew();for (int j = 0; j < N; j++)

EmptyX(); // X = 0, 1, 2, 3sw.Stop();Write(sw.ElapsedMilliseconds + " ");

}}

Empty0: 242 253 245 253 242 244 245 255 245 245 // SlowEmpty1: 241 240 237 244 242 241 238 245 239 239 // SlowEmpty2: 224 228 229 224 223 224 227 222 228 222 // FastEmpty3: 229 222 226 222 224 226 227 229 225 230 // Fast

Intel Core i7 Haswell, RyuJIT-x6446/81 2.1 Практика: Сложности нанобенчмаркинга

Page 109: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Обратимся к классике

Рекомендуемая литература: Agner Fog,“The microarchitecture of Intel, AMD and VIA CPUs.An optimization guide for assembly programmers and compiler makers.”

3.8 Branch prediction in Intel Haswell, Broadwell and Skylake

Pattern recognition for indirect jumps and calls.Indirect jumps and indirect calls are predicted well.. . .These observations may indicate that there are two branch predictionmethods: a fast method tied to the µop cache and the instruction cache,and a slower method using a branch target buffer.

47/81 2.1 Практика: Сложности нанобенчмаркинга

Page 110: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Обратимся к классике

Рекомендуемая литература: Agner Fog,“The microarchitecture of Intel, AMD and VIA CPUs.An optimization guide for assembly programmers and compiler makers.”

3.8 Branch prediction in Intel Haswell, Broadwell and Skylake

Pattern recognition for indirect jumps and calls.Indirect jumps and indirect calls are predicted well.

. . .These observations may indicate that there are two branch predictionmethods: a fast method tied to the µop cache and the instruction cache,and a slower method using a branch target buffer.

47/81 2.1 Практика: Сложности нанобенчмаркинга

Page 111: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Обратимся к классике

Рекомендуемая литература: Agner Fog,“The microarchitecture of Intel, AMD and VIA CPUs.An optimization guide for assembly programmers and compiler makers.”

3.8 Branch prediction in Intel Haswell, Broadwell and Skylake

Pattern recognition for indirect jumps and calls.Indirect jumps and indirect calls are predicted well.. . .These observations may indicate that there are two branch predictionmethods: a fast method tied to the µop cache and the instruction cache,and a slower method using a branch target buffer.

47/81 2.1 Практика: Сложности нанобенчмаркинга

Page 112: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Воспользуемся правильным инструментом

48/81 2.1 Практика: Сложности нанобенчмаркинга

Page 113: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Раскрутка цикла спешит на помощь!var sw = Stopwatch.StartNew();for (int j = 0; j < N; j++){

Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();Empty0();

}sw.Stop();

49/81 2.1 Практика: Сложности нанобенчмаркинга

Page 114: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.2Работаем с памятью

50/81 2.2 Практика: Работаем с памятью

Page 115: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Сумма элементов массива

const int N = 1024;int[,] a = new int[N, N];

[Benchmark]public double SumIj(){

var sum = 0;for (int i = 0; i < N; i++)

for (int j = 0; j < N; j++)sum += a[i, j];

return sum;}

[Benchmark]public double SumJi(){

var sum = 0;for (int j = 0; j < N; j++)

for (int i = 0; i < N; i++)sum += a[i, j];

return sum;}

SumIj SumJiLegacyJIT-x86 ≈1.3ms ≈4.0ms

51/81 2.2 Практика: Работаем с памятью

Page 116: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Сумма элементов массива

const int N = 1024;int[,] a = new int[N, N];

[Benchmark]public double SumIj(){

var sum = 0;for (int i = 0; i < N; i++)

for (int j = 0; j < N; j++)sum += a[i, j];

return sum;}

[Benchmark]public double SumJi(){

var sum = 0;for (int j = 0; j < N; j++)

for (int i = 0; i < N; i++)sum += a[i, j];

return sum;}

SumIj SumJiLegacyJIT-x86 ≈1.3ms ≈4.0ms

51/81 2.2 Практика: Работаем с памятью

Page 117: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.3Работаем с условными переходами

52/81 2.3 Практика: Работаем с условными переходами

Page 118: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Branch predictionconst int N = 32767;int[] sorted, unsorted; // random numbers [0..255]private static int Sum(int[] data){

int sum = 0;for (int i = 0; i < N; i++)

if (data[i] >= 128)sum += data[i];

return sum;}[Benchmark]public int Sorted(){

return Sum(sorted);}

[Benchmark]public int Unsorted(){

return Sum(unsorted);}

Sorted UnsortedLegacyJIT-x86 ≈20µs ≈139µs

53/81 2.3 Практика: Работаем с условными переходами

Page 119: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Branch predictionconst int N = 32767;int[] sorted, unsorted; // random numbers [0..255]private static int Sum(int[] data){

int sum = 0;for (int i = 0; i < N; i++)

if (data[i] >= 128)sum += data[i];

return sum;}[Benchmark]public int Sorted(){

return Sum(sorted);}

[Benchmark]public int Unsorted(){

return Sum(unsorted);}

Sorted UnsortedLegacyJIT-x86 ≈20µs ≈139µs

53/81 2.3 Практика: Работаем с условными переходами

Page 120: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.4Interface method dispatch

54/81 2.4 Практика: Interface method dispatch

Page 121: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Интерфейсыprivate interface IInc {

double Inc(double x);}private class Foo : IInc {

double Inc(double x) => x + 1;}private class Bar : IInc {

double Inc(double x) => x + 1;}private double Run(IInc inc) {

double sum = 0;for (int i = 0; i < 1001; i++)

sum += inc.Inc(0);return sum;

}

// Which method is faster?

[Benchmark]public double FooFoo() {

var foo1 = new Foo();var foo2 = new Foo();return Run(foo1) + Run(foo2);

}

[Benchmark]public double FooBar() {

var foo = new Foo();var bar = new Bar();return Run(foo) + Run(bar);

}

FooFoo FooBarLegacyJIT-x64 ≈5.4µs ≈7.1µs

55/81 2.4 Практика: Interface method dispatch

Page 122: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Интерфейсыprivate interface IInc {

double Inc(double x);}private class Foo : IInc {

double Inc(double x) => x + 1;}private class Bar : IInc {

double Inc(double x) => x + 1;}private double Run(IInc inc) {

double sum = 0;for (int i = 0; i < 1001; i++)

sum += inc.Inc(0);return sum;

}

// Which method is faster?

[Benchmark]public double FooFoo() {

var foo1 = new Foo();var foo2 = new Foo();return Run(foo1) + Run(foo2);

}

[Benchmark]public double FooBar() {

var foo = new Foo();var bar = new Bar();return Run(foo) + Run(bar);

}

FooFoo FooBarLegacyJIT-x64 ≈5.4µs ≈7.1µs

55/81 2.4 Практика: Interface method dispatch

Page 123: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.5Inlining

56/81 2.5 Практика: Inlining

Page 124: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Исходники .NET Framework

57/81 2.5 Практика: Inlining

Page 125: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Inlining — это сложно// mscorlib/system/decimal.cs,158// Constructs a Decimal from an integer value.public Decimal(int value) {

// JIT today can't inline methods that contains "starg"// opcode. For more details, see DevDiv Bugs 81184:// x86 JIT CQ: Removing the inline striction of "starg".int value_copy = value;if (value_copy >= 0) {

flags = 0;} else {

flags = SignMask;value_copy = -value_copy;

}lo = value_copy;mid = 0;hi = 0;

}

58/81 2.5 Практика: Inlining

Page 126: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Проведём опыт

[Benchmark]int Calc() => WithoutStarg(0x11) + WithStarg(0x12);

int WithoutStarg(int value) => value;

int WithStarg(int value){

if (value < 0)value = -value;

return value;}

LegacyJIT-x86 LegacyJIT-x64 RyuJIT-x64≈1.7ns 0 ≈1.7ns

59/81 2.5 Практика: Inlining

Page 127: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Проведём опыт

[Benchmark]int Calc() => WithoutStarg(0x11) + WithStarg(0x12);

int WithoutStarg(int value) => value;

int WithStarg(int value){

if (value < 0)value = -value;

return value;}

LegacyJIT-x86 LegacyJIT-x64 RyuJIT-x64≈1.7ns 0 ≈1.7ns

59/81 2.5 Практика: Inlining

Page 128: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?

LegacyJIT-x64

; LegacyJIT-x64mov ecx,23hret

RyuJIT-x64

// Inline expansion aborted due to opcode// [06] OP_starg.s in method// Program:WithStarg(int):int:this

60/81 2.5 Практика: Inlining

Page 129: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?

LegacyJIT-x64

; LegacyJIT-x64mov ecx,23hret

RyuJIT-x64

// Inline expansion aborted due to opcode// [06] OP_starg.s in method// Program:WithStarg(int):int:this

60/81 2.5 Практика: Inlining

Page 130: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Ещё одна загадка

61/81 2.5 Практика: Inlining

Page 131: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Отгадка

62/81 2.5 Практика: Inlining

Page 132: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.6SIMD

63/81 2.6 Практика: SIMD

Page 133: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Поговорим про SIMDprivate struct MyVector {

public float X, Y, Z, W;public MyVector(float x, float y, float z, float w) {

X = x; Y = y; Z = z; W = w;}[MethodImpl(MethodImplOptions.AggressiveInlining)]public static MyVector operator *(MyVector left, MyVector right) {

return new MyVector(left.X * right.X, left.Y * right.Y,left.Z * right.Z, left.W * right.W);

}}private Vector4 vector1, vector2, vector3;private MyVector myVector1, myVector2, myVector3;[Benchmark] public void MyMul() => myVector3 = myVector1 * myVector2;[Benchmark] public void BclMul() => vector3 = vector1 * vector2;

LegacyJIT-x64 RyuJIT-x64MyMul 12.9ns 2.5nsBclMul 12.9ns 0.2ns

64/81 2.6 Практика: SIMD

Page 134: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Поговорим про SIMDprivate struct MyVector {

public float X, Y, Z, W;public MyVector(float x, float y, float z, float w) {

X = x; Y = y; Z = z; W = w;}[MethodImpl(MethodImplOptions.AggressiveInlining)]public static MyVector operator *(MyVector left, MyVector right) {

return new MyVector(left.X * right.X, left.Y * right.Y,left.Z * right.Z, left.W * right.W);

}}private Vector4 vector1, vector2, vector3;private MyVector myVector1, myVector2, myVector3;[Benchmark] public void MyMul() => myVector3 = myVector1 * myVector2;[Benchmark] public void BclMul() => vector3 = vector1 * vector2;

LegacyJIT-x64 RyuJIT-x64MyMul 12.9ns 2.5nsBclMul 12.9ns 0.2ns

64/81 2.6 Практика: SIMD

Page 135: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?LegacyJIT-x64 RyuJIT-x64

MyMul ≈12.9ns ≈2.5nsBclMul ≈12.9ns ≈0.2ns

; LegacyJIT-x64; MyMul, BclMul: Naı̈ve SSE; ...movss xmm3,dword ptr [rsp+40h]mulss xmm3,dword ptr [rsp+30h]movss xmm2,dword ptr [rsp+44h]mulss xmm2,dword ptr [rsp+34h]movss xmm1,dword ptr [rsp+48h]mulss xmm1,dword ptr [rsp+38h]movss xmm0,dword ptr [rsp+4Ch]mulss xmm0,dword ptr [rsp+3Ch]xor eax,eaxmov qword ptr [rsp],raxmov qword ptr [rsp+8],raxlea rax,[rsp]movss dword ptr [rax],xmm3movss dword ptr [rax+4],xmm2; ...

; RyuJIT-x64; MyMul: Naı̈ve AVX; ...vmulss xmm0,xmm0,xmm4vmulss xmm1,xmm1,xmm5vmulss xmm2,xmm2,xmm6vmulss xmm3,xmm3,xmm7; ...

; BclMul: Smart AVX intrinsicvmovupd xmm0,xmmword ptr [rcx+8]vmovupd xmm1,xmmword ptr [rcx+18h]vmulps xmm0,xmm0,xmm1vmovupd xmmword ptr [rcx+28h],xmm0

65/81 2.6 Практика: SIMD

Page 136: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.7Constant folding

66/81 2.7 Практика: Constant folding

Page 137: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Интересный issue на dotnet/coreclr

67/81 2.7 Практика: Constant folding

Page 138: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Учимся извлекать корни

double Sqrt13() =>Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + /* ... */+ Math.Sqrt(13);

VS

double Sqrt14() =>Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + /* ... */+ Math.Sqrt(13) + Math.Sqrt(14);

RyuJIT-x64Sqrt13 ≈91nsSqrt14 0 ns

68/81 2.7 Практика: Constant folding

Page 139: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Учимся извлекать корни

double Sqrt13() =>Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + /* ... */+ Math.Sqrt(13);

VS

double Sqrt14() =>Math.Sqrt(1) + Math.Sqrt(2) + Math.Sqrt(3) + /* ... */+ Math.Sqrt(13) + Math.Sqrt(14);

RyuJIT-x64Sqrt13 ≈91nsSqrt14 0 ns

68/81 2.7 Практика: Constant folding

Page 140: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?RyuJIT-x64, Sqrt13

vsqrtsd xmm0,xmm0,mmword ptr [7FF94F9E4D28h]vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D30h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D38h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D40h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D48h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D50h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D58h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D60h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D68h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D70h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D78h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D80h]vaddsd xmm0,xmm0,xmm1vsqrtsd xmm1,xmm0,mmword ptr [7FF94F9E4D88h]vaddsd xmm0,xmm0,xmm1ret

69/81 2.7 Практика: Constant folding

Page 141: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?RyuJIT-x64, Sqrt14

vmovsd xmm0,qword ptr [7FF94F9C4C80h]ret

70/81 2.7 Практика: Constant folding

Page 142: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?Большое дерево выражения

* stmtExpr void (top level) (IL 0x000... ???)| /--* mathFN double sqrt| | \--* dconst double 13.000000000000000| /--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 12.000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 11.000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 10.000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 9.0000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 8.0000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 7.0000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 6.0000000000000000| | \--* + double| | | /--* mathFN double sqrt| | | | \--* dconst double 5.0000000000000000// ...

71/81 2.7 Практика: Constant folding

Page 143: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?Constant folding в действии

N001 [000001] dconst 1.0000000000000000 => $c0 {DblCns[1.000000]}N002 [000002] mathFN => $c0 {DblCns[1.000000]}N003 [000003] dconst 2.0000000000000000 => $c1 {DblCns[2.000000]}N004 [000004] mathFN => $c2 {DblCns[1.414214]}N005 [000005] + => $c3 {DblCns[2.414214]}N006 [000006] dconst 3.0000000000000000 => $c4 {DblCns[3.000000]}N007 [000007] mathFN => $c5 {DblCns[1.732051]}N008 [000008] + => $c6 {DblCns[4.146264]}N009 [000009] dconst 4.0000000000000000 => $c7 {DblCns[4.000000]}N010 [000010] mathFN => $c1 {DblCns[2.000000]}N011 [000011] + => $c8 {DblCns[6.146264]}N012 [000012] dconst 5.0000000000000000 => $c9 {DblCns[5.000000]}N013 [000013] mathFN => $ca {DblCns[2.236068]}N014 [000014] + => $cb {DblCns[8.382332]}N015 [000015] dconst 6.0000000000000000 => $cc {DblCns[6.000000]}N016 [000016] mathFN => $cd {DblCns[2.449490]}N017 [000017] + => $ce {DblCns[10.831822]}N018 [000018] dconst 7.0000000000000000 => $cf {DblCns[7.000000]}N019 [000019] mathFN => $d0 {DblCns[2.645751]}N020 [000020] + => $d1 {DblCns[13.477573]}...

72/81 2.7 Практика: Constant folding

Page 144: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 2.8Instruction level parallelism

73/81 2.8 Практика: Instruction level parallelism

Page 145: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Неожиданные perf-эффекты

1Справедливо для RyuJIT RC, ныне пофикшено74/81 2.8 Практика: Instruction level parallelism

Page 146: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Задачкаprivate double[] x = new double[11];

[Benchmark]public double Calc(){

double sum = 0.0;for (int i = 1; i < x.Length; i++)

sum += 1.0 / (i * i) * x[i];return sum;

}

LegacyJIT-x64 RyuJIT-x641

Calc 1 попугай 2 попугая

75/81 2.8 Практика: Instruction level parallelism

Page 147: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Задачкаprivate double[] x = new double[11];

[Benchmark]public double Calc(){

double sum = 0.0;for (int i = 1; i < x.Length; i++)

sum += 1.0 / (i * i) * x[i];return sum;

}

LegacyJIT-x64 RyuJIT-x641

Calc 1 попугай 2 попугая

1RyuJIT RC75/81 2.8 Практика: Instruction level parallelism

Page 148: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Как же так?; LegacyJIT-x64; eax = imov eax,r8d; eax = i*iimul eax,r8d; xmm0=i*icvtsi2sd xmm0,eax; xmm1=1movsd xmm1,

mmword ptr [7FF9141145E0h]; xmm1=1/(i*i)divsd xmm1,xmm0

; xmm1=1/(i*i)*x[i]mulsd xmm1,

mmword ptr [rdx+r9+10h]; xmm1 = sum + 1/(i*i)*x[i]addsd xmm1,xmm2; sum = sum + 1/(i*i)*x[i]movapd xmm2,xmm1

; RyuJIT-x64; r8d = imov r8d,eax; r8d = i*iimul r8d,eax; xmm1=i*ivcvtsi2sd xmm1,xmm1,r8d; xmm2=1vmovsd xmm2,

qword ptr [7FF9140E4398h]; xmm2=1/(i*i)vdivsd xmm2,xmm2,xmm1mov r8,rdxmovsxd r9,eax; xmm1 = 1/(i*i)vmovaps xmm1,xmm2; xmm1 = 1/(i*i)*x[i]vmulsd xmm1,xmm1,

mmword ptr [r8+r9*8+10h]; sum += 1/(i*i)*x[i]vaddsd xmm0,xmm0,xmm1

См. также: https://github.com/dotnet/coreclr/issues/993

76/81 2.8 Практика: Instruction level parallelism

Page 149: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Часть 3Заключение

77/81 3. Заключение

Page 150: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Отказ от ответственности

• Все представленные выводы и бенчмарки могут быть враньём

• На вашем железе цифры могут быть другие, это нормально

• Использование BenchmarkDotNet не делает ваш бенчмарк правильным

• Использование самописных бенчмарков не делает выводы ложными

78/81 3. Заключение

Page 151: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Сегодня мы узнали

• Бенчмаркинг и прочие замеры производительности — это сложно

• Бенчмаркинг требует очень много сил, знаний, времени и нервов

• Бенчмарк без анализа — плохой бенчмарк

79/81 3. Заключение

Page 152: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Методическая литератураДля успешных микробенчмарков нужно очень много знать:

80/81 3. Заключение

Page 153: Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)

Вопросы?

Андрей Акиньшинhttp://aakinshin.net

https://github.com/AndreyAkinshinhttps://twitter.com/andrey_akinshin

[email protected]/81 3. Заключение