Профилирование: кадр движка и работа C#
Измеряйте нужный участок; отсутствие строки C# в профиле не означает нулевую стоимость.
Что показывает встроенный инструмент
При запуске из редактора откройте Debugger → Profiler и нажмите Start. Воспроизведите проблему, остановите захват и выберите проблемный кадр. Frame Time (ms) задаёт представление времени кадра; сравнивайте одинаковый режим и одинаковый сценарий.
Inclusive включает вызовы из функции, Self оставляет её собственное время. Эти режимы полезны только для тех функций, которые действительно представлены в профиле. Встроенные функции профилирования CSharpLanguage в 1.0.0 не собирают профиль методов C#: отсутствие метода на графике не означает, что он ничего не стоит.
Мониторы кадра и профиль методов — разные данные. Получение performance frame через подключённую диагностику подтверждает поток общих метрик, а не полноценный .NET-профиль. CPU-время нельзя считать временем выполнения GPU.
Измерить конкретный синхронный участок
WorkMeasurement.cs
using System;
using System.Diagnostics;
public readonly record struct WorkMeasurement(double Milliseconds, long AllocatedBytes, long Checksum)
{
public static WorkMeasurement Run(int iterations)
{
if (iterations < 0 || iterations > 10_000_000)
throw new ArgumentOutOfRangeException(nameof(iterations));
long before = GC.GetAllocatedBytesForCurrentThread();
long start = Stopwatch.GetTimestamp();
long checksum = 0;
for (int i = 0; i < iterations; i++) checksum += i;
double elapsed = Stopwatch.GetElapsedTime(start).TotalMilliseconds;
long allocated = GC.GetAllocatedBytesForCurrentThread() - before;
return new WorkMeasurement(elapsed, allocated, checksum);
}
}В полном примере сначала выполняется разогрев, затем Run(4096). Checksum должен быть 8386560, а Milliseconds и AllocatedBytes зависят от запуска.
AllocatedBytes — прирост выделений текущего потока во время вызова; это не живой объём managed heap и не память всех потоков. Milliseconds — прошедшее время этого синхронного участка, не стоимость всего кадра. Результат checksum не позволяет случайно заменить полезную работу пустой функцией при сравнении.
Сравнить две версии
Сохраните одинаковые входы, конфигурацию сборки и условия запуска. После разогрева повторите одну и ту же операцию несколько раз; отдельно оцените обычное время и редкие скачки. Не сравнивайте холодный Debug с разогретым ExportRelease и не выводите ускорение из одного замера. Сборка profiler-инструмента сама может менять измеряемую нагрузку.
Для распределения стоимости по методам, асинхронным продолжениям и managed-выделениям нужен отдельно настроенный .NET-профайлер. Его настройка и точность не подтверждаются этим простым замером.