【问题标题】:Why is the graph spiky when using average?为什么使用平均值时图表会出现尖峰?
【发布时间】:2015-08-25 12:11:53
【问题描述】:

我在我的 WCF 服务中使用 messageInspectors 来测量每个服务方法的经过时间,如下所示:

public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
    if (_activated)
    {
        _startTime.Stop();
        PerformanceCounterHandler.Instance.SetAveragePerformanceCounter(operationName, _startTime.ElapsedTicks);
    }
}

public object BeforeCall(string operationName, object[] inputs)
{
    Guid correlationState;

    if (_activated)
    {
        correlationState = Guid.NewGuid();
        _startTime = new Stopwatch();
        _startTime.Start();
        return correlationState;
    }
    return null;
}

这就是计数器的注册方式

foreach (string methodName in ServiceMethodNames)
                {
                    counter = new CounterCreationData(methodName, methodName + " > Genomsnittlig tid(ms)", PerformanceCounterType.AverageTimer32);
                    col.Add(counter);
                    counter = new CounterCreationData(methodName + "_base", methodName + " > Genomsnittlig tid(ms)", PerformanceCounterType.AverageBase);
                    col.Add(counter);
                }

设置性能计数器的方法如下:

public Boolean SetAveragePerformanceCounter(string performanceCounterName, long value)
        {
            PerformanceCounter performCounter;

            if (_useOrbitPerformanceCounters && (performCounter = _performanceCounters.Values.Where(c=> c.CounterName == performanceCounterName).FirstOrDefault()) != null)
            {
                performCounter.IncrementBy(value);
                performanceCounterName = performanceCounterName + "_base";
                performCounter = _performanceCounters[performanceCounterName];
                performCounter.Increment();
                return true;
            }
            return false;
        }

但是,性能计数器确实显示峰值而不是平均值?如果我更改视图以报告一切都是 0,只要我什么都不做?即使目前没有呼叫,我也需要能够看到呼叫时间平均值现在的样子。我做错了什么?

【问题讨论】:

    标签: c# .net performance performancecounter performance-monitor


    【解决方案1】:

    问题是,AverageTimer32 没有显示一些历史平均值。来自documentation

    平均计数器,用于测量完成流程或操作平均所需的时间。这种类型的计数器显示采样间隔的总经过时间与在该时间段内完成的进程或操作数的比率。这种计数器类型以系统时钟的刻度来测量时间。 公式:((N1 - N0)/F)/(B1 - B0),其中N1和N0是性能计数器读数,B1和B0是它们对应的AverageBase值,F是每秒的滴答数。

    有趣的部分是公式。性能计数器仅显示两个性能计数器读数之间的平均值。因此,如果没有请求,则结果值为 0,因为分子为 0。

    也许可以通过某种方式自行计算该值并通过其他类型的性能计数器公开它。

    编辑: 我编写了一个演示应用程序来演示一种解决方法,但感觉很混乱。我创建了一个NumberOfItems32 性能计数器。

    var counterDataCollection = new CounterCreationDataCollection();
    
    var averageRandomNumer = new CounterCreationData
    {
        CounterType = PerformanceCounterType.NumberOfItems32,
        CounterName = averageRandomNumberCounterName,
        CounterHelp = "Views the average random number."
    };
    counterDataCollection.Add(averageRandomNumer);
    
    PerformanceCounterCategory.Create(
        categoryName,
        "Displays the various performance counters of a test application",
        PerformanceCounterCategoryType.MultiInstance,
        counterDataCollection);
    

    并像这样设置值:

    var averageRandomNumberPerfCounter = new PerformanceCounter(categoryName, averageRandomNumberCounterName, "firstInstance", false);
    var random = new Random();
    var currentAverage = 0d;
    var numberOfReadings = 0L;
    
    while (true)
    {
        var nextRandom = random.Next(1, 101);
    
        // ATTENTION: real code should handle overflow properly
        numberOfReadings++;
        currentAverage = (((numberOfReadings - 1) * currentAverage) + nextRandom) / numberOfReadings;
    
        averageRandomNumberPerfCounter.RawValue = (long)currentAverage;
    
        Thread.Sleep(1000);
    }
    

    这种解决方案的缺点很明显。由于性能计数器只能存储long,因此您会丢失平均值的小数位。此问题的另一种解决方法是缩放您的值,例如将它们乘以 10,然后在性能监视器中选择较低的缩放比例。

    【讨论】:

    • 谢谢,问题是我应该改用什么性能计数器类型?
    猜你喜欢
    • 2010-09-19
    • 2021-02-09
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2021-10-02
    • 2014-10-12
    • 2022-11-04
    • 1970-01-01
    相关资源
    最近更新 更多