Как использовать счетчики производительности AverageTimer32 и AverageBase с System.Diagnostics.Stopwatch?
Когда я запускаю следующую программу и смотрю на счетчик производительности, результаты для меня не имеют смысла. Среднее значение равно нулю, а значения min/max равны ~ 0,4, когда я ожидал бы ~ 0,1 или ~ 100.
В чем моя проблема?
код
class Program
{
const string CategoryName = "____Test Category";
const string CounterName = "Average Operation Time";
const string BaseCounterName = "Average Operation Time Base";
static void Main(string[] args)
{
if (PerformanceCounterCategory.Exists(CategoryName))
PerformanceCounterCategory.Delete(CategoryName);
var counterDataCollection = new CounterCreationDataCollection();
var avgOpTimeCounter = new CounterCreationData()
{
CounterName = CounterName,
CounterHelp = "Average Operation Time Help",
CounterType = PerformanceCounterType.AverageTimer32
};
counterDataCollection.Add(avgOpTimeCounter);
var avgOpTimeBaseCounter = new CounterCreationData()
{
CounterName = BaseCounterName,
CounterHelp = "Average Operation Time Base Help",
CounterType = PerformanceCounterType.AverageBase
};
counterDataCollection.Add(avgOpTimeBaseCounter);
PerformanceCounterCategory.Create(CategoryName, "Test Perf Counters", PerformanceCounterCategoryType.SingleInstance, counterDataCollection);
var counter = new PerformanceCounter(CategoryName, CounterName, false);
var baseCounter = new PerformanceCounter(CategoryName, BaseCounterName, false);
for (int i = 0; i < 500; i++)
{
var sw = Stopwatch.StartNew();
Thread.Sleep(100);
sw.Stop();
Console.WriteLine(string.Format("t({0}) ms({1})", sw.Elapsed.Ticks, sw.Elapsed.TotalMilliseconds));
counter.IncrementBy(sw.Elapsed.Ticks);
baseCounter.Increment();
}
Console.Read();
}
}
Скриншот счетчика производительности
Скриншот счетчика производительности http://friendfeed-media.com/50028bb6a0016931a3af5122774b56f93741bb5c
Ответы
Ответ 1
API System.Diagnostics содержит довольно тонкий источник большой путаницы: "ticks" System.Diagnostics не являются такими же, как и "DateTime" или "TimeSpan"!
Если вы используете StopWatch.ElapsedTicks вместо StopWatch.Elapsed.Ticks, он должен работать.
В документации содержится дополнительная информация об этом.
Ответ 2
Марк Семанн объяснил запутанный источник проблемы, но я хотел бы предоставить немного дополнительной информации.
Если вы хотите установить счетчик производительности AverageTimer32
с TimeSpan
, а не Stopwatch
, вы можете выполнить следующее преобразование:
var performanceCounterTicks = timeSpan.Ticks*Stopwatch.Frequency/TimeSpan.TicksPerSecond;
averageTimerCounter.IncrementBy(performanceCounterTicks);
averageTimerCounterBase.Increment();
Ответ 3
Это старый поток, но я думал, что буду звонить. Мне сказал кто-то из Microsoft, что я не должен использовать TimeSpan
, StopWatch
или DateTime
при работе с счетчиками производительности. Вместо этого он рекомендовал добавить в свой проект следующий собственный метод:
internal static class NativeMethods
{
[DllImport("Kernel32.dll")]
public static extern void QueryPerformanceCounter(ref long ticks);
}
При добавлении счетчика он рекомендует сделать это следующим образом:
public void Foo()
{
var beginTicks = 0L;
var endTicks = 0L;
NativeMethods.QueryPerformanceCounter(ref beginTicks);
// Do stuff
NativeMethods.QueryPerformanceCounter(ref endTicks);
this.Counter.IncrementBy(endTicks - beginTicks);
this.BaseCounter.Increment();
}