Net Performance. Зачем нужна производительность

Содержание

Слайд 2

Зачем нужна производительность?

Зачем нужна производительность?

Слайд 3

Как понять, на каком уровне проблема?

Как понять, на каком уровне проблема?

Слайд 4

Инструменты

dotTrace

dotMemory

BenchmarkDotNet

Visual Studio profiler

CodeTrack

CLR Profiler

Инструменты dotTrace dotMemory BenchmarkDotNet Visual Studio profiler CodeTrack CLR Profiler

Слайд 5

Инструменты

BenchmarkDotNet

CodeTrack

CLR Profiler

Инструменты BenchmarkDotNet CodeTrack CLR Profiler

Слайд 6

Инструменты

Performance Monitor

Инструменты Performance Monitor

Слайд 7

Инструменты

ETW
Windows Performance Analyzer

Инструменты ETW Windows Performance Analyzer

Слайд 8

Инструменты

MS Message Analyzer

Инструменты MS Message Analyzer

Слайд 9

Lock-free & Wait-free

Lock-free & Wait-free

Слайд 10

Lock-free & Wait-free

Lock-free & Wait-free

Слайд 11

Lock-free & Wait-free

double CompareExchange (ref double location1, double value, double comparand);

Compare

Lock-free & Wait-free double CompareExchange (ref double location1, double value, double comparand); Compare and Swap Interlocked
and Swap

Interlocked

Слайд 12

ConcurrentDictionary

ConcurrentDictionary

Слайд 13

ConcurrentDictionary

Сильная деградация при попытке
получить все блокировки

ConcurrentDictionary Сильная деградация при попытке получить все блокировки

Слайд 14

SIMD

Single instruction, Multiple data

float[] values = GetValues();
float increment = GetIncrement();
for (int i

SIMD Single instruction, Multiple data float[] values = GetValues(); float increment =
= 0; i < values.Length; i++)
{
values[i] += increment;
}

Vector values = GetValues();
Vector increment = GetIncrement();
Vector result = values + increment;

Vector.IsHardwareAccelerated

Слайд 15

SIMD

Single instruction, Multiple data

SIMD Single instruction, Multiple data

Слайд 16

Task.Yield

async Task LongRunningCpuBoundWorkAsync()
{
for (int i = 0; i != 1000000; ++i)

Task.Yield async Task LongRunningCpuBoundWorkAsync() { for (int i = 0; i !=
{
... // CPU-bound work.
}
}

Слайд 17

Task.Yield

async Task LongRunningCpuBoundWorkAsync()
{
for (int i = 0; i != 1000000; ++i)

Task.Yield async Task LongRunningCpuBoundWorkAsync() { for (int i = 0; i !=
{
... // CPU-bound work.
await Task.Yield();
}
}

Слайд 18

Long switch-case

switch (packetID)
{
case BncsPacketId.Null:
break;
case BncsPacketId.EnterChat:
string ecUniqueName = pck.ReadNTString();

Long switch-case switch (packetID) { case BncsPacketId.Null: break; case BncsPacketId.EnterChat: string ecUniqueName
string ecStatstring = pck.ReadNTString();
string ecAcctName = pck.ReadNTString();
var args = new EventArgs(ecUniqueName, ecStatstring, ecAcctName);
OnEnteredChat(args);
break; ...
// ну и так и далее
}

Слайд 19

Long switch-case

Dictionary>

switch (packetID)
{
case BncsPacketId.Null:
break;
case BncsPacketId.EnterChat:
string ecUniqueName =

Long switch-case Dictionary > switch (packetID) { case BncsPacketId.Null: break; case BncsPacketId.EnterChat:
pck.ReadNTString();
string ecStatstring = pck.ReadNTString();
string ecAcctName = pck.ReadNTString();
var args = new EventArgs(ecUniqueName, ecStatstring, ecAcctName);
OnEnteredChat(args);
break; ...
// ну и так и далее
}

Слайд 20

GC

Клиентский режим

Серверный режим

GC Клиентский режим Серверный режим

Слайд 21

ConcurrentBag

Оптимизация потребления памяти

ConcurrentBag Оптимизация потребления памяти

Слайд 22

async/await

async/await

Слайд 23

async/await

async/await

Слайд 24

async/await

async/await

Слайд 25

async/await

Task.FromResult(0)

Task.CompletedResult

.Net 4.6

async/await Task.FromResult(0) Task.CompletedResult .Net 4.6

Слайд 26

Аллокация на стеке

.net core 2.1
Span

C# 7.2
int* block = stackalloc int[100];

Span span

Аллокация на стеке .net core 2.1 Span C# 7.2 int* block =
= size <= 128 ? stackalloc byte[size] : new byte[size];

ValueTask

Слайд 27

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class FreeObjectUtils

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор умный
{
public void Free(T instance)
where T : IChildItems
{
bool needDispose = typeof(IDisposable).IsAssignableFrom(typeof(T));
foreach (var element in instance.ChildItems) element.Dispose();
if (needDispose)
DisposableUtils.Clean(instance);
else
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 28

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class FreeObjectUtils

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор умный
{
public void Free(T instance)
where T : IChildItems
{
foreach (var element in instance.ChildItems) element.Dispose();
if (false)
DisposableUtils.Clean(instance);
else
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 29

JIT оптимизация

[AggressiveInlining] спасет всех

Generic типы инлайнятся

Типичные заблуждения:

Компилятор умный

internal static class FreeObjectUtils

JIT оптимизация [AggressiveInlining] спасет всех Generic типы инлайнятся Типичные заблуждения: Компилятор умный
{
public void Free(T instance)
where T : IChildItems
{
foreach (var element in instance.ChildItems) element.Dispose();
instance.ChildItems.Clear();
}
}

interface IChildItems
{
Collection ChildItems { get; }
}

Слайд 30

JIT оптимизация

public Dictionary(IEqualityComparer comparer);

public struct LongEqualityComparer : IEqualityComparer
{
public static readonly

JIT оптимизация public Dictionary(IEqualityComparer comparer); public struct LongEqualityComparer : IEqualityComparer { public
IEqualityComparer BoxedInstanceInt64 = new LongEqualityComparer();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(long x, long y)
{
return x == y;
}
}

Слайд 31

JIT оптимизация

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
if (typeof(T) == typeof(int) ||

JIT оптимизация [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { if (typeof(T) == typeof(int) ||
typeof(T) == typeof(uint) || typeof(T) == typeof(byte) ||
typeof(T) == typeof(short) || typeof(T) == typeof(long) || typeof(T) == typeof(ulong))
{
_size = 0;
_version++;
}
else
{
int size = (int)_size;
_size = 0;
_version++;
if (size > 0)
Array.Clear(_items, 0, size);
}
}

Слайд 32

MemoryStream

MemoryStream

Слайд 33

MemoryStream

MemoryStream

Слайд 34

MemoryStream

То же самое для:
List
Collection
Dictionary
и прочих коллекций

MemoryStream То же самое для: List Collection Dictionary и прочих коллекций

Слайд 35

struct[] -> IList

int[] a = new int[10];
DoSomething(a);
public void DoSomething(IList list)
{
}

struct[] -> IList int[] a = new int[10]; DoSomething(a); public void DoSomething (IList list) { }

Слайд 36

LINQ

// [18 7 - 18 80]
IL_000e: ldarg.0 // this
IL_000f:

LINQ // [18 7 - 18 80] IL_000e: ldarg.0 // this IL_000f:
call instance class [mscorlib]System.Collections.Generic.IEnumerable`1 WpfApp3.Class2::get_AllParts()
IL_0014: ldloc.0 // 'CS$<>8__locals0'
IL_0015: ldftn instance bool WpfApp3.Class2/'<>c__DisplayClass2_0'::'b__0'(class WpfApp3.RibbonPartMetadata)
IL_001b: newobj instance void class [mscorlib]System.Func`2::.ctor(object, native int)
IL_0020: call class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Where(class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Func`2)
IL_0025: call class [mscorlib]System.Collections.Generic.List`1 [System.Core]System.Linq.Enumerable::ToList(class [mscorlib]System.Collections.Generic.IEnumerable`1)
IL_002a: stloc.1 // V_1
IL_002b: br.s IL_002d

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

Слайд 37

LINQ

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

public IEnumerable FindChildren(Guid

LINQ public IEnumerable FindChildren(Guid parentId) { return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
parentId)
{
var list = new List();
foreach (RibbonPartMetadata part in this.AllParts)
{
if (part.ParentGuid == parentId)
{
list.Add(part);
}
}
return list;
}

Слайд 38

LINQ

public IEnumerable FindChildren(Guid parentId)
{
return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
}

public IEnumerable FindChildren(Guid

LINQ public IEnumerable FindChildren(Guid parentId) { return this.AllParts.Where(part => part.ParentGuid == parentId).ToList();
parentId)
{
var list = new List(this.AllPart.Count);
foreach (RibbonPartMetadata part in this.AllParts)
{
if (part.ParentGuid == parentId)
{
list.Add(part);
}
}
return list;
}

Слайд 39

Строки

Вместо конкатенаций используй StringBuilder

Вместо string.Format используй конкатенацию

string first = "first";
string

Строки Вместо конкатенаций используй StringBuilder Вместо string.Format используй конкатенацию string first =
second = "second";
return $"{first}{second}";

string first = "first";
string second = "second";
return first + second;

Слайд 40

Boxing

public void Info(params object[] args)

log.Info(1, 2, 3, 4, 5);

Как надо?
public static void

Boxing public void Info(params object[] args) log.Info(1, 2, 3, 4, 5); Как
Info();
public static void Info(T1 arg1);

public static void Info(T1 arg1, T2 arg2, T3 arg3);

static Logger log = new Logger();

log.Info();

new object[0]

Слайд 41

Heap Allocation Viewer

Heap Allocation Viewer

Слайд 42

Почитать?

Federico Lois
Sasha Goldstein
Андрей Акиньшин

Почитать? Federico Lois Sasha Goldstein Андрей Акиньшин