Основные методы измерения производительности
1. Базовые инструменты .NET
Stopwatch - наиболее точный способ для ручных замеров:
var sw = Stopwatch.StartNew();
// Тестируемый код
sw.Stop();
Console.WriteLine($"Время выполнения: {sw.ElapsedMilliseconds} мс");
Важно: Всегда включайте Stopwatch.StartNew()
для минимизации погрешности.
2. Профилировщики
- Visual Studio Diagnostic Tools (CPU Usage, Memory Usage)
- JetBrains dotTrace/dotMemory
- PerfView (для глубокого анализа CLR)
3. BenchmarkDotNet - золотой стандарт
[MemoryDiagnoser]
[ShortRunJob]
public class MyBenchmark
{
[Benchmark]
public void TestMethod()
{
// Тестируемый код
}
}
Преимущества:
- Учет "прогрева" кода (JIT-компиляция)
- Статистическая обработка результатов
- Анализ аллокаций памяти
Ключевые метрики производительности
- Время выполнения (Execution time)
- Потребление памяти (GC collections, аллокации)
- CPU utilization (Процент использования процессора)
- Throughput (Операций в секунду)
Влияние замеров на производительность
Факторы, искажающие результаты:
-
JIT-компиляция:
- Первый запуск всегда медленнее
- Решение: "Прогрев" (warm-up) перед замерами
-
Оптимизации компилятора:
// Может быть оптимизировано в пустоту без фактического выполнения
var result = Calculate();
Решение: Использовать [MethodImpl(MethodImplOptions.NoOptimization)]
-
Кэширование:
- Данные/результаты могут кэшироваться между запусками
- Решение: Сброс состояния перед каждым тестом
-
Накладные расходы инструментов:
- Stopwatch добавляет ```20-100 нс на вызов
- Профилировщики могут замедлять выполнение на 10-300%
Практические рекомендации
Правильный подход к замерам:
- Многократное выполнение (1000-10000 итераций)
- Исключение outliers (аномальных значений)
- Контроль окружения:
- Закрыть фоновые приложения
- Отключить другие процессы
- Фиксированная температура CPU (для избежания thermal throttling)
Пример точного замера:
const int Iterations = 10000;
var sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
// Тестируемый код
}
sw.Stop();
double avgTime = (double)sw.ElapsedTicks / Iterations / Stopwatch.Frequency * 1_000_000;
Console.WriteLine($"Среднее время: {avgTime:F3} мкс");
Анализ результатов
-
Статистическая значимость:
- Разница менее 5% часто нерелевантна
- Учет доверительного интервала
-
Memory vs CPU bound:
- Если время ≈ GC time → проблема в аллокациях
- Если CPU ≈ 100% → проблема в вычислениях
Резюмируем
- Инструменты: Stopwatch для ручных тестов, BenchmarkDotNet для точных замеров
- Метрики: Время, память, CPU, throughput
- Искажения: JIT, кэширование, оптимизации, накладные расходы
- Правила:
- Многократные измерения
- Контроль окружения
- Статистический анализ
- Учет природы замедлений (CPU/memory/IO bound)
Главный принцип: "Измеряй правильно или не измеряй вообще - ложные данные хуже их отсутствия"