Поговорим про память

Andrey Akinshin
Andrey AkinshinSoftware developer at JetBrains
Поговорим про память
Андрей Акиньшин, JetBrains
DotNext 2017 SPb
1/79
Часть 1
О чём будем разговаривать?
2/79 1. О чём будем разговаривать?
Мотивация
Хотим, чтобы программы работали
очень быстро и кушали мало памяти!
3/79 1. О чём будем разговаривать?
Знай свой bottleneck
4/79 1. О чём будем разговаривать?
Знай свой bottleneck
• CPU
• Database
• I/O
• Network
• Concurrency
• . . .
• Main memory (вот про неё и будем разговаривать)
5/79 1. О чём будем разговаривать?
История одной оптимизации
6/79 1. О чём будем разговаривать?
История одной оптимизации
Делаем замер времени (один) до и после:
До 50ms
После 45ms
6/79 1. О чём будем разговаривать?
История одной оптимизации
Делаем замер времени (один) до и после:
До 50ms
После 45ms
Вопрос: а стало ли лучше?
6/79 1. О чём будем разговаривать?
Посмотрим на распределения
7/79 1. О чём будем разговаривать?
Краткое содержание доклада
Сегодня мы узнаем:
• Из чего складывается производительность памяти?
• 10 способов написать некорректный memory benchmark
8/79 1. О чём будем разговаривать?
Краткое содержание доклада
Сегодня мы узнаем:
• Из чего складывается производительность памяти?
• 10 способов написать некорректный memory benchmark
Обсуждаемые темы:
• CPU Cache (cache line size, associativity, . . . )
• Cache Bank Conflicts
• Alignment
• Struct Promotion
• Prefetching
• Store forwarding; 4K aliasing
• Трудности работы с GC и pinned objects
• Large Object Heap; Full Framework vs Mono
8/79 1. О чём будем разговаривать?
Часть 2
Введение
9/79 2. Введение
Отказ от ответственности
Нужно понимать
• Все примеры академические, нужны для иллюстрации идей
• Погрешности малы, для целей доклада ими можно пренебречь
• На вашем железе цифры могут быть другие, это нормально
Подопытное железо
• Ivy Bridge Core i7-3632QM CPU 2.20GHz
• Haswell Core i7-4702MQ CPU 2.20GHz
• Skylake Core i7-6700HQ CPU 2.60GHz
Информация о бенчмарках
• BenchmarkDotNet v0.10.6 (supported by the .NET Foundation)
• Gist с исходниками: https://git.io/v9dV8
10/79 2. Введение
Давайте позамеряем время!
// Инициализируем собственную хешмапу
var dict = new MyAwesomeDictionary<int, int>();
dict.Put(0, 0);
11/79 2. Введение
Давайте позамеряем время!
// Инициализируем собственную хешмапу
var dict = new MyAwesomeDictionary<int, int>();
dict.Put(0, 0);
// А теперь немного побенчмаркаем:
var sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
dict.Get(0);
sw.Stop();
WriteLine(sw.Elapsed);
11/79 2. Введение
Давайте позамеряем время!
// Инициализируем собственную хешмапу
var dict = new MyAwesomeDictionary<int, int>();
dict.Put(0, 0);
// А теперь немного побенчмаркаем:
var sw = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
dict.Get(0);
sw.Stop();
WriteLine(sw.Elapsed);
Есть ли проблемы с этим бенчмарком?
11/79 2. Введение
Нужно правильно дизайнить memory-бенчмарки
12/79 2. Введение
Нужно правильно дизайнить memory-бенчмарки
Пробуйте разные паттерны доступа к памяти
• Последовательный доступ
• Случайный доступ
• Пользовательский сценарий
• “Хитрые” случаи
12/79 2. Введение
Нужно правильно дизайнить memory-бенчмарки
Пробуйте разные паттерны доступа к памяти
• Последовательный доступ
• Случайный доступ
• Пользовательский сценарий
• “Хитрые” случаи
Пробуйте разные размеры рабочей памяти
• Очень маленький
• Очень большой
• Значения, близкие к размеру L1, L2, L3
12/79 2. Введение
Часть 3
Поговорим про CPU Cache
13/79 3. Поговорим про CPU Cache
Доступ к памяти — это вам не константа!
14/79 3. Поговорим про CPU Cache
(Бенчмарк) CPU Cache
/* Сколько стоит сделать N инкрементов? */
private const int N = 16 * 1024 * 1024;
private byte[] data;
[Params(1, 2, 4, 8, 16, 32, 64, 128, 256, 512,
1024, 2048, 4096, 6144, 8192, 16384, 32768)]
public int SizeKb;
[Setup] public void Setup() => data = new byte[SizeKb * 1024];
[Benchmark]
public void Calc() {
var mask = data.Length - 1;
for (int i = 0; i < N; i++) // Бегаем по массиву с шагом в 64B
data[(i * 64) & mask]++; // И тыкаемся в элементы
}
Windows 10, .NET 4.6.2, LegacyJIT-x86
15/79 3. Поговорим про CPU Cache
(Результаты) CPU Cache
Сколько стоит сделать N инкрементов?
Cache Level Ivy Bridge Skylake
16/79 3. Поговорим про CPU Cache
(Результаты) CPU Cache
Сколько стоит сделать N инкрементов?
Cache Level Ivy Bridge Skylake
4 KB
L1
≈20ms ≈18ms
8 KB ≈20ms ≈18ms
16 KB ≈20ms ≈18ms
32 KB ≈20ms ≈18ms
16/79 3. Поговорим про CPU Cache
(Результаты) CPU Cache
Сколько стоит сделать N инкрементов?
Cache Level Ivy Bridge Skylake
4 KB
L1
≈20ms ≈18ms
8 KB ≈20ms ≈18ms
16 KB ≈20ms ≈18ms
32 KB ≈20ms ≈18ms
64 KB
L2
≈36ms ≈22ms
128 KB ≈36ms ≈22ms
256 KB ≈36ms ≈22ms
16/79 3. Поговорим про CPU Cache
(Результаты) CPU Cache
Сколько стоит сделать N инкрементов?
Cache Level Ivy Bridge Skylake
4 KB
L1
≈20ms ≈18ms
8 KB ≈20ms ≈18ms
16 KB ≈20ms ≈18ms
32 KB ≈20ms ≈18ms
64 KB
L2
≈36ms ≈22ms
128 KB ≈36ms ≈22ms
256 KB ≈36ms ≈22ms
512 KB
L3
≈50ms ≈36ms
1 MB ≈50ms ≈36ms
2 MB ≈50ms ≈36ms
4 MB ≈54ms ≈40ms
6 MB ≈54ms ≈40ms
16/79 3. Поговорим про CPU Cache
(Результаты) CPU Cache
Сколько стоит сделать N инкрементов?
Cache Level Ivy Bridge Skylake
4 KB
L1
≈20ms ≈18ms
8 KB ≈20ms ≈18ms
16 KB ≈20ms ≈18ms
32 KB ≈20ms ≈18ms
64 KB
L2
≈36ms ≈22ms
128 KB ≈36ms ≈22ms
256 KB ≈36ms ≈22ms
512 KB
L3
≈50ms ≈36ms
1 MB ≈50ms ≈36ms
2 MB ≈50ms ≈36ms
4 MB ≈54ms ≈40ms
6 MB ≈54ms ≈40ms
8 MB
RAM
≈80ms ≈70ms
16 MB ≈102ms ≈80ms
32 MB ≈108ms ≈83ms
16/79 3. Поговорим про CPU Cache
Часть 4
Поговорим про CPU Cache Levels
17/79 4. Поговорим про CPU Cache Levels
(Схематическое устройство) CPU Cache Levels
CPU0 CPU1 CPU2 CPU3
L1 L1 L1 L1
L2 L2 L2 L2
L3
18/79 4. Поговорим про CPU Cache Levels
(Бенчмарк) CPU Cache Levels
private const int N = 16 * 1024 * 1024;
private byte[] data;
[Params(2048, 4096, 6144)] // Нагрузка на L3
public int SizeKb;
[Setup] public void Setup() => data = new byte[SizeKb * 1024];
[Benchmark]
public void Calc() {
var mask = data.Length - 1;
for (int i = 0; i < N; i++)
data[(i * 64) & mask]++;
}
Windows 10, .NET 4.6.2, LegacyJIT-x86, Skylake
19/79 4. Поговорим про CPU Cache Levels
(Результаты) CPU Cache Levels
Условия Mean Min Max
2 MB
Стерильные
35.38ms 34.92ms 36.08ms
4 MB 39.49ms 39.01ms 40.06ms
6 MB 40.44ms 39.87ms 40.92ms
20/79 4. Поговорим про CPU Cache Levels
(Результаты) CPU Cache Levels
Условия Mean Min Max
2 MB
Стерильные
35.38ms 34.92ms 36.08ms
4 MB 39.49ms 39.01ms 40.06ms
6 MB 40.44ms 39.87ms 40.92ms
2 MB Firefox, Rider, IDEA,
TEXstudio, Dropbox,
GoogleDrive, . . .
44.50ms 36.75ms 52.34ms
4 MB 97.64ms 63.14ms 172.74ms
6 MB 75.02ms 42.07ms 154.55ms
20/79 4. Поговорим про CPU Cache Levels
(Распределение) CPU Cache Levels
21/79 4. Поговорим про CPU Cache Levels
Часть 5
Поговорим про CPU Cache Associativity
22/79 5. Поговорим про CPU Cache Associativity
(Бенчмарк) CPU Cache Associativity
private int[,] a;
[Params(511, 512, 513)] public int N;
[Setup] public void Setup() => a = new int[N, N];
// Ищем максимальный элемент в колонке
[Benchmark] public int Max() {
int max = 0;
for (int i = 0; i < N; i++)
max = Math.Max(max, a[i, 0]);
return max;
}
Windows 10, .NET 4.6.2, LegacyJIT-x86, Skylake
23/79 5. Поговорим про CPU Cache Associativity
(Результаты) CPU Cache Associativity
N Max
511 ≈844ns
512 ≈1330ns
513 ≈844ns
24/79 5. Поговорим про CPU Cache Associativity
(Теория) CPU Cache Associativity
25/79 5. Поговорим про CPU Cache Associativity
(Теория) CPU Cache Associativity
var criticalStride = cacheSize / associativity;
26/79 5. Поговорим про CPU Cache Associativity
(Теория) CPU Cache Associativity
var criticalStride = cacheSize / associativity;
Level Size Associativity Critical Stide
L1 32KB 8-way 4KB
L2 256KB 4-way 64KB
L2 256KB 8-way 32KB
L3 6MB 12-way 512KB
26/79 5. Поговорим про CPU Cache Associativity
Минутка занимательного про 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 enlarged
buffers.
• Page split load penalty down from 100 cycles in previous generation
to 5 cycles.
• L3 write bandwidth increased from 4 cycles per line in previous
generation to 2 per line.
• L2 associativity changed from 8 ways to 4 ways.
27/79 5. Поговорим про CPU Cache Associativity
Часть 6
Поговорим про Cache Bank Conflicts
28/79 6. Поговорим про Cache Bank Conflicts
(Бенчмарк) Cache Bank Conflicts
int[] data = new int[2 * 1024 * 1024];
[Params(15, 16, 17)] public int Delta;
// Есть ли у нас пары элементов на расстоянии Delta,
// в которых первое число меньше второго?
[Benchmark] public unsafe bool Calc() {
fixed (int* dataPtr = data) {
int* ptr = dataPtr;
int d = Delta;
bool res = false;
for (int i = 0; i < 1024 * 1024; i++) {
res |= (ptr[0] < ptr[d]);
ptr++;
}
return res;
}
}
Windows 10, .NET 4.6.2, LegacyJIT-x86
29/79 6. Поговорим про Cache Bank Conflicts
(Результаты) Cache Bank Conflicts
Delta 15 16 17
Skylake: выпущен 2015-08-05, микроархитектура Skylake
Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge
30/79 6. Поговорим про Cache Bank Conflicts
(Результаты) Cache Bank Conflicts
Delta 15 16 17
Skylake ≈1.05ms ≈1.05ms ≈1.05ms
Skylake: выпущен 2015-08-05, микроархитектура Skylake
Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge
30/79 6. Поговорим про Cache Bank Conflicts
(Результаты) Cache Bank Conflicts
Delta 15 16 17
Skylake ≈1.05ms ≈1.05ms ≈1.05ms
Ivy Bridge ≈1.07ms ≈1.30ms ≈1.07ms
Skylake: выпущен 2015-08-05, микроархитектура Skylake
Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge
30/79 6. Поговорим про Cache Bank Conflicts
(Мануал) Cache Bank Conflicts
Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual:
3.6.1.3. Handling L1D Cache Bank Conflict
In Intel microarchitecture code name Sandy Bridge, the internal organization
of the L1D cache may manifest a situation when two load micro-ops whose
addresses have a bank conflict. When a bank conflict is present between
two load operations, the more recent one will be delayed until the conflict
isresolved. A bank conflict happens when two simultaneous load operations
have the same bit 2–5 of their linear address but they are not from the same
set in the cache (bits 6–12).
(Мануал) Cache Bank Conflicts
Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual:
3.6.1.3. Handling L1D Cache Bank Conflict
In Intel microarchitecture code name Sandy Bridge, the internal organization
of the L1D cache may manifest a situation when two load micro-ops whose
addresses have a bank conflict. When a bank conflict is present between
two load operations, the more recent one will be delayed until the conflict
isresolved. A bank conflict happens when two simultaneous load operations
have the same bit 2–5 of their linear address but they are not from the same
set in the cache (bits 6–12).
With the Haswell microarchitecture, the L1 DCache bank conflict issue does
not apply.
31/79 6. Поговорим про Cache Bank Conflicts
Часть 7
Поговорим про Alignment
32/79 7. Поговорим про Alignment
(Бенчмарк) Alignment
public struct Struct3 {
public byte X1, X2, X3;
}
public struct Struct8 {
public byte X1, X2, X3, X4, X5, X6, X7, X8;
}
private Struct3[] struct3 = new Struct3[256];
private Struct8[] struct8 = new Struct8[256];
33/79 7. Поговорим про Alignment
(Бенчмарк) Alignment
[Benchmark] public int S3() {
int res = 0;
for (int i = 0; i < struct3.Length; i++) {
var s = struct3[i]; res += s.X1 + s.X2;
}
return res;
}
[Benchmark] public int S8() {
int res = 0;
for (int i = 0; i < struct8.Length; i++) {
var s = struct8[i]; res += s.X1 + s.X2;
}
return res;
}
34/79 7. Поговорим про Alignment
(Результаты) Alignment
LegacyJIT-x64 Mono
S3 ≈1276ns ≈1146ns
S8 ≈241ns ≈2232ns
35/79 7. Поговорим про Alignment
(Результаты) Alignment
LegacyJIT-x64 Mono
S3 ≈1276ns ≈1146ns
S8 ≈241ns ≈2232ns
Marshal.SizeOf(typeof(S3)) 3 8
35/79 7. Поговорим про Alignment
Часть 8
Поговорим про Struct promotion
36/79 8. Поговорим про Struct promotion
(Бенчмарк) Struct promotion
// А что будет под RyuJIT-x64?
[Benchmark] public int S3() {
int res = 0;
for (int i = 0; i < struct3.Length; i++) {
var s = struct3[i]; res += s.X1 + s.X2;
}
return res;
}
[Benchmark] public int S8() {
int res = 0;
for (int i = 0; i < struct8.Length; i++) {
var s = struct8[i]; res += s.X1 + s.X2;
}
return res;
}
37/79 8. Поговорим про Struct promotion
(Результаты) Struct promotion
RyuJIT-x64
S3 ≈280ns
S8 ≈280ns
38/79 8. Поговорим про Struct promotion
(Смотрим ASM) Struct promotion
; *** S3 ***
; res += s.X1 + s.X2;
add eax, r10d
add eax, r9d
; *** S8 ***
; res += s.X1 + s.X2;
movzx r9d, byte ptr [rsp+20h]
add eax, r9d
movzx r9d, byte ptr [rsp+21h]
add eax, r9d
39/79 8. Поговорим про Struct promotion
(Текущая реализация) Struct promotion
Иногда RyuJIT1 может аллоцировать структуру
в регистрах, а не на стеке
• The struct must not be address-taken.
• It must have no overlapping fields.
• It must have only primitive fields.
• It must not be an argument or a return value that is passed in
registers.
• It can’t be larger than 32 bytes.
• It can’t have more than 4 fields.
1
Справедливо для v4.6.1637.0, поведение может поменяться, см. coreclr#6733
40/79 8. Поговорим про Struct promotion
Часть 9
Поговорим про Prefetching
41/79 9. Поговорим про Prefetching
(Бенчмарк) Prefetching
// Подготавливаем данные
int[] data = new int[32 * 1024 * 1024];
int[] next = new int[32 * 1024 * 1024];
int n = 2000;
42/79 9. Поговорим про Prefetching
(Бенчмарк) Prefetching
// Подготавливаем данные
int[] data = new int[32 * 1024 * 1024];
int[] next = new int[32 * 1024 * 1024];
int n = 2000;
var random = new Random(42);
for (int i = 0; i < data.Length; i++)
data[i] = random.Next();
for (int i = 0; i < next.Length; i++)
next[i] = random.Next(data.Length);
42/79 9. Поговорим про Prefetching
(Бенчмарк) Prefetching
// CPU-bound method
[MethodImpl(MethodImplOptions.NoInlining)]
private static int IsNice(int x) {
if (x % 13 == 0 | x % 17 == 0 |
x % 19 == 0 | x % 43 == 0 |
x % 71 == 0 | x % 101 == 0 |
x % 233 == 0 | x % 383 == 0 |
x % 479 == 0 | x % 541 == 0)
return 1;
return 0;
}
43/79 9. Поговорим про Prefetching
(Бенчмарк) Prefetching
[Benchmark]
public int Simple() {
var res = 0;
var index = 0;
for (int i = 0; i < n; i++) {
index = next[index];
var x = data[index];
res += IsNice(x);
}
return res;
}
44/79 9. Поговорим про Prefetching
(Бенчмарк) Prefetching
[Benchmark]
public int Simple() Prefetch() {
var res = 0;
var index = 0; next[0]; var y = data[index];
for (int i = 0; i < n; i++) {
index = next[index]; var x = y;
var x = data[index]; index = next[index]; y = data[index];
res += IsNice(x);
}
return res;
}
45/79 9. Поговорим про Prefetching
(Результаты) Prefetching
Simple ≈161µs
Prefetch ≈96µs
Windows 10, .NET 4.6.2, LegacyJIT-x86, Haswell
46/79 9. Поговорим про Prefetching
(Минутка занимательного) Prefetching
Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual:
3.7.2. Hardware Prefetching for First-Level Data Cache
The additional instructions to load data from one member in the modified
sequence can trigger the DCU hardware prefetch mechanisms to prefetch
data in the next cache line, enabling the work on the second member to
complete sooner.
; Without prefetching
mov eax, [ebx+4]
; With prefetching
mov eax, [ebx+4]
mov eax, [ebx+4]
mov eax, [ebx+4]
47/79 9. Поговорим про Prefetching
Часть 10
Поговорим про 4K aliasing
48/79 10. Поговорим про 4K aliasing
Store forwarding
49/79 10. Поговорим про 4K aliasing
Store forwarding
50/79 10. Поговорим про 4K aliasing
Store forwarding
51/79 10. Поговорим про 4K aliasing
Store forwarding
52/79 10. Поговорим про 4K aliasing
Выравниванием доступ к памяти на 4KB
byte[] data = new byte[32 * 1024 * 1024];
int baseOffset; // Хотим выровнять на 4KB
53/79 10. Поговорим про 4K aliasing
Выравниванием доступ к памяти на 4KB
byte[] data = new byte[32 * 1024 * 1024];
int baseOffset; // Хотим выровнять на 4KB
GCHandle handle = GCHandle.Alloc(data,
GCHandleType.Pinned);
IntPtr addrOfObject = handle.AddrOfPinnedObject();
53/79 10. Поговорим про 4K aliasing
Выравниванием доступ к памяти на 4KB
byte[] data = new byte[32 * 1024 * 1024];
int baseOffset; // Хотим выровнять на 4KB
GCHandle handle = GCHandle.Alloc(data,
GCHandleType.Pinned);
IntPtr addrOfObject = handle.AddrOfPinnedObject();
long address = addrOfObject.ToInt64();
const int align = 4 * 1024; // 4KB
baseOffset = ((int) (align - (address % (align))));
53/79 10. Поговорим про 4K aliasing
(Бенчмарк) 4K aliasing
public int StrideOffset; // [Params]
[Benchmark]
public void ArrayCopy() => Array.Copy(
sourceArray: data,
sourceIndex: baseOffset,
destinationArray: data,
destinationIndex: baseOffset +
24 * 1024 + StrideOffset, //24KB
length: 16 * 1024); //16KB
54/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
55/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
-33 ≈390ns Unaligned
55/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
-33 ≈390ns Unaligned
-32 ≈330ns Aligned
55/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
-33 ≈390ns Unaligned
-32 ≈330ns Aligned
-31 ≈390ns Unaligned
-1 ≈390ns Unaligned
55/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
-33 ≈390ns Unaligned
-32 ≈330ns Aligned
-31 ≈390ns Unaligned
-1 ≈390ns Unaligned
0 ≈290ns Aligned
55/79 10. Поговорим про 4K aliasing
(Результаты) 4K aliasing
StrideOffset Haswell Comment
-33 ≈390ns Unaligned
-32 ≈330ns Aligned
-31 ≈390ns Unaligned
-1 ≈390ns Unaligned
0 ≈290ns Aligned
1 ≈1250ns 4K aliasing
2 ≈1250ns 4K aliasing
31 ≈1250ns 4K aliasing
55/79 10. Поговорим про 4K aliasing
Rider: взгляд из VTune Amplifier
56/79 10. Поговорим про 4K aliasing
(Мануал) 4K aliasing
Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual:
11.8. 4K ALIASING
To resolve 4K aliasing, try the following methods in the following order:
• Align data to 32 Bytes.
• Change offsets between input and output buffers if possible.
• Use 16-Byte memory accesses on memory which is not 32-Byte
aligned.
57/79 10. Поговорим про 4K aliasing
Часть 11
Поговорим про GC
58/79 11. Поговорим про GC
GC: перфомансные кредиты
59/79 11. Поговорим про GC
Секретная Rider-фича
60/79 11. Поговорим про GC
Факты об одном эксперименте
61/79 11. Поговорим про GC
Факты об одном эксперименте
• Среднестатистический working set после
загрузки: 566MB.
61/79 11. Поговорим про GC
Факты об одном эксперименте
• Среднестатистический working set после
загрузки: 566MB.
• Большинство людей имеют больше
среднестатистического количества ног.
61/79 11. Поговорим про GC
Посмотрим на распределение
62/79 11. Поговорим про GC
Посмотрим на снэпшот
63/79 11. Поговорим про GC
Посмотрим на код
var myListener = new HttpListener();
// ...
while (myListener.IsListening)
{
HttpListenerContext ctx = null;
try
{
ctx = myListener.GetContext(); // А что внутри?
string rstr = ProcessRequest(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
// ...
}
64/79 11. Поговорим про GC
Продолжаем смотреть на код
65/79 11. Поговорим про GC
Продолжаем смотреть на код
66/79 11. Поговорим про GC
Часть 12
Поговорим про LOH
67/79 12. Поговорим про LOH
Поговорим про LOH
Справедливо для Full .NET Framework, .NET Core
68/79 12. Поговорим про LOH
(Бенчмарк) LOH
public class ChunkedArray // Чудо-класс, который
{ // спасает от LOH
private readonly List<object[]> arrays;
public ChunkedArray(int n, int chunkSize)
{
arrays = new List<object[]>();
while (n > 0)
{
var size = Math.Min(n, chunkSize / IntPtr.Size);
arrays.Add(new object[size]);
n -= size;
}
}
}
69/79 12. Поговорим про LOH
(Бенчмарк) LOH
public class Node // Вспомогательный класс,
{ // который поможет нам бенчмаркать
public ChunkedArray Array { get; }
public Node Next { get; }
public int X;
public Node(ChunkedArray array, Node next)
{
Array = array;
Next = next;
}
// Очень полезный финализатор
~Node() => X++;
}
70/79 12. Поговорим про LOH
(Бенчмарк) LOH
// *** Allocate ***
var node = new Node(new ChunkedArray(N, ChunkSize),
null);
for (int i = 0; i < 1000; i++)
node = new Node(new ChunkedArray(N, ChunkSize),
(i % 50 == 0) ? null : node);
71/79 12. Поговорим про LOH
(Бенчмарк) LOH
// *** Allocate ***
var node = new Node(new ChunkedArray(N, ChunkSize),
null);
for (int i = 0; i < 1000; i++)
node = new Node(new ChunkedArray(N, ChunkSize),
(i % 50 == 0) ? null : node);
// *** Force Collect (.NET 4.5.1+) ***
GCSettings.LargeObjectHeapCompactionMode =
GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
GC.WaitForPendingFinalizers();
71/79 12. Поговорим про LOH
(Результаты) LOH
Аллоцируем много больших объектов,
собираем мусор и замеряем время:
ChunkSize Full Framework Mono
80000 ≈3.3s ≈2.0s
Windows 10, .NET 4.6.2, RyuJIT-x64, Mono 4.6.2, Skylake
72/79 12. Поговорим про LOH
(Результаты) LOH
Аллоцируем много больших объектов,
собираем мусор и замеряем время:
ChunkSize Full Framework Mono
80000 ≈3.3s ≈2.0s
∞ ≈1.9s ≈1.5s
Windows 10, .NET 4.6.2, RyuJIT-x64, Mono 4.6.2, Skylake
72/79 12. Поговорим про LOH
Выводы
По данному бенчмарку:
73/79 12. Поговорим про LOH
Выводы
По данному бенчмарку:
• Нельзя делать выводы о рантаймах
73/79 12. Поговорим про LOH
Выводы
По данному бенчмарку:
• Нельзя делать выводы о рантаймах
• Нельзя делать выводы о том, что же
использовать в продакшене
73/79 12. Поговорим про LOH
Выводы
По данному бенчмарку:
• Нельзя делать выводы о рантаймах
• Нельзя делать выводы о том, что же
использовать в продакшене
• Вообще нельзя так бенчмаркать GC,
пример слишком академический
73/79 12. Поговорим про LOH
Почему Rider всё ещё использует чанки?
74/79 12. Поговорим про LOH
Почему Rider всё ещё использует чанки?
Нельзя просто так взять и начать
рефакторить legacy
Нужно подумать про:
74/79 12. Поговорим про LOH
Почему Rider всё ещё использует чанки?
Нельзя просто так взять и начать
рефакторить legacy
Нужно подумать про:
• Разные ОС и рантаймы
74/79 12. Поговорим про LOH
Почему Rider всё ещё использует чанки?
Нельзя просто так взять и начать
рефакторить legacy
Нужно подумать про:
• Разные ОС и рантаймы
• Разные нагрузки и сценарии
74/79 12. Поговорим про LOH
Почему Rider всё ещё использует чанки?
Нельзя просто так взять и начать
рефакторить legacy
Нужно подумать про:
• Разные ОС и рантаймы
• Разные нагрузки и сценарии
• Целевые метрики: latency, footprint
74/79 12. Поговорим про LOH
По уши в свопе
75/79 12. Поговорим про LOH
Часть 13
Заключение
76/79 13. Заключение
Заключение
Для memory-bound бенчмаркинга нужно много
понимать
• Общая методология
(размер рабочей памяти, паттерны доступа и всё такое)
• Устройство железа и рантаймов
• Пользовательские сценарии
77/79 13. Заключение
Заключение
Для memory-bound бенчмаркинга нужно много
понимать
• Общая методология
(размер рабочей памяти, паттерны доступа и всё такое)
• Устройство железа и рантаймов
• Пользовательские сценарии
Напоминания
• Это был доклад о замерах, а не об оптимизациях
• В большинстве случаев всё не так уж и плохо
77/79 13. Заключение
Методическая литература
• Intel® 64 and IA-32 Architectures Optimization Reference Manual
• An optimization guide for assembly programmers and compiler makers
• What Every Programmer Should Know About Memory
78/79 13. Заключение
Вопросы?
Андрей Акиньшин
http://aakinshin.net
https://github.com/AndreyAkinshin
https://twitter.com/andrey_akinshin
andrey.akinshin@gmail.com
79/79 13. Заключение
1 of 116

Recommended

Франкенштейнизация Voldemort или key-value данные в Одноклассниках. Роман Ан... by
Франкенштейнизация Voldemort или key-value данные в Одноклассниках. Роман Ан...Франкенштейнизация Voldemort или key-value данные в Одноклассниках. Роман Ан...
Франкенштейнизация Voldemort или key-value данные в Одноклассниках. Роман Ан...odnoklassniki.ru
1.6K views28 slides
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков... by
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...
как написать масштабируемую баннерокрутилку. денис бирюков, артем гавриченков...rit2011
3K views68 slides
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве... by
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...odnoklassniki.ru
2.5K views50 slides
Платформа для видео сроком в квартал. Александр Тоболь. by
Платформа для видео сроком в квартал. Александр Тоболь.Платформа для видео сроком в квартал. Александр Тоболь.
Платформа для видео сроком в квартал. Александр Тоболь.odnoklassniki.ru
5.5K views46 slides
Кадры решают все, или стриминг видео в «Одноклассниках». Александр Тоболь by
Кадры решают все, или стриминг видео в «Одноклассниках». Александр ТобольКадры решают все, или стриминг видео в «Одноклассниках». Александр Тоболь
Кадры решают все, или стриминг видео в «Одноклассниках». Александр Тобольodnoklassniki.ru
2.3K views44 slides
Cpp by
CppCpp
CppMax Klyga
423 views58 slides

More Related Content

What's hot

Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве... by
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Ontico
2K views50 slides
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta... by
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Ontico
2.9K views52 slides
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2 by
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2rit2011
757 views61 slides
Класс!ная Cassandra by
Класс!ная CassandraКласс!ная Cassandra
Класс!ная Cassandraodnoklassniki.ru
4.6K views45 slides
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C... by
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Ontico
1.9K views48 slides
Java Platform Performance BoF by
Java Platform Performance BoFJava Platform Performance BoF
Java Platform Performance BoFDmitry Buzdin
2.7K views49 slides

What's hot(20)

Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве... by Ontico
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных серве...
Ontico2K views
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta... by Ontico
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Что особенного в СУБД для данных в оперативной памяти / Константин Осипов (Ta...
Ontico2.9K views
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2 by rit2011
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2
rit2011757 views
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C... by Ontico
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Chronicle Map — key-value хранилище для трейдинга на Java / Левентов Роман (C...
Ontico1.9K views
Java Platform Performance BoF by Dmitry Buzdin
Java Platform Performance BoFJava Platform Performance BoF
Java Platform Performance BoF
Dmitry Buzdin2.7K views
DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel) by Ontico
DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel)DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel)
DPDK в виртуальном коммутаторе Open vSwitch / Александр Джуринский (Selectel)
Ontico776 views
За гранью NoSQL: NewSQL на Cassandra by odnoklassniki.ru
За гранью NoSQL: NewSQL на CassandraЗа гранью NoSQL: NewSQL на Cassandra
За гранью NoSQL: NewSQL на Cassandra
odnoklassniki.ru7K views
Caching data outside Java Heap and using Shared Memory in Java by Andrei Pangin
Caching data outside Java Heap and using Shared Memory in JavaCaching data outside Java Heap and using Shared Memory in Java
Caching data outside Java Heap and using Shared Memory in Java
Andrei Pangin1.7K views
Марина Широчкина: Верстка. Вид снизу by Yandex
Марина Широчкина: Верстка. Вид снизуМарина Широчкина: Верстка. Вид снизу
Марина Широчкина: Верстка. Вид снизу
Yandex7.3K views
Александр Крижановский, NatSys Lab by Ontico
Александр Крижановский, NatSys LabАлександр Крижановский, NatSys Lab
Александр Крижановский, NatSys Lab
Ontico2.4K views
Опыт внедрения и использования распределенной системы хранения данных на осно... by tfmailru
Опыт внедрения и использования распределенной системы хранения данных на осно...Опыт внедрения и использования распределенной системы хранения данных на осно...
Опыт внедрения и использования распределенной системы хранения данных на осно...
tfmailru1.5K views
Чему мы научились разрабатывая микросервисы? by Vadim Madison
Чему мы научились разрабатывая микросервисы?Чему мы научились разрабатывая микросервисы?
Чему мы научились разрабатывая микросервисы?
Vadim Madison415 views
Как обслужить 60 миллионов абонентов, Артем Руфанов (ПЕТЕР-СЕРВИС) by Ontico
Как обслужить 60 миллионов абонентов, Артем Руфанов (ПЕТЕР-СЕРВИС)Как обслужить 60 миллионов абонентов, Артем Руфанов (ПЕТЕР-СЕРВИС)
Как обслужить 60 миллионов абонентов, Артем Руфанов (ПЕТЕР-СЕРВИС)
Ontico2.5K views
Игнат Корчагин "Как Cloudflare помогает справиться с крупнейшими атаками в Сети" by Fwdays
Игнат Корчагин "Как Cloudflare помогает справиться с крупнейшими атаками в Сети"Игнат Корчагин "Как Cloudflare помогает справиться с крупнейшими атаками в Сети"
Игнат Корчагин "Как Cloudflare помогает справиться с крупнейшими атаками в Сети"
Fwdays748 views
Тюним память и сетевой стек в Linux: история перевода высоконагруженных сер... by Dmitry Samsonov
Тюним память  и сетевой стек в Linux: история перевода высоконагруженных  сер...Тюним память  и сетевой стек в Linux: история перевода высоконагруженных  сер...
Тюним память и сетевой стек в Linux: история перевода высоконагруженных сер...
Dmitry Samsonov458 views
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe... by Ontico
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...
Tempesta FW: challenges, internals, use cases / Александр Крижановский (Tempe...
Ontico1.2K views
Евгений Потапов (Сумма Айти) by Ontico
Евгений Потапов (Сумма Айти)Евгений Потапов (Сумма Айти)
Евгений Потапов (Сумма Айти)
Ontico1.7K views
Резервное копирование MySQL в экстремальных условиях by Sveta Smirnova
Резервное копирование MySQL в экстремальных условияхРезервное копирование MySQL в экстремальных условиях
Резервное копирование MySQL в экстремальных условиях
Sveta Smirnova1.3K views

Similar to Поговорим про память

Low-level C/C++ Optimization by Anrew Axenov (Sphinx) by
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)Vadim Kosov
364 views58 slides
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013 by
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Unigine Corp.
779 views58 slides
Семинар 5. Многопоточное программирование на OpenMP (часть 5) by
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Mikhail Kurnosov
816 views27 slides
How to cook a blockchain and not get burned by
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
36 views92 slides
Реактивный раздатчик ok.ru/music by
Реактивный раздатчик ok.ru/musicРеактивный раздатчик ok.ru/music
Реактивный раздатчик ok.ru/musicVadim Tsesko
213 views153 slides
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library by
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryTatyanazaxarova
162 views8 slides

Similar to Поговорим про память(20)

Low-level C/C++ Optimization by Anrew Axenov (Sphinx) by Vadim Kosov
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Low-level C/C++ Optimization by Anrew Axenov (Sphinx)
Vadim Kosov364 views
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013 by Unigine Corp.
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Низкоуровневые оптимизации. Андрей Аксенов. Unigine Open Air 2013
Unigine Corp. 779 views
Семинар 5. Многопоточное программирование на OpenMP (часть 5) by Mikhail Kurnosov
Семинар 5. Многопоточное программирование на OpenMP (часть 5)Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Семинар 5. Многопоточное программирование на OpenMP (часть 5)
Mikhail Kurnosov816 views
Реактивный раздатчик ok.ru/music by Vadim Tsesko
Реактивный раздатчик ok.ru/musicРеактивный раздатчик ok.ru/music
Реактивный раздатчик ok.ru/music
Vadim Tsesko213 views
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library by Tatyanazaxarova
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Tatyanazaxarova162 views
Доклад на Highload-2012 by Alex Tutubalin
Доклад на Highload-2012Доклад на Highload-2012
Доклад на Highload-2012
Alex Tutubalin3.1K views
Эффективное использование x86-совместимых CPU (Алексей Тутубалин) by Ontico
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Эффективное использование x86-совместимых CPU (Алексей Тутубалин)
Ontico1.3K views
Smirnov Memcached High Load 2008 by Ontico
Smirnov Memcached High Load 2008Smirnov Memcached High Load 2008
Smirnov Memcached High Load 2008
Ontico988 views
Smirnov Memcached Highload 2008 by Ontico
Smirnov Memcached Highload 2008Smirnov Memcached Highload 2008
Smirnov Memcached Highload 2008
Ontico557 views
Михаил Щербаков "WinDbg сотоварищи" by Mikhail Shcherbakov
Михаил Щербаков "WinDbg сотоварищи"Михаил Щербаков "WinDbg сотоварищи"
Михаил Щербаков "WinDbg сотоварищи"
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro by it-people
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
"Мультимастер для PostgreSQL" Кельвич Станислав, Книжник Константин, PostgresPro
it-people267 views
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse" by Fwdays
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Fwdays232 views
Погружение в виртуальную память и большие страницы / Константин Новаковский (... by Ontico
Погружение в виртуальную память и большие страницы / Константин Новаковский (...Погружение в виртуальную память и большие страницы / Константин Новаковский (...
Погружение в виртуальную память и большие страницы / Константин Новаковский (...
Ontico585 views
WinDbg со товарищи by CUSTIS
WinDbg со товарищиWinDbg со товарищи
WinDbg со товарищи
CUSTIS150 views
Developing highload servers with Java by Andrei Pangin
Developing highload servers with JavaDeveloping highload servers with Java
Developing highload servers with Java
Andrei Pangin1.2K views
Внутреннее устройство PostgreSQL: временные таблицы и фрагментация памяти / Г... by Ontico
Внутреннее устройство PostgreSQL: временные таблицы и фрагментация памяти / Г...Внутреннее устройство PostgreSQL: временные таблицы и фрагментация памяти / Г...
Внутреннее устройство PostgreSQL: временные таблицы и фрагментация памяти / Г...
Ontico2.5K views
Флеш в серверах: работа со скоростью вспышки by КРОК
Флеш в серверах: работа со скоростью вспышкиФлеш в серверах: работа со скоростью вспышки
Флеш в серверах: работа со скоростью вспышки
КРОК370 views
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев) by Ontico
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Практика использования NoSQL в высоконагруженном проекте (Дмитрий Ананьев)
Ontico2.6K views

More from Andrey Akinshin

Поговорим про performance-тестирование by
Поговорим про performance-тестированиеПоговорим про performance-тестирование
Поговорим про performance-тестированиеAndrey Akinshin
368 views105 slides
Сложности performance-тестирования by
Сложности performance-тестированияСложности performance-тестирования
Сложности performance-тестированияAndrey Akinshin
277 views91 slides
Сложности микробенчмаркинга by
Сложности микробенчмаркингаСложности микробенчмаркинга
Сложности микробенчмаркингаAndrey Akinshin
521 views66 slides
Кроссплатформенный .NET и как там дела с Mono и CoreCLR by
Кроссплатформенный .NET и как там дела с Mono и CoreCLRКроссплатформенный .NET и как там дела с Mono и CoreCLR
Кроссплатформенный .NET и как там дела с Mono и CoreCLRAndrey Akinshin
322 views32 slides
Теория и практика .NET-бенчмаркинга (25.01.2017, Москва) by
 Теория и практика .NET-бенчмаркинга (25.01.2017, Москва) Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)
Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)Andrey Akinshin
3.6K views153 slides
Продолжаем говорить про арифметику by
Продолжаем говорить про арифметикуПродолжаем говорить про арифметику
Продолжаем говорить про арифметикуAndrey Akinshin
676 views83 slides

More from Andrey Akinshin(20)

Поговорим про performance-тестирование by Andrey Akinshin
Поговорим про performance-тестированиеПоговорим про performance-тестирование
Поговорим про performance-тестирование
Andrey Akinshin368 views
Сложности performance-тестирования by Andrey Akinshin
Сложности performance-тестированияСложности performance-тестирования
Сложности performance-тестирования
Andrey Akinshin277 views
Сложности микробенчмаркинга by Andrey Akinshin
Сложности микробенчмаркингаСложности микробенчмаркинга
Сложности микробенчмаркинга
Andrey Akinshin521 views
Кроссплатформенный .NET и как там дела с Mono и CoreCLR by Andrey Akinshin
Кроссплатформенный .NET и как там дела с Mono и CoreCLRКроссплатформенный .NET и как там дела с Mono и CoreCLR
Кроссплатформенный .NET и как там дела с Mono и CoreCLR
Andrey Akinshin322 views
Теория и практика .NET-бенчмаркинга (25.01.2017, Москва) by Andrey Akinshin
 Теория и практика .NET-бенчмаркинга (25.01.2017, Москва) Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)
Теория и практика .NET-бенчмаркинга (25.01.2017, Москва)
Andrey Akinshin3.6K views
Продолжаем говорить про арифметику by Andrey Akinshin
Продолжаем говорить про арифметикуПродолжаем говорить про арифметику
Продолжаем говорить про арифметику
Andrey Akinshin676 views
Let’s talk about microbenchmarking by Andrey Akinshin
Let’s talk about microbenchmarkingLet’s talk about microbenchmarking
Let’s talk about microbenchmarking
Andrey Akinshin598 views
Теория и практика .NET-бенчмаркинга (02.11.2016, Екатеринбург) by Andrey Akinshin
Теория и практика .NET-бенчмаркинга (02.11.2016, Екатеринбург)Теория и практика .NET-бенчмаркинга (02.11.2016, Екатеринбург)
Теория и практика .NET-бенчмаркинга (02.11.2016, Екатеринбург)
Andrey Akinshin1.4K views
Поговорим про арифметику by Andrey Akinshin
Поговорим про арифметикуПоговорим про арифметику
Поговорим про арифметику
Andrey Akinshin120.8K views
Подружили CLR и JVM в Project Rider by Andrey Akinshin
Подружили CLR и JVM в Project RiderПодружили CLR и JVM в Project Rider
Подружили CLR и JVM в Project Rider
Andrey Akinshin794 views
Что нам готовит грядущий C#7? by Andrey Akinshin
Что нам готовит грядущий C#7?Что нам готовит грядущий C#7?
Что нам готовит грядущий C#7?
Andrey Akinshin376 views
.NET 2015: Будущее рядом by Andrey Akinshin
.NET 2015: Будущее рядом.NET 2015: Будущее рядом
.NET 2015: Будущее рядом
Andrey Akinshin538 views
Продолжаем говорить о микрооптимизациях .NET-приложений by Andrey Akinshin
Продолжаем говорить о микрооптимизациях .NET-приложенийПродолжаем говорить о микрооптимизациях .NET-приложений
Продолжаем говорить о микрооптимизациях .NET-приложений
Andrey Akinshin665 views
Распространённые ошибки оценки производительности .NET-приложений by Andrey Akinshin
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
Andrey Akinshin1K views
Поговорим о микрооптимизациях .NET-приложений by Andrey Akinshin
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложений
Andrey Akinshin855 views
Практические приёмы оптимизации .NET-приложений by Andrey Akinshin
Практические приёмы оптимизации .NET-приложенийПрактические приёмы оптимизации .NET-приложений
Практические приёмы оптимизации .NET-приложений
Andrey Akinshin2.4K views
Поговорим о различных версиях .NET by Andrey Akinshin
Поговорим о различных версиях .NETПоговорим о различных версиях .NET
Поговорим о различных версиях .NET
Andrey Akinshin726 views
Низкоуровневые оптимизации .NET-приложений by Andrey Akinshin
Низкоуровневые оптимизации .NET-приложенийНизкоуровневые оптимизации .NET-приложений
Низкоуровневые оптимизации .NET-приложений
Andrey Akinshin3.8K views
Основы работы с Git by Andrey Akinshin
Основы работы с GitОсновы работы с Git
Основы работы с Git
Andrey Akinshin3.8K views
Сборка мусора в .NET by Andrey Akinshin
Сборка мусора в .NETСборка мусора в .NET
Сборка мусора в .NET
Andrey Akinshin3.9K views

Поговорим про память

  • 1. Поговорим про память Андрей Акиньшин, JetBrains DotNext 2017 SPb 1/79
  • 2. Часть 1 О чём будем разговаривать? 2/79 1. О чём будем разговаривать?
  • 3. Мотивация Хотим, чтобы программы работали очень быстро и кушали мало памяти! 3/79 1. О чём будем разговаривать?
  • 4. Знай свой bottleneck 4/79 1. О чём будем разговаривать?
  • 5. Знай свой bottleneck • CPU • Database • I/O • Network • Concurrency • . . . • Main memory (вот про неё и будем разговаривать) 5/79 1. О чём будем разговаривать?
  • 6. История одной оптимизации 6/79 1. О чём будем разговаривать?
  • 7. История одной оптимизации Делаем замер времени (один) до и после: До 50ms После 45ms 6/79 1. О чём будем разговаривать?
  • 8. История одной оптимизации Делаем замер времени (один) до и после: До 50ms После 45ms Вопрос: а стало ли лучше? 6/79 1. О чём будем разговаривать?
  • 9. Посмотрим на распределения 7/79 1. О чём будем разговаривать?
  • 10. Краткое содержание доклада Сегодня мы узнаем: • Из чего складывается производительность памяти? • 10 способов написать некорректный memory benchmark 8/79 1. О чём будем разговаривать?
  • 11. Краткое содержание доклада Сегодня мы узнаем: • Из чего складывается производительность памяти? • 10 способов написать некорректный memory benchmark Обсуждаемые темы: • CPU Cache (cache line size, associativity, . . . ) • Cache Bank Conflicts • Alignment • Struct Promotion • Prefetching • Store forwarding; 4K aliasing • Трудности работы с GC и pinned objects • Large Object Heap; Full Framework vs Mono 8/79 1. О чём будем разговаривать?
  • 13. Отказ от ответственности Нужно понимать • Все примеры академические, нужны для иллюстрации идей • Погрешности малы, для целей доклада ими можно пренебречь • На вашем железе цифры могут быть другие, это нормально Подопытное железо • Ivy Bridge Core i7-3632QM CPU 2.20GHz • Haswell Core i7-4702MQ CPU 2.20GHz • Skylake Core i7-6700HQ CPU 2.60GHz Информация о бенчмарках • BenchmarkDotNet v0.10.6 (supported by the .NET Foundation) • Gist с исходниками: https://git.io/v9dV8 10/79 2. Введение
  • 14. Давайте позамеряем время! // Инициализируем собственную хешмапу var dict = new MyAwesomeDictionary<int, int>(); dict.Put(0, 0); 11/79 2. Введение
  • 15. Давайте позамеряем время! // Инициализируем собственную хешмапу var dict = new MyAwesomeDictionary<int, int>(); dict.Put(0, 0); // А теперь немного побенчмаркаем: var sw = Stopwatch.StartNew(); for (int i = 0; i < 1000000; i++) dict.Get(0); sw.Stop(); WriteLine(sw.Elapsed); 11/79 2. Введение
  • 16. Давайте позамеряем время! // Инициализируем собственную хешмапу var dict = new MyAwesomeDictionary<int, int>(); dict.Put(0, 0); // А теперь немного побенчмаркаем: var sw = Stopwatch.StartNew(); for (int i = 0; i < 1000000; i++) dict.Get(0); sw.Stop(); WriteLine(sw.Elapsed); Есть ли проблемы с этим бенчмарком? 11/79 2. Введение
  • 17. Нужно правильно дизайнить memory-бенчмарки 12/79 2. Введение
  • 18. Нужно правильно дизайнить memory-бенчмарки Пробуйте разные паттерны доступа к памяти • Последовательный доступ • Случайный доступ • Пользовательский сценарий • “Хитрые” случаи 12/79 2. Введение
  • 19. Нужно правильно дизайнить memory-бенчмарки Пробуйте разные паттерны доступа к памяти • Последовательный доступ • Случайный доступ • Пользовательский сценарий • “Хитрые” случаи Пробуйте разные размеры рабочей памяти • Очень маленький • Очень большой • Значения, близкие к размеру L1, L2, L3 12/79 2. Введение
  • 20. Часть 3 Поговорим про CPU Cache 13/79 3. Поговорим про CPU Cache
  • 21. Доступ к памяти — это вам не константа! 14/79 3. Поговорим про CPU Cache
  • 22. (Бенчмарк) CPU Cache /* Сколько стоит сделать N инкрементов? */ private const int N = 16 * 1024 * 1024; private byte[] data; [Params(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 6144, 8192, 16384, 32768)] public int SizeKb; [Setup] public void Setup() => data = new byte[SizeKb * 1024]; [Benchmark] public void Calc() { var mask = data.Length - 1; for (int i = 0; i < N; i++) // Бегаем по массиву с шагом в 64B data[(i * 64) & mask]++; // И тыкаемся в элементы } Windows 10, .NET 4.6.2, LegacyJIT-x86 15/79 3. Поговорим про CPU Cache
  • 23. (Результаты) CPU Cache Сколько стоит сделать N инкрементов? Cache Level Ivy Bridge Skylake 16/79 3. Поговорим про CPU Cache
  • 24. (Результаты) CPU Cache Сколько стоит сделать N инкрементов? Cache Level Ivy Bridge Skylake 4 KB L1 ≈20ms ≈18ms 8 KB ≈20ms ≈18ms 16 KB ≈20ms ≈18ms 32 KB ≈20ms ≈18ms 16/79 3. Поговорим про CPU Cache
  • 25. (Результаты) CPU Cache Сколько стоит сделать N инкрементов? Cache Level Ivy Bridge Skylake 4 KB L1 ≈20ms ≈18ms 8 KB ≈20ms ≈18ms 16 KB ≈20ms ≈18ms 32 KB ≈20ms ≈18ms 64 KB L2 ≈36ms ≈22ms 128 KB ≈36ms ≈22ms 256 KB ≈36ms ≈22ms 16/79 3. Поговорим про CPU Cache
  • 26. (Результаты) CPU Cache Сколько стоит сделать N инкрементов? Cache Level Ivy Bridge Skylake 4 KB L1 ≈20ms ≈18ms 8 KB ≈20ms ≈18ms 16 KB ≈20ms ≈18ms 32 KB ≈20ms ≈18ms 64 KB L2 ≈36ms ≈22ms 128 KB ≈36ms ≈22ms 256 KB ≈36ms ≈22ms 512 KB L3 ≈50ms ≈36ms 1 MB ≈50ms ≈36ms 2 MB ≈50ms ≈36ms 4 MB ≈54ms ≈40ms 6 MB ≈54ms ≈40ms 16/79 3. Поговорим про CPU Cache
  • 27. (Результаты) CPU Cache Сколько стоит сделать N инкрементов? Cache Level Ivy Bridge Skylake 4 KB L1 ≈20ms ≈18ms 8 KB ≈20ms ≈18ms 16 KB ≈20ms ≈18ms 32 KB ≈20ms ≈18ms 64 KB L2 ≈36ms ≈22ms 128 KB ≈36ms ≈22ms 256 KB ≈36ms ≈22ms 512 KB L3 ≈50ms ≈36ms 1 MB ≈50ms ≈36ms 2 MB ≈50ms ≈36ms 4 MB ≈54ms ≈40ms 6 MB ≈54ms ≈40ms 8 MB RAM ≈80ms ≈70ms 16 MB ≈102ms ≈80ms 32 MB ≈108ms ≈83ms 16/79 3. Поговорим про CPU Cache
  • 28. Часть 4 Поговорим про CPU Cache Levels 17/79 4. Поговорим про CPU Cache Levels
  • 29. (Схематическое устройство) CPU Cache Levels CPU0 CPU1 CPU2 CPU3 L1 L1 L1 L1 L2 L2 L2 L2 L3 18/79 4. Поговорим про CPU Cache Levels
  • 30. (Бенчмарк) CPU Cache Levels private const int N = 16 * 1024 * 1024; private byte[] data; [Params(2048, 4096, 6144)] // Нагрузка на L3 public int SizeKb; [Setup] public void Setup() => data = new byte[SizeKb * 1024]; [Benchmark] public void Calc() { var mask = data.Length - 1; for (int i = 0; i < N; i++) data[(i * 64) & mask]++; } Windows 10, .NET 4.6.2, LegacyJIT-x86, Skylake 19/79 4. Поговорим про CPU Cache Levels
  • 31. (Результаты) CPU Cache Levels Условия Mean Min Max 2 MB Стерильные 35.38ms 34.92ms 36.08ms 4 MB 39.49ms 39.01ms 40.06ms 6 MB 40.44ms 39.87ms 40.92ms 20/79 4. Поговорим про CPU Cache Levels
  • 32. (Результаты) CPU Cache Levels Условия Mean Min Max 2 MB Стерильные 35.38ms 34.92ms 36.08ms 4 MB 39.49ms 39.01ms 40.06ms 6 MB 40.44ms 39.87ms 40.92ms 2 MB Firefox, Rider, IDEA, TEXstudio, Dropbox, GoogleDrive, . . . 44.50ms 36.75ms 52.34ms 4 MB 97.64ms 63.14ms 172.74ms 6 MB 75.02ms 42.07ms 154.55ms 20/79 4. Поговорим про CPU Cache Levels
  • 33. (Распределение) CPU Cache Levels 21/79 4. Поговорим про CPU Cache Levels
  • 34. Часть 5 Поговорим про CPU Cache Associativity 22/79 5. Поговорим про CPU Cache Associativity
  • 35. (Бенчмарк) CPU Cache Associativity private int[,] a; [Params(511, 512, 513)] public int N; [Setup] public void Setup() => a = new int[N, N]; // Ищем максимальный элемент в колонке [Benchmark] public int Max() { int max = 0; for (int i = 0; i < N; i++) max = Math.Max(max, a[i, 0]); return max; } Windows 10, .NET 4.6.2, LegacyJIT-x86, Skylake 23/79 5. Поговорим про CPU Cache Associativity
  • 36. (Результаты) CPU Cache Associativity N Max 511 ≈844ns 512 ≈1330ns 513 ≈844ns 24/79 5. Поговорим про CPU Cache Associativity
  • 37. (Теория) CPU Cache Associativity 25/79 5. Поговорим про CPU Cache Associativity
  • 38. (Теория) CPU Cache Associativity var criticalStride = cacheSize / associativity; 26/79 5. Поговорим про CPU Cache Associativity
  • 39. (Теория) CPU Cache Associativity var criticalStride = cacheSize / associativity; Level Size Associativity Critical Stide L1 32KB 8-way 4KB L2 256KB 4-way 64KB L2 256KB 8-way 32KB L3 6MB 12-way 512KB 26/79 5. Поговорим про CPU Cache Associativity
  • 40. Минутка занимательного про 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 enlarged buffers. • Page split load penalty down from 100 cycles in previous generation to 5 cycles. • L3 write bandwidth increased from 4 cycles per line in previous generation to 2 per line. • L2 associativity changed from 8 ways to 4 ways. 27/79 5. Поговорим про CPU Cache Associativity
  • 41. Часть 6 Поговорим про Cache Bank Conflicts 28/79 6. Поговорим про Cache Bank Conflicts
  • 42. (Бенчмарк) Cache Bank Conflicts int[] data = new int[2 * 1024 * 1024]; [Params(15, 16, 17)] public int Delta; // Есть ли у нас пары элементов на расстоянии Delta, // в которых первое число меньше второго? [Benchmark] public unsafe bool Calc() { fixed (int* dataPtr = data) { int* ptr = dataPtr; int d = Delta; bool res = false; for (int i = 0; i < 1024 * 1024; i++) { res |= (ptr[0] < ptr[d]); ptr++; } return res; } } Windows 10, .NET 4.6.2, LegacyJIT-x86 29/79 6. Поговорим про Cache Bank Conflicts
  • 43. (Результаты) Cache Bank Conflicts Delta 15 16 17 Skylake: выпущен 2015-08-05, микроархитектура Skylake Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge 30/79 6. Поговорим про Cache Bank Conflicts
  • 44. (Результаты) Cache Bank Conflicts Delta 15 16 17 Skylake ≈1.05ms ≈1.05ms ≈1.05ms Skylake: выпущен 2015-08-05, микроархитектура Skylake Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge 30/79 6. Поговорим про Cache Bank Conflicts
  • 45. (Результаты) Cache Bank Conflicts Delta 15 16 17 Skylake ≈1.05ms ≈1.05ms ≈1.05ms Ivy Bridge ≈1.07ms ≈1.30ms ≈1.07ms Skylake: выпущен 2015-08-05, микроархитектура Skylake Ivy Bridge: выпущен 2012-04-29, микроархитектура Sandy Bridge 30/79 6. Поговорим про Cache Bank Conflicts
  • 46. (Мануал) Cache Bank Conflicts Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual: 3.6.1.3. Handling L1D Cache Bank Conflict In Intel microarchitecture code name Sandy Bridge, the internal organization of the L1D cache may manifest a situation when two load micro-ops whose addresses have a bank conflict. When a bank conflict is present between two load operations, the more recent one will be delayed until the conflict isresolved. A bank conflict happens when two simultaneous load operations have the same bit 2–5 of their linear address but they are not from the same set in the cache (bits 6–12).
  • 47. (Мануал) Cache Bank Conflicts Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual: 3.6.1.3. Handling L1D Cache Bank Conflict In Intel microarchitecture code name Sandy Bridge, the internal organization of the L1D cache may manifest a situation when two load micro-ops whose addresses have a bank conflict. When a bank conflict is present between two load operations, the more recent one will be delayed until the conflict isresolved. A bank conflict happens when two simultaneous load operations have the same bit 2–5 of their linear address but they are not from the same set in the cache (bits 6–12). With the Haswell microarchitecture, the L1 DCache bank conflict issue does not apply. 31/79 6. Поговорим про Cache Bank Conflicts
  • 48. Часть 7 Поговорим про Alignment 32/79 7. Поговорим про Alignment
  • 49. (Бенчмарк) Alignment public struct Struct3 { public byte X1, X2, X3; } public struct Struct8 { public byte X1, X2, X3, X4, X5, X6, X7, X8; } private Struct3[] struct3 = new Struct3[256]; private Struct8[] struct8 = new Struct8[256]; 33/79 7. Поговорим про Alignment
  • 50. (Бенчмарк) Alignment [Benchmark] public int S3() { int res = 0; for (int i = 0; i < struct3.Length; i++) { var s = struct3[i]; res += s.X1 + s.X2; } return res; } [Benchmark] public int S8() { int res = 0; for (int i = 0; i < struct8.Length; i++) { var s = struct8[i]; res += s.X1 + s.X2; } return res; } 34/79 7. Поговорим про Alignment
  • 51. (Результаты) Alignment LegacyJIT-x64 Mono S3 ≈1276ns ≈1146ns S8 ≈241ns ≈2232ns 35/79 7. Поговорим про Alignment
  • 52. (Результаты) Alignment LegacyJIT-x64 Mono S3 ≈1276ns ≈1146ns S8 ≈241ns ≈2232ns Marshal.SizeOf(typeof(S3)) 3 8 35/79 7. Поговорим про Alignment
  • 53. Часть 8 Поговорим про Struct promotion 36/79 8. Поговорим про Struct promotion
  • 54. (Бенчмарк) Struct promotion // А что будет под RyuJIT-x64? [Benchmark] public int S3() { int res = 0; for (int i = 0; i < struct3.Length; i++) { var s = struct3[i]; res += s.X1 + s.X2; } return res; } [Benchmark] public int S8() { int res = 0; for (int i = 0; i < struct8.Length; i++) { var s = struct8[i]; res += s.X1 + s.X2; } return res; } 37/79 8. Поговорим про Struct promotion
  • 55. (Результаты) Struct promotion RyuJIT-x64 S3 ≈280ns S8 ≈280ns 38/79 8. Поговорим про Struct promotion
  • 56. (Смотрим ASM) Struct promotion ; *** S3 *** ; res += s.X1 + s.X2; add eax, r10d add eax, r9d ; *** S8 *** ; res += s.X1 + s.X2; movzx r9d, byte ptr [rsp+20h] add eax, r9d movzx r9d, byte ptr [rsp+21h] add eax, r9d 39/79 8. Поговорим про Struct promotion
  • 57. (Текущая реализация) Struct promotion Иногда RyuJIT1 может аллоцировать структуру в регистрах, а не на стеке • The struct must not be address-taken. • It must have no overlapping fields. • It must have only primitive fields. • It must not be an argument or a return value that is passed in registers. • It can’t be larger than 32 bytes. • It can’t have more than 4 fields. 1 Справедливо для v4.6.1637.0, поведение может поменяться, см. coreclr#6733 40/79 8. Поговорим про Struct promotion
  • 58. Часть 9 Поговорим про Prefetching 41/79 9. Поговорим про Prefetching
  • 59. (Бенчмарк) Prefetching // Подготавливаем данные int[] data = new int[32 * 1024 * 1024]; int[] next = new int[32 * 1024 * 1024]; int n = 2000; 42/79 9. Поговорим про Prefetching
  • 60. (Бенчмарк) Prefetching // Подготавливаем данные int[] data = new int[32 * 1024 * 1024]; int[] next = new int[32 * 1024 * 1024]; int n = 2000; var random = new Random(42); for (int i = 0; i < data.Length; i++) data[i] = random.Next(); for (int i = 0; i < next.Length; i++) next[i] = random.Next(data.Length); 42/79 9. Поговорим про Prefetching
  • 61. (Бенчмарк) Prefetching // CPU-bound method [MethodImpl(MethodImplOptions.NoInlining)] private static int IsNice(int x) { if (x % 13 == 0 | x % 17 == 0 | x % 19 == 0 | x % 43 == 0 | x % 71 == 0 | x % 101 == 0 | x % 233 == 0 | x % 383 == 0 | x % 479 == 0 | x % 541 == 0) return 1; return 0; } 43/79 9. Поговорим про Prefetching
  • 62. (Бенчмарк) Prefetching [Benchmark] public int Simple() { var res = 0; var index = 0; for (int i = 0; i < n; i++) { index = next[index]; var x = data[index]; res += IsNice(x); } return res; } 44/79 9. Поговорим про Prefetching
  • 63. (Бенчмарк) Prefetching [Benchmark] public int Simple() Prefetch() { var res = 0; var index = 0; next[0]; var y = data[index]; for (int i = 0; i < n; i++) { index = next[index]; var x = y; var x = data[index]; index = next[index]; y = data[index]; res += IsNice(x); } return res; } 45/79 9. Поговорим про Prefetching
  • 64. (Результаты) Prefetching Simple ≈161µs Prefetch ≈96µs Windows 10, .NET 4.6.2, LegacyJIT-x86, Haswell 46/79 9. Поговорим про Prefetching
  • 65. (Минутка занимательного) Prefetching Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual: 3.7.2. Hardware Prefetching for First-Level Data Cache The additional instructions to load data from one member in the modified sequence can trigger the DCU hardware prefetch mechanisms to prefetch data in the next cache line, enabling the work on the second member to complete sooner. ; Without prefetching mov eax, [ebx+4] ; With prefetching mov eax, [ebx+4] mov eax, [ebx+4] mov eax, [ebx+4] 47/79 9. Поговорим про Prefetching
  • 66. Часть 10 Поговорим про 4K aliasing 48/79 10. Поговорим про 4K aliasing
  • 67. Store forwarding 49/79 10. Поговорим про 4K aliasing
  • 68. Store forwarding 50/79 10. Поговорим про 4K aliasing
  • 69. Store forwarding 51/79 10. Поговорим про 4K aliasing
  • 70. Store forwarding 52/79 10. Поговорим про 4K aliasing
  • 71. Выравниванием доступ к памяти на 4KB byte[] data = new byte[32 * 1024 * 1024]; int baseOffset; // Хотим выровнять на 4KB 53/79 10. Поговорим про 4K aliasing
  • 72. Выравниванием доступ к памяти на 4KB byte[] data = new byte[32 * 1024 * 1024]; int baseOffset; // Хотим выровнять на 4KB GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr addrOfObject = handle.AddrOfPinnedObject(); 53/79 10. Поговорим про 4K aliasing
  • 73. Выравниванием доступ к памяти на 4KB byte[] data = new byte[32 * 1024 * 1024]; int baseOffset; // Хотим выровнять на 4KB GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned); IntPtr addrOfObject = handle.AddrOfPinnedObject(); long address = addrOfObject.ToInt64(); const int align = 4 * 1024; // 4KB baseOffset = ((int) (align - (address % (align)))); 53/79 10. Поговорим про 4K aliasing
  • 74. (Бенчмарк) 4K aliasing public int StrideOffset; // [Params] [Benchmark] public void ArrayCopy() => Array.Copy( sourceArray: data, sourceIndex: baseOffset, destinationArray: data, destinationIndex: baseOffset + 24 * 1024 + StrideOffset, //24KB length: 16 * 1024); //16KB 54/79 10. Поговорим про 4K aliasing
  • 75. (Результаты) 4K aliasing StrideOffset Haswell Comment 55/79 10. Поговорим про 4K aliasing
  • 76. (Результаты) 4K aliasing StrideOffset Haswell Comment -33 ≈390ns Unaligned 55/79 10. Поговорим про 4K aliasing
  • 77. (Результаты) 4K aliasing StrideOffset Haswell Comment -33 ≈390ns Unaligned -32 ≈330ns Aligned 55/79 10. Поговорим про 4K aliasing
  • 78. (Результаты) 4K aliasing StrideOffset Haswell Comment -33 ≈390ns Unaligned -32 ≈330ns Aligned -31 ≈390ns Unaligned -1 ≈390ns Unaligned 55/79 10. Поговорим про 4K aliasing
  • 79. (Результаты) 4K aliasing StrideOffset Haswell Comment -33 ≈390ns Unaligned -32 ≈330ns Aligned -31 ≈390ns Unaligned -1 ≈390ns Unaligned 0 ≈290ns Aligned 55/79 10. Поговорим про 4K aliasing
  • 80. (Результаты) 4K aliasing StrideOffset Haswell Comment -33 ≈390ns Unaligned -32 ≈330ns Aligned -31 ≈390ns Unaligned -1 ≈390ns Unaligned 0 ≈290ns Aligned 1 ≈1250ns 4K aliasing 2 ≈1250ns 4K aliasing 31 ≈1250ns 4K aliasing 55/79 10. Поговорим про 4K aliasing
  • 81. Rider: взгляд из VTune Amplifier 56/79 10. Поговорим про 4K aliasing
  • 82. (Мануал) 4K aliasing Почитаем Intel® 64 and IA-32 Architectures Optimization Reference Manual: 11.8. 4K ALIASING To resolve 4K aliasing, try the following methods in the following order: • Align data to 32 Bytes. • Change offsets between input and output buffers if possible. • Use 16-Byte memory accesses on memory which is not 32-Byte aligned. 57/79 10. Поговорим про 4K aliasing
  • 83. Часть 11 Поговорим про GC 58/79 11. Поговорим про GC
  • 84. GC: перфомансные кредиты 59/79 11. Поговорим про GC
  • 85. Секретная Rider-фича 60/79 11. Поговорим про GC
  • 86. Факты об одном эксперименте 61/79 11. Поговорим про GC
  • 87. Факты об одном эксперименте • Среднестатистический working set после загрузки: 566MB. 61/79 11. Поговорим про GC
  • 88. Факты об одном эксперименте • Среднестатистический working set после загрузки: 566MB. • Большинство людей имеют больше среднестатистического количества ног. 61/79 11. Поговорим про GC
  • 90. Посмотрим на снэпшот 63/79 11. Поговорим про GC
  • 91. Посмотрим на код var myListener = new HttpListener(); // ... while (myListener.IsListening) { HttpListenerContext ctx = null; try { ctx = myListener.GetContext(); // А что внутри? string rstr = ProcessRequest(ctx.Request); byte[] buf = Encoding.UTF8.GetBytes(rstr); ctx.Response.ContentLength64 = buf.Length; ctx.Response.OutputStream.Write(buf, 0, buf.Length); } // ... } 64/79 11. Поговорим про GC
  • 92. Продолжаем смотреть на код 65/79 11. Поговорим про GC
  • 93. Продолжаем смотреть на код 66/79 11. Поговорим про GC
  • 94. Часть 12 Поговорим про LOH 67/79 12. Поговорим про LOH
  • 95. Поговорим про LOH Справедливо для Full .NET Framework, .NET Core 68/79 12. Поговорим про LOH
  • 96. (Бенчмарк) LOH public class ChunkedArray // Чудо-класс, который { // спасает от LOH private readonly List<object[]> arrays; public ChunkedArray(int n, int chunkSize) { arrays = new List<object[]>(); while (n > 0) { var size = Math.Min(n, chunkSize / IntPtr.Size); arrays.Add(new object[size]); n -= size; } } } 69/79 12. Поговорим про LOH
  • 97. (Бенчмарк) LOH public class Node // Вспомогательный класс, { // который поможет нам бенчмаркать public ChunkedArray Array { get; } public Node Next { get; } public int X; public Node(ChunkedArray array, Node next) { Array = array; Next = next; } // Очень полезный финализатор ~Node() => X++; } 70/79 12. Поговорим про LOH
  • 98. (Бенчмарк) LOH // *** Allocate *** var node = new Node(new ChunkedArray(N, ChunkSize), null); for (int i = 0; i < 1000; i++) node = new Node(new ChunkedArray(N, ChunkSize), (i % 50 == 0) ? null : node); 71/79 12. Поговорим про LOH
  • 99. (Бенчмарк) LOH // *** Allocate *** var node = new Node(new ChunkedArray(N, ChunkSize), null); for (int i = 0; i < 1000; i++) node = new Node(new ChunkedArray(N, ChunkSize), (i % 50 == 0) ? null : node); // *** Force Collect (.NET 4.5.1+) *** GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); GC.WaitForPendingFinalizers(); 71/79 12. Поговорим про LOH
  • 100. (Результаты) LOH Аллоцируем много больших объектов, собираем мусор и замеряем время: ChunkSize Full Framework Mono 80000 ≈3.3s ≈2.0s Windows 10, .NET 4.6.2, RyuJIT-x64, Mono 4.6.2, Skylake 72/79 12. Поговорим про LOH
  • 101. (Результаты) LOH Аллоцируем много больших объектов, собираем мусор и замеряем время: ChunkSize Full Framework Mono 80000 ≈3.3s ≈2.0s ∞ ≈1.9s ≈1.5s Windows 10, .NET 4.6.2, RyuJIT-x64, Mono 4.6.2, Skylake 72/79 12. Поговорим про LOH
  • 103. Выводы По данному бенчмарку: • Нельзя делать выводы о рантаймах 73/79 12. Поговорим про LOH
  • 104. Выводы По данному бенчмарку: • Нельзя делать выводы о рантаймах • Нельзя делать выводы о том, что же использовать в продакшене 73/79 12. Поговорим про LOH
  • 105. Выводы По данному бенчмарку: • Нельзя делать выводы о рантаймах • Нельзя делать выводы о том, что же использовать в продакшене • Вообще нельзя так бенчмаркать GC, пример слишком академический 73/79 12. Поговорим про LOH
  • 106. Почему Rider всё ещё использует чанки? 74/79 12. Поговорим про LOH
  • 107. Почему Rider всё ещё использует чанки? Нельзя просто так взять и начать рефакторить legacy Нужно подумать про: 74/79 12. Поговорим про LOH
  • 108. Почему Rider всё ещё использует чанки? Нельзя просто так взять и начать рефакторить legacy Нужно подумать про: • Разные ОС и рантаймы 74/79 12. Поговорим про LOH
  • 109. Почему Rider всё ещё использует чанки? Нельзя просто так взять и начать рефакторить legacy Нужно подумать про: • Разные ОС и рантаймы • Разные нагрузки и сценарии 74/79 12. Поговорим про LOH
  • 110. Почему Rider всё ещё использует чанки? Нельзя просто так взять и начать рефакторить legacy Нужно подумать про: • Разные ОС и рантаймы • Разные нагрузки и сценарии • Целевые метрики: latency, footprint 74/79 12. Поговорим про LOH
  • 111. По уши в свопе 75/79 12. Поговорим про LOH
  • 113. Заключение Для memory-bound бенчмаркинга нужно много понимать • Общая методология (размер рабочей памяти, паттерны доступа и всё такое) • Устройство железа и рантаймов • Пользовательские сценарии 77/79 13. Заключение
  • 114. Заключение Для memory-bound бенчмаркинга нужно много понимать • Общая методология (размер рабочей памяти, паттерны доступа и всё такое) • Устройство железа и рантаймов • Пользовательские сценарии Напоминания • Это был доклад о замерах, а не об оптимизациях • В большинстве случаев всё не так уж и плохо 77/79 13. Заключение
  • 115. Методическая литература • Intel® 64 and IA-32 Architectures Optimization Reference Manual • An optimization guide for assembly programmers and compiler makers • What Every Programmer Should Know About Memory 78/79 13. Заключение