Продолжаем говорить о микрооптимизациях...
-
Upload
andrey-akinshin -
Category
Software
-
view
403 -
download
3
Transcript of Продолжаем говорить о микрооптимизациях...
![Page 1: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/1.jpg)
Продолжаем говорить о микрооптимизациях.NET-приложений
Андрей Акиньшин, JetBrains
.NEXT 2015 Moscow
1/32
![Page 2: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/2.jpg)
Про что будем разговаривать?
Не будет:• Универсальных способов оптимизации• Скучной теории• Подробного устройства .NET, GC, JIT, CPU
Будет:• Много весёлых историй1
2/32
![Page 3: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/3.jpg)
Про что будем разговаривать?
Не будет:• Универсальных способов оптимизации• Скучной теории• Подробного устройства .NET, GC, JIT, CPU
Будет:• Много весёлых историй1
2/32
![Page 4: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/4.jpg)
Про что будем разговаривать?
Не будет:• Универсальных способов оптимизации• Скучной теории• Подробного устройства .NET, GC, JIT, CPU
Будет:• Много весёлых историй1
1Все истории основаны на реальных событиях2/32
![Page 5: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/5.jpg)
Roslyn
3/32 Roslyn
![Page 6: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/6.jpg)
Roslyn
Задачка:
void Print(string format,params object[] args)
{// ...
}
Print("DotNext"); // Будет ли аллокация?
old csc.exe Roslynnew object[0] System.Array.Empty<T>1
4/32 Roslyn
![Page 7: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/7.jpg)
Roslyn
Задачка:
void Print(string format,params object[] args)
{// ...
}
Print("DotNext"); // Будет ли аллокация?
old csc.exe Roslynnew object[0] System.Array.Empty<T>1
1.NET Framework 4.6+4/32 Roslyn
![Page 8: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/8.jpg)
Boxing
5/32 Boxing
![Page 9: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/9.jpg)
BoxingБудет ли упаковка/распаковка?
[MethodImpl(MethodImplOptions.NoInlining)]private static TBase Foo<T, TBase>(T t)
where T : TBase{
return (TBase) t;}
Взглянем на IL:IL_0000: ldarg.0 ; tIL_0001: box 0 ; TIL_0006: unbox.any 1 ; TBaseIL_000b: ret
6/32 Boxing
![Page 10: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/10.jpg)
BoxingБудет ли упаковка/распаковка?
[MethodImpl(MethodImplOptions.NoInlining)]private static TBase Foo<T, TBase>(T t)
where T : TBase{
return (TBase) t;}
Взглянем на IL:IL_0000: ldarg.0 ; tIL_0001: box 0 ; TIL_0006: unbox.any 1 ; TBaseIL_000b: ret
6/32 Boxing
![Page 11: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/11.jpg)
Примеры
struct Bar {}struct Bar<T> {}
Foo<int, int>(1);Foo<long, long>(2);Foo<Bar, Bar>(new Bar());Foo<Bar<int>, Bar<int>>(new Bar<int>());Foo<Bar<IList>, Bar<IList>>(new Bar<IList>());
Но не сможет ли JIT нам помочь?
7/32 Boxing
![Page 12: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/12.jpg)
Примеры
struct Bar {}struct Bar<T> {}
Foo<int, int>(1);Foo<long, long>(2);Foo<Bar, Bar>(new Bar());Foo<Bar<int>, Bar<int>>(new Bar<int>());Foo<Bar<IList>, Bar<IList>>(new Bar<IList>());
Но не сможет ли JIT нам помочь?
7/32 Boxing
![Page 13: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/13.jpg)
Иногда сможет
Foo<int, int>(1);Foo<long, long>(2);Foo<Bar, Bar>(new Bar());Foo<Bar<int>, Bar<int>>(new Bar<int>());
⇓mov eax,ecx ; (С точностью до регистра)ret
8/32 Boxing
![Page 14: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/14.jpg)
А иногда нетFoo<Bar<IList>, Bar<IList>>(new Bar<IList>());
⇓sub rsp,28hmov dword ptr [rsp+30h],ecxmov rax,qword ptr [rsp+30h]mov rcx,qword ptr [rax+10h]mov rcx,qword ptr [rcx]btr rcx,0cmovb rcx,qword ptr [rcx]lea rdx,[rsp+38h]call 00007FF8C37D48D0mov rdx,raxmov rax,qword ptr [rsp+30h]mov rcx,qword ptr [rax+10h]mov rcx,qword ptr [rcx+8]btr rcx,0cmovb rcx,qword ptr [rcx]call 00007FF8C3896870mov al,byte ptr [rax]add rsp,28hret
9/32 Boxing
![Page 15: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/15.jpg)
GC
10/32 GC
![Page 16: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/16.jpg)
GCclass Foo{
public object Bar { get; set; }}var foo = new Foo() { Bar = new object() };// Long live the Bar!GC.KeepAlive(foo);
Уважаемые знатоки, внимание, вопрос:Может ли string удерживать ссылку на object?
var foo = "DotNext";var bar = new object();BlackBox(); // Что же находится в чёрном ящике?// Long live the Bar!GC.KeepAlive(foo);
11/32 GC
![Page 17: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/17.jpg)
GCclass Foo{
public object Bar { get; set; }}var foo = new Foo() { Bar = new object() };// Long live the Bar!GC.KeepAlive(foo);
Уважаемые знатоки, внимание, вопрос:Может ли string удерживать ссылку на object?
var foo = "DotNext";var bar = new object();BlackBox(); // Что же находится в чёрном ящике?// Long live the Bar!GC.KeepAlive(foo);
11/32 GC
![Page 18: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/18.jpg)
GCclass Foo{
public object Bar { get; set; }}var foo = new Foo() { Bar = new object() };// Long live the Bar!GC.KeepAlive(foo);
Уважаемые знатоки, внимание, вопрос:Может ли string удерживать ссылку на object?
var foo = "DotNext";var bar = new object();BlackBox(); // Что же находится в чёрном ящике?// Long live the Bar!GC.KeepAlive(foo);
11/32 GC
![Page 19: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/19.jpg)
GC
Удивительный BCL:
ConditionalWeakTable<TKey, TValue> Class
Enables compilers to dynamically attach object fields to managed objects.
c©MSDN
А давайте немножко пошалим:
var foo = "DotNext";var bar = new object();var cwt = new ConditionalWeakTable<string, object>();cwt.Add(foo, bar);String.Intern(foo);// foo держит ссылку на barGC.KeepAlive(cwt);
12/32 GC
![Page 20: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/20.jpg)
GC
Удивительный BCL:
ConditionalWeakTable<TKey, TValue> Class
Enables compilers to dynamically attach object fields to managed objects.
c©MSDN
А давайте немножко пошалим:
var foo = "DotNext";var bar = new object();var cwt = new ConditionalWeakTable<string, object>();cwt.Add(foo, bar);String.Intern(foo);// foo держит ссылку на barGC.KeepAlive(cwt);
12/32 GC
![Page 21: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/21.jpg)
OS
13/32 OS
![Page 22: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/22.jpg)
OS
14/32 OS
![Page 23: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/23.jpg)
Guid
15/32 OS
![Page 24: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/24.jpg)
Benchmarks
16/32 Benchmarks
![Page 25: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/25.jpg)
Benchmarks
Что там может быть сложного?
// Нужно замерить время?public double WithoutStopwatch(){
double a = 1, b = 1;
for (int i = 0; i < 100; i++)a = a + b;
return a;}
// У нас же есть Stopwatch!public double WithStopwatch(){
double a = 1, b = 1;var sw = Stopwatch.Start();for (int i = 0; i < 100; i++)
a = a + b;Print(sw.ElapsedMilliseconds);return a;
}
WithoutStopwatch WithStopwatch∼100ns ∼350ns
; a + bfld1faddp st(1),st
; a + bfld1fadd qword ptr [ebp-0Ch]fstp qword ptr [ebp-0Ch]
17/32 Benchmarks
![Page 26: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/26.jpg)
Benchmarks
Что там может быть сложного?// Нужно замерить время?public double WithoutStopwatch(){
double a = 1, b = 1;
for (int i = 0; i < 100; i++)a = a + b;
return a;}
// У нас же есть Stopwatch!public double WithStopwatch(){
double a = 1, b = 1;var sw = Stopwatch.Start();for (int i = 0; i < 100; i++)
a = a + b;Print(sw.ElapsedMilliseconds);return a;
}
WithoutStopwatch WithStopwatch∼100ns ∼350ns
; a + bfld1faddp st(1),st
; a + bfld1fadd qword ptr [ebp-0Ch]fstp qword ptr [ebp-0Ch]
17/32 Benchmarks
![Page 27: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/27.jpg)
Benchmarks
Что там может быть сложного?// Нужно замерить время?public double WithoutStopwatch(){
double a = 1, b = 1;
for (int i = 0; i < 100; i++)a = a + b;
return a;}
// У нас же есть Stopwatch!public double WithStopwatch(){
double a = 1, b = 1;var sw = Stopwatch.Start();for (int i = 0; i < 100; i++)
a = a + b;Print(sw.ElapsedMilliseconds);return a;
}
WithoutStopwatch WithStopwatch∼100ns ∼350ns
; a + bfld1faddp st(1),st
; a + bfld1fadd qword ptr [ebp-0Ch]fstp qword ptr [ebp-0Ch]
17/32 Benchmarks
![Page 28: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/28.jpg)
Benchmarks
Что там может быть сложного?// Нужно замерить время?public double WithoutStopwatch(){
double a = 1, b = 1;
for (int i = 0; i < 100; i++)a = a + b;
return a;}
// У нас же есть Stopwatch!public double WithStopwatch(){
double a = 1, b = 1;var sw = Stopwatch.Start();for (int i = 0; i < 100; i++)
a = a + b;Print(sw.ElapsedMilliseconds);return a;
}
WithoutStopwatch WithStopwatch∼100ns ∼350ns
; a + bfld1faddp st(1),st
; a + bfld1fadd qword ptr [ebp-0Ch]fstp qword ptr [ebp-0Ch]
17/32 Benchmarks
![Page 29: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/29.jpg)
Benchmarks
Что там может быть сложного?// Нужно замерить время?public double WithoutStopwatch(){
double a = 1, b = 1;
for (int i = 0; i < 100; i++)a = a + b;
return a;}
// У нас же есть Stopwatch!public double WithStopwatch(){
double a = 1, b = 1;var sw = Stopwatch.Start();for (int i = 0; i < 100; i++)
a = a + b;Print(sw.ElapsedMilliseconds);return a;
}
WithoutStopwatch WithStopwatch∼100ns ∼350ns
; a + bfld1faddp st(1),st
; a + bfld1fadd qword ptr [ebp-0Ch]fstp qword ptr [ebp-0Ch]
17/32 Benchmarks
![Page 30: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/30.jpg)
RyuJIT
18/32 RyuJIT
![Page 31: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/31.jpg)
RyuJITЕсли бы вы были JIT-компилятором,
то как бы вы скомпилировали следующий код?[MethodImpl(MethodImplOptions.AggressiveInlining)]public static ulong RotateRight64(ulong value){
return (value >> 1) | (value << 63);}
Может быть так?mov rdx,rax ; valueshr rdx,1 ; value >> 1shl rax,3Fh ; value << 63or eax,edx ; (value >> 1) | (value << 63)
Или так?ror rax,1
19/32 RyuJIT
![Page 32: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/32.jpg)
RyuJITЕсли бы вы были JIT-компилятором,
то как бы вы скомпилировали следующий код?[MethodImpl(MethodImplOptions.AggressiveInlining)]public static ulong RotateRight64(ulong value){
return (value >> 1) | (value << 63);}
Может быть так?mov rdx,rax ; valueshr rdx,1 ; value >> 1shl rax,3Fh ; value << 63or eax,edx ; (value >> 1) | (value << 63)
Или так?ror rax,1
19/32 RyuJIT
![Page 33: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/33.jpg)
RyuJITЕсли бы вы были JIT-компилятором,
то как бы вы скомпилировали следующий код?[MethodImpl(MethodImplOptions.AggressiveInlining)]public static ulong RotateRight64(ulong value){
return (value >> 1) | (value << 63);}
Может быть так?mov rdx,rax ; valueshr rdx,1 ; value >> 1shl rax,3Fh ; value << 63or eax,edx ; (value >> 1) | (value << 63)
Или так?ror rax,1
19/32 RyuJIT
![Page 34: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/34.jpg)
RyuJIT
Time PercentComputeHash 4047ms 100%RotateRight 1487ms 37%
20/32 RyuJIT
![Page 35: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/35.jpg)
RyuJIT
21/32 RyuJIT
![Page 36: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/36.jpg)
Blittable
Загадка для любителей помаршалить:[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 37: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/37.jpg)
BlittableЗагадка для любителей помаршалить:
[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}
[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 38: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/38.jpg)
BlittableЗагадка для любителей помаршалить:
[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}
var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 39: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/39.jpg)
BlittableЗагадка для любителей помаршалить:
[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;
Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 40: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/40.jpg)
BlittableЗагадка для любителей помаршалить:
[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 41: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/41.jpg)
BlittableЗагадка для любителей помаршалить:
[StructLayout(LayoutKind.Explicit)]public struct UInt128{
[FieldOffset(0)] public ulong Value1;[FieldOffset(8)] public ulong Value2;
}[StructLayout(LayoutKind.Sequential)]public struct MyStruct{
public UInt128 UInt128;public char Char;
}var myStruct = new MyStruct();var baseAddress = (int)&myStruct;var uInt128Address = (int)&myStruct.UInt128;Console.WriteLine(uInt128Address - baseAddress); // ???Console.WriteLine(Marshal.OffsetOf(typeof(MyStruct), "UInt128")); // ???
MS.NET-x86 MS.NET-x64 MonoAddress 4 8 0Marshal 0 0 0
22/32 Blittable
![Page 42: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/42.jpg)
Memory
Event Latency Scaled1 CPU cycle 0.3 ns 1 sLevel 1 cache access 0.9 ns 3 sLevel 2 cache access 2.8 ns 9 sLevel 3 cache access 12.9 ns 43 sMain memory access 120 ns 6 minSolid-state disk I/O 50-150 µs 2-6 daysRotational disk I/O 1-10 ms 1-12 monthsInternet: SF to NYC 40 ms 4 yearsInternet: SF to UK 81 ms 8 yearsInternet: SF to Australia 183 ms 19 yearsOS virtualization reboot 4 s 423 yearsSCSI command time-out 30 s 3000 yearsHardware virtualization reboot 40 s 4000 yearsPhysical system reboot 5 m 32 millenia
c© Systems Performance: Enterprise and the Cloud23/32 Memory
![Page 43: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/43.jpg)
Memory
Задача: подсчитать сумму элементов массива
const int N = 1024;int[,] a = new int[N, N];
[Benchmark]public double Sum_ij(){
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 Sum_ji(){
var sum = 0;for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)sum += a[i, j];
return sum;}
Sum_ij() Sum_ji()∼1.5ms ∼9ms
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
24/32 Memory
![Page 44: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/44.jpg)
Memory
Задача: подсчитать сумму элементов массива
const int N = 1024;int[,] a = new int[N, N];
[Benchmark]public double Sum_ij(){
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 Sum_ji(){
var sum = 0;for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)sum += a[i, j];
return sum;}
Sum_ij() Sum_ji()∼1.5ms ∼9ms
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
24/32 Memory
![Page 45: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/45.jpg)
Memory
Задача: подсчитать сумму элементов массива
const int N = 1024;int[,] a = new int[N, N];
[Benchmark]public double Sum_ij(){
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 Sum_ji(){
var sum = 0;for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)sum += a[i, j];
return sum;}
Sum_ij() Sum_ji()∼1.5ms ∼9ms
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
24/32 Memory
![Page 46: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/46.jpg)
Memory
Задача: подсчитать сумму элементов массива
const int N = 1024;int[,] a = new int[N, N];
[Benchmark]public double Sum_ij(){
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 Sum_ji(){
var sum = 0;for (int j = 0; j < N; j++)
for (int i = 0; i < N; i++)sum += a[i, j];
return sum;}
Sum_ij() Sum_ji()∼1.5ms ∼9ms
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz24/32 Memory
![Page 47: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/47.jpg)
Memory
25/32 Memory
![Page 48: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/48.jpg)
stackalloc
26/32 stackalloc
![Page 49: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/49.jpg)
stackallocfor (int i = 0; i < 10000000; i++){
// Alloc class on heapvar hello = new HelloClassOnStack(random);result += hello.Compute(i);
}vs
for (int i = 0; i < 10000000; i++){
// Alloc class on stackvar hello = stackalloc HelloClassOnStack(random);result += hello.Compute(i);
}
Time GC Collectstack ∼400ms 0heap ∼5000ms 100+
27/32 stackalloc
![Page 50: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/50.jpg)
stackallocfor (int i = 0; i < 10000000; i++){
// Alloc class on heapvar hello = new HelloClassOnStack(random);result += hello.Compute(i);
}vs
for (int i = 0; i < 10000000; i++){
// Alloc class on stackvar hello = stackalloc HelloClassOnStack(random);result += hello.Compute(i);
}
Time GC Collectstack ∼400ms 0heap ∼5000ms 100+
27/32 stackalloc
![Page 51: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/51.jpg)
Branch prediction
28/32 Branch prediction
![Page 52: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/52.jpg)
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 Unsorted∼20µs ∼150µs
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
29/32 Branch prediction
![Page 53: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/53.jpg)
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 Unsorted∼20µs ∼150µs
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
29/32 Branch prediction
![Page 54: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/54.jpg)
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 Unsorted∼20µs ∼150µs
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz29/32 Branch prediction
![Page 55: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/55.jpg)
Branch prediction
Branchless version:private static int Sum(int[] data){
int sum = 0;for (int i = 0; i < N; i++){
// if (data[i] >= 128)// sum += data[i];int t = (data[i] - 128) >> 31;sum += ~t & data[i];
}return sum;
}
Sorted UnsortedBranch ∼20µs ∼150µsBranchless ∼30µs ∼30µs
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz
30/32 Branch prediction
![Page 56: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/56.jpg)
Branch prediction
Branchless version:private static int Sum(int[] data){
int sum = 0;for (int i = 0; i < N; i++){
// if (data[i] >= 128)// sum += data[i];int t = (data[i] - 128) >> 31;sum += ~t & data[i];
}return sum;
}
Sorted UnsortedBranch ∼20µs ∼150µsBranchless ∼30µs ∼30µs
∗LegacyJIT-x86, i7-4702MQ CPU @ 2.20GHz30/32 Branch prediction
![Page 57: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/57.jpg)
Методическая литература
31/32
![Page 58: Продолжаем говорить о микрооптимизациях .NET-приложений](https://reader033.fdocuments.net/reader033/viewer/2022042618/589f3a481a28ab490c8b4f41/html5/thumbnails/58.jpg)
Вопросы?
Андрей Акиньшин, JetBrainshttp://aakinshin.net
https://github.com/AndreyAkinshinhttps://twitter.com/andrey_akinshin
32/32