计数器类型RateOfCountsPerSecond32始终显示为0。

13

我有一个 Windows 服务,通过 WCF 服务接口提供某个虚拟队列的消息。

我想公开两个性能计数器 -

  1. 队列中项目的数量
  2. 每秒从队列中删除的项目数量

第一个正常工作,第二个在 PerfMon.exe 中始终显示为 0,尽管 RawValue 看起来是正确的。

我是这样创建计数器的 -

    internal const string PERF_COUNTERS_CATEGORY = "HRG.Test.GDSSimulator";
    internal const string PERF_COUNTER_ITEMSINQUEUE_COUNTER = "# Messages on queue";
    internal const string PERF_COUNTER_PNR_PER_SECOND_COUNTER = "# Messages read / sec";

if (!PerformanceCounterCategory.Exists(PERF_COUNTERS_CATEGORY))
{
    System.Diagnostics.Trace.WriteLine("Creating performance counter category: " + PERF_COUNTERS_CATEGORY);
    CounterCreationDataCollection counters = new CounterCreationDataCollection();

    CounterCreationData numberOfMessagesCounter = new CounterCreationData();
    numberOfMessagesCounter.CounterHelp = "This counter provides the number of messages exist in each simulated queue";
    numberOfMessagesCounter.CounterName = PERF_COUNTER_ITEMSINQUEUE_COUNTER;
    numberOfMessagesCounter.CounterType = PerformanceCounterType.NumberOfItems32;
    counters.Add(numberOfMessagesCounter);

    CounterCreationData messagesPerSecondCounter= new CounterCreationData();
    messagesPerSecondCounter.CounterHelp = "This counter provides the number of messages read from the queue per second";
    messagesPerSecondCounter.CounterName = PERF_COUNTER_PNR_PER_SECOND_COUNTER;
    messagesPerSecondCounter.CounterType = PerformanceCounterType.RateOfCountsPerSecond32;
    counters.Add(messagesPerSecondCounter);

    PerformanceCounterCategory.Create(PERF_COUNTERS_CATEGORY, "HRG Queue Simulator performance counters", PerformanceCounterCategoryType.MultiInstance,counters);
}

然后,在每个服务调用中,我会增加相关计数器的值。对于每秒计数器来说,目前看起来是这样的 -

messagesPerSecCounter = new PerformanceCounter();
messagesPerSecCounter.CategoryName = QueueSimulator.PERF_COUNTERS_CATEGORY;
messagesPerSecCounter.CounterName = QueueSimulator.PERF_COUNTER_PNR_PER_SECOND_COUNTER;
messagesPerSecCounter.MachineName = ".";
messagesPerSecCounter.InstanceName = this.ToString().ToLower();
messagesPerSecCounter.ReadOnly = false;

messagesPerSecCounter.Increment();

如上所述 - 如果我在调用increment之后设置断点,我可以看到RawValue不断增加,与对服务的调用一致(相当频繁,我认为至少一秒钟多次) 但性能计数器本身仍然保持在0。

提供'队列'上的项目计数的性能计数器以相同方式实现(尽管我分配了RawValue而不是调用Increment),它运行良好。

我错过了什么?


你每次增加计数器时都在创建一个新的计数器吗?这是不正确的,只需要创建一个即可。 - Hans Passant
所以 - 最初我没有这样做,而且它仍然不起作用,但我认为这并不是问题。 事实上 - 我尝试了网上的一个示例(http://www.codeguru.com/columns/dotnet/article.php/c7279/),它运行得非常好,并更改了它以每次重新创建性能计数器,它仍然有效(尽管我完全同意这不是最有效的方法)。 无论如何 - 正如我所说,我尝试了两种方法,这只是代码目前的状态,因为我一直在尝试各种方法。 - Yossi Dahan
4个回答

16

我最初也遇到了这个计数器的问题。 MSDN提供了一个完整可用的示例,对我帮助很大:

http://msdn.microsoft.com/en-us/library/4bcx21aa.aspx

虽然他们的示例相对冗长,但我将其简化为一个方法以演示最基本的内容。运行时,我在PerfMon中看到了预期的每秒10次计数。

public static void Test()
{
    var ccdc = new CounterCreationDataCollection();

    // add the counter
    const string counterName = "RateOfCountsPerSecond64Sample";
    var rateOfCounts64 = new CounterCreationData
    {
        CounterType = PerformanceCounterType.RateOfCountsPerSecond64,
        CounterName = counterName
    };
    ccdc.Add(rateOfCounts64);

    // ensure category exists
    const string categoryName = "RateOfCountsPerSecond64SampleCategory";
    if (PerformanceCounterCategory.Exists(categoryName))
    {
        PerformanceCounterCategory.Delete(categoryName);
    }
    PerformanceCounterCategory.Create(categoryName, "",
        PerformanceCounterCategoryType.SingleInstance, ccdc);

    // create the counter
    var pc = new PerformanceCounter(categoryName, counterName, false);

    // send some sample data - roughly ten counts per second
    while (true)
    {
        pc.IncrementBy(10);
        System.Threading.Thread.Sleep(1000);
    }
}

我希望这能帮助到某些人。


1
谢谢Mikey,已经过了一段时间,我已经继续前进了,所以无法在我的原始代码上验证它,但它看起来很好,并且非常有用,所以我认为它“值得”答案标记! - Yossi Dahan
@Mike-Chamberlain,我有一个类似的问题。虽然NumberOfItems64类型的计数器被设置为一个值(每分钟一次),但在PerfMon中显示为0。在调试器中,我看到RawValue已经增加了。如果我只是在调试器中点击某些东西,RawValue立即变为0。perf.counter的设置是在ASP.NET应用程序中完成的。我无法在控制台应用程序中在家中重现这个问题。我的问题是:你有什么猜测可能是这个原因,并知道任何修复/解决方法吗? - Dimitre Novatchev
可能是ASP.NET应用程序没有权限设置或创建性能计数器。您可以尝试以管理员权限运行应用程序(仅供测试目的-在IIS管理器中更改应用程序池的用户)。实际上,我不知道创建或修改性能计数器需要哪些权限。 - Palo

5
当使用平均计数器(Average type Performance Counters)时,有两个组成部分——分子和分母。因为你正在使用的是平均值,所以计数器被计算为“x个实例每y个实例”。在这种情况下,你需要计算“每秒钟多少个项目”(即“number items per number of seconds”)。换句话说,你需要计算出从队列中取出了多少项以及它们被移除所需的时间。
实际上,Average类型的性能计数器会创建两个计数器:一个分子组件名为{name},一个分母组件名为{name}Base。如果你前往性能计数器管理器 snap-in,可以查看所有类别和计数器;你可以检查Base计数器的名称。当队列处理过程启动时,应:
  • 开始一个秒表
  • 从队列中删除一个或多个项
  • 停止秒表
  • {name}计数器增加已从队列中删除的项的数量
  • {name}Base计数器逐秒增加
计数器应该自动知道将第一个计数器除以第二个计数器以给出平均速率。请参考CodeProject,以了解其工作方式的好示例。
很可能你不需要这种类型的计数器。这些Average计数器用于确定每秒操作发生多少次实例;例如,完成订单所需的平均秒数,或执行某个复杂的事务或进程所需的平均秒数。你可能需要的是实时平均实例数,而不是处理时间内的平均数。
考虑一下,如果你的队列中有1个项目,需要1毫秒才能删除,那么速率为每秒1000个项目。但是,在一秒钟后,你只删除了1个项目(因为只有一个),因此你的“实际”时间内每秒只处理1个项目。同样,如果队列中有100万个项目,但由于服务器正忙于其他工作,你只处理了一个项目,那么你想看到1000个项目/秒的理论值还是每秒1个真实值?
如果你想要这个“真实”数字,而不是理论吞吐量数字,则此场景并不适合性能计数器——相反,你需要知道开始时间、结束时间和处理的项目数量。它不可能只使用简单的“计数器”完成。相反,应该将系统启动时间存储在某个地方,并计算出(number of items) / (现在 - 启动时间)

我刚意识到这个问题已经一年了 :-/ - Kirk Broadhurst
1
这是很好的信息,但我不确定这是否解决了原帖作者的问题。 RateOfCountsPerSecond计数器没有基础计数器。这样的计数器似乎是原帖作者情况的一个很好的选择 - 他只想看到前一秒从队列中移除的项目的总数。此处没有进行平均处理 - 计数器仅报告计数器在上一秒内增加了多少次。 - Mike Chamberlain
你对如何递增平均计数器非常确定吗?在你的例子中,你说要通过滴答数来递增基数,但链接的代码项目却相反。 “// 通过操作的时间成本递增计时器 _AverageDuration.IncrementBy(ticks); // 只将基础计数器递增1 _AverageDurationBase.Increment();” - user1228
@Will 是的。链接的代码描述了如何获取“平均持续时间”,即 时间 / 事件数量。而这个问题是关于每秒平均事件数,即 事件数量 / 时间 - Kirk Broadhurst

1
我遇到了同样的问题。在我的测试中,我认为这个问题是多实例和每秒计数率的某种组合。如果我使用单个实例或多个项计数器,它可以工作。那种多实例和每秒速率的组合会导致它始终为零。
正如性能计数器类型RateOfCountsPerSecond64始终具有值0所提到的,重新启动可能会奏效。反正对我有效。
另一个对我有效的方法是在代码块中初始化计数器,就像这样:
counter.BeginInit();
counter.RawValue = 0;
counter.EndInit();

0

我认为你需要一些方法来持久化计数器。在我的看法中,每次服务调用被启动时,计数器都会被重新创建。

因此,你可以将计数器保存到数据库、平面文件,或者甚至是会话变量(如果你希望它对用户唯一)。


1
我觉得你误解了 Windows 性能计数器。请从这里开始:http://msdn.microsoft.com/zh-cn/library/aa373083(v=vs.85).aspx - Mike Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接