Пример простейшего счетчика производительности
Какое наименьшее количество кода на C# позволяет запустить счетчик производительности?
Я просто хочу измерить количество циклов ЦП и / или время между двумя точками в моем коде. Я пролистал всю вафлю в сети, но, похоже, НАМНОГО больше кода, чем необходимо для такой тривиальной задачи. Я просто хочу быстро провести измерения и сконцентрироваться на том, над чем я работаю.
4 ответа
Я не думаю, что вам нужен счетчик производительности для этого. Вам нужно больше времени, чем вы можете получить от StopWatch? Это очень точно.
Stopwatch watch = Stopwatch.StartNew();
// Do work
watch.Stop();
// elapsed time is in watch.Elapsed
Однако, чтобы ответить на вопрос, который вы фактически задали: если вы просто хотите запросить существующие счетчики, это на самом деле довольно просто. Вот полный пример:
using System;
using System.Diagnostics;
using System.Linq;
static class Test
{
static void Main()
{
var processorCategory = PerformanceCounterCategory.GetCategories()
.FirstOrDefault(cat => cat.CategoryName == "Processor");
var countersInCategory = processorCategory.GetCounters("_Total");
DisplayCounter(countersInCategory.First(cnt => cnt.CounterName == "% Processor Time"));
}
private static void DisplayCounter(PerformanceCounter performanceCounter)
{
while (!Console.KeyAvailable)
{
Console.WriteLine("{0}\t{1} = {2}",
performanceCounter.CategoryName, performanceCounter.CounterName, performanceCounter.NextValue());
System.Threading.Thread.Sleep(1000);
}
}
}
Конечно, процессу потребуются соответствующие разрешения для доступа к необходимым вам счетчикам производительности.
Мне нравится то, что может взять любой блок кода и обернуть его кодом профилирования секундомера, чтобы измерить время, потраченное на его выполнение:
using System.Diagnostics;
using System.Threading;
public static T Profile<T>(Func<T> codeBlock, string description = "")
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
T res = codeBlock();
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
const double thresholdSec = 2;
double elapsed = ts.TotalSeconds;
if(elapsed > thresholdSec)
System.Diagnostics.Debug.Write(description + " code was too slow! It took " +
elapsed + " second(s).");
return res;
}
Затем назовите это так:
Profile(() => MyObj.MySlowMethod());
или же:
Profile(() => MyObj.MySlowMethod(), "I can explain why");
Не существует тривиального способа запустить это в.NET. Тем не менее, самый простой способ, который я нашел, - это построить поверх Enterprise Library, которая предоставляет некоторые готовые возможности для работы со счетчиками производительности. Например: обработчик счетчика производительности
Корпоративная библиотека также предоставляет некоторые возможности для более простого управления установкой счетчиков производительности.
Кроме того, он позволяет вам строить поверх него, поэтому вы можете создать AvergeTimeMeter, который позволит вам просто сделать это:
private static EnterpriseLibraryPerformanceCounter averageRequestTimeCounter = PerformanceCounterManager.GetEnterpriseLibraryCounter(MadPerformanceCountersListener.AverageRequestTime);
private static EnterpriseLibraryPerformanceCounter averageRequestTimeCounterBase = PerformanceCounterManager.GetEnterpriseLibraryCounter(MadPerformanceCountersListener.AverageRequestTimeBase);
public void DoSomethingWeWantToMonitor()
{
using (new AverageTimeMeter(averageRequestTimeCounter, averageRequestTimeCounterBase))
{
// code here that you want to perf mon
}
}
Это позволяет вам просто инкапсулировать код, который вы хотите отслеживать, в использующий блок - и сосредоточиться на коде, над которым вы действительно хотите работать, а не беспокоиться обо всей инфраструктуре счетчика производительности.
Для этого вы создадите повторно используемый класс AverageTimeMeter, например:
public sealed class AverageTimeMeter : IDisposable
{
private EnterpriseLibraryPerformanceCounter averageCounter;
private EnterpriseLibraryPerformanceCounter baseCounter;
private Stopwatch stopWatch;
private string instanceName;
public AverageTimeMeter(EnterpriseLibraryPerformanceCounter averageCounter, EnterpriseLibraryPerformanceCounter baseCounter, string instanceName = null)
{
this.stopWatch = new Stopwatch();
this.averageCounter = averageCounter;
this.baseCounter = baseCounter;
this.instanceName = instanceName;
this.stopWatch.Start();
}
public void Dispose()
{
this.stopWatch.Stop();
if (this.baseCounter != null)
{
this.baseCounter.Increment();
}
if (this.averageCounter != null)
{
if (string.IsNullOrEmpty(this.instanceName))
{
this.averageCounter.IncrementBy(this.stopWatch.ElapsedTicks);
}
else
{
this.averageCounter.SetValueFor(this.instanceName, this.averageCounter.Value + this.stopWatch.ElapsedTicks);
}
}
}
}
Вы должны зарегистрировать свои счетчики производительности (показанные в примерах EntLib), но это должно начать.
Вы можете сделать статическую переменную с именем counter как long и создать поток, который увеличивает его. Вы можете запускать и прерывать эту ветку в любое время, когда захотите и / или захотите. Во время работы потока вы можете использовать целочисленное значение статического счетчика для измерения количества циклов ЦП и / или времени между двумя точками в вашем коде. Технику Thread и статического счетчика можно сравнить с использованием методов Stopwatch Start Stop Restart Reset и свойства ElapsedTicks.