性能计数器NextValue()非常慢(1,000+计数器)

时间:2014-08-18 21:09:42

标签: c# .net performancecounter perfmon

在我们的应用程序中,我们使用Windows性能计数器来存储我们的一些应用程序指标,这些指标稍后会在某些Web服务中检索。

我遇到了从计数器读取值所花费的时间问题。我查看了我的应用程序的其余部分,一切都很好,性能明智,但从循环中的计数器(从列表或数组)中读取需要花费大量时间。

示例代码:

// This triggers a read of the counter's initial value (1000ms delay following for calculated counters)
counters.ToList().ForEach(counter => counter.NextValue());

在我上面的循环测试中,1,359个计数器的列表需要20秒,并且使用秒表,似乎读取计数器值的平均时间是0-10ms,或大约80-90ms。其中很多都需要0ms,最高约为170ms,平均非零值约为80-90ms。

也许我太乐观了,但我认为读取1,000个数值应该只需要几毫秒。这里有更多的处理工作比我知道的还多吗?

我实际上在我的逻辑中有另一个循环,它获得计算计数器的第二个值。这只会使情况变得更糟。 :)

谢谢!


更新1

我将计数器检索包裹在秒表中,我对结果感到惊讶。阅读.RawValue的简单属性仍然需要花费过多的时间。据我所知,计数器基本上都是一样的,检索应该非常快;奇怪的是,我也看到了网络类别的计数器需要更长时间的模式。

根据http://joe.blog.freemansoft.com/2014/03/windows-performance-counters.html,性能计数器服务的性能甚至不应该是一个考虑因素。

我已将一些秒表结果发布到以下pastebin:http://pastebin.com/raw.php?i=aDJk2Tru

我的代码如下:

Stopwatch t;
foreach (var c in counters)
{
    t = Stopwatch.StartNew();
    var r = c.RawValue;
    Debug.WriteLine(t.ElapsedMilliseconds.ToString("000") + " - " + c.CategoryName + ":" + c.CounterName + "(" + c.CounterType + ") = " + r);
}

正如您在粘贴中看到的,很多读取都是0,但在50-100ms范围内有很多。我真的不明白这是怎么回事。当然,一个计数器值应该和其他任何一个一样快,对吗?

1 个答案:

答案 0 :(得分:7)

这是我能够找到的关于计数器的信息。请原谅语法;这是从我发出的关于这个问题的电子邮件中提取的。

  • 在我的机器上至少有一个4-5秒的处理时间(在服务器上可能更好或更差,不确定),从计数器类别中读取实例名称。这与一个类别中的计数器数量可以忽略不计。如果您没有使用实例计数器,则可以避免这种情况。
  • 我们将所有计数器存储在一个类别中,因此根据我们的情况,不可避免的是,类别最终会有数千个计数器。在我的测试中,一个类别中的计数器越多,性能越差。这看起来应该有意义,但个人计数器的性能受当前内存中数量的计数器的影响,这是奇怪的相关性,可能:
    • 总计8个计数器,每个计数器的读取时间约为1-2毫秒
    • 总共256个计数器,每个计数器的读取时间约为15-18ms
    • 使用512个计数器,每个计数器的读取时间约为30毫秒
    • 共有3,584个计数器(读取所有计数器),每个计数器的读取时间约为200毫秒
    • 系统中共有3,584个计数器(在内存中过滤掉,只能读取512个计数器),每个计数器的读取时间为50-90毫秒。不确定为什么这些比前一批512个计数器慢。
    • 我使用System.Diagnostics.Stopwatch计算了几次这些测试以计时。
  • 值得注意的是,计数器必须被读取两次,因为许多计数器是在一段时间内计算的,并且在开始和结束读取时间之间呈现平均值,因此这些不良数字在现实世界中变得更糟场景。

鉴于上面的数字,在我的机器上,慢速端有512个计数器,大约50ms,加上实例查询,第二个计数器读取,我们每个请求大约需要60秒。这是因为我们一次只使用512个计数器。我已经多次针对我的机器上的服务运行完整查询,并且请求在60-65秒内一直完成。

基于所评估的其他计数器的数量,我当然不会假设单个计数器的这种性能下降。在我的阅读中,Windows性能监视器系统应该是快速的,并且当然是小型集合。我们的用例可能不太合适,我们可能会滥用系统。

更新

鉴于我们已经控制了我们如何创建计数器,我们决定改变我们的方法。我们改为创建许多类别,而不是几个具有许多计数器的类别,每个类别都有较少的计数器(每个类别4-8个计数器)。这种方法使我们能够有效地避免性能问题,并且计数器读取时间在0-1ms范围内。根据我们迄今为止的经验,即使是100个新类别,每个类别都有几个计数器,也不会影响系统的性能。

在处理大量其他计数器时需要注意的是,您需要解决默认情况下为性能计数器设置的内存限制。这可以通过machine.config或注册表项来完成。可以在此处找到更多信息:http://msdn.microsoft.com/en-us/library/ms229387(v=vs.110).aspx