【问题标题】:Counter of type RateOfCountsPerSecond32 always shows 0RateOfCountsPerSecond32 类型的计数器始终显示 0
【发布时间】:2011-01-15 08:14:49
【问题描述】:

我有一个 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)工作得很好。

我错过了什么?

【问题讨论】:

  • 您是否真的在每次递增时都创建一个 new 计数器?这不正确,只需创建一个。
  • 所以 - 最初我没有,它仍然没有工作,但我不认为这是一个问题。事实上 - 我已经尝试了一个网络样本(codeguru.com/columns/dotnet/article.php/c7279),它工作得很好,并改变了它以每次重新创建性能计数器,它仍然有效(尽管我完全同意这不是最有效的方法。无论哪种方式 - 正如我所说的我都尝试过,这只是我不断尝试各种事情时代码的状态。

标签: c# performancecounter


【解决方案1】:

我遇到了同样的问题。在我的测试中,我相信我看到的问题是多实例和每秒计数率的某种组合。如果我使用单个实例或多个项目计数器,它就可以工作。多实例和每秒速率的组合导致它始终为零。

正如Performance counter of type RateOfCountsPerSecond64 has always the value 0 所提到的,重启可能会奏效。无论如何都为我工作。

对我有用的另一件事是在这样的块中初始化计数器:

counter.BeginInit();
counter.RawValue = 0;
counter.EndInit();

【讨论】:

    【解决方案2】:

    我最初也遇到过这个计数器的问题。 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);
        }
    }
    

    我希望这对某人有所帮助。

    【讨论】:

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

    当您使用Average 类型的性能计数器时,有两个组件 - 分子和分母。因为您使用的是平均值,所以计数器计算为“x 个实例/y 个实例”。在您的情况下,您正在计算每“秒数”的“数字项目”。换句话说,您需要计算从队列中取出的项目数量以及移除它们需要多少秒。

    Average 类型的性能计数器实际上创建了两个计数器 - 一个名为 {name} 的分子组件和一个名为 {name}Base 的分母组件。如果您转到性能计数器管理单元,您可以查看所有类别和计数器;您可以查看Base 计数器的名称。当队列处理进程启动时,你应该

    • 开始秒表
    • 从队列中删除项目
    • 停止秒表
    • {name} 计数器增加从队列中删除的项目数
    • {name}Base 计数器增加秒表上的刻度数

    计数器应该自动知道将第一个计数器除以第二个以给出平均速率。查看CodeProject 了解其工作原理的一个很好的示例。


    您很可能不想要这种类型的计数器。这些Average 计数器用于确定每秒操作发生多少个实例;例如完成订单或执行某些复杂交易或流程所需的平均秒数。您可能想要的是“实时”的平均实例数,而不是处理时间。

    考虑一下,如果您的队列中有 1 个项目,并且需要 1 毫秒来删除,那么这就是每秒 1000 个项目的速率。但是一秒钟后,您只删除了 1 个项目(因为仅此而已),因此您每秒“实时”处理 1 个项目。同样,如果队列中有 100 万个项目,但您只处理了一个,因为您的服务器正忙于做其他工作,您希望看到 1000 个项目/秒理论还是 1 个项目/秒实际?

    如果您想要这个“真实”数字,而不是理论吞吐量数字,那么这种情况并不适合性能计数器 - 相反,您需要知道开始时间和结束时间,以及一些项目处理。它不能用一个简单的“计数器”来完成。相反,您将在某处存储系统启动时间,并计算(number of items) / (now - startup time)

    【讨论】:

    • 我刚刚意识到这个问题已经存在一年了:-/
    • 这是很好的信息,但我不确定这是否解决了 OP 的问题。 RateOfCountsPerSecond 计数器没有基本计数器。对于 OP 的情况,这样的计数器似乎是一个不错的选择——他只想查看前一秒从队列中删除的项目总数。没有进行平均 - 计数器只报告计数器在最后一秒内增加了多少次。
    • 您是否绝对确定如何增加平均计数器?在您的示例中,您说将基数增加刻度数,但链接的代码项目却相反。 // increment the timer by the time cost of the operation _AverageDuration.IncrementBy(ticks); // increment base counter only by 1 _AverageDurationBase.Increment();
    • @Will 是的。链接代码描述了如何获得“平均持续时间”,即time / number of events。这个问题询问每秒平均事件数,即number of events / time
    【解决方案4】:

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

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多