为什么使用平均值时图表会很尖锐?

时间:2015-06-10 09:55:51

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

我在我的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?即使现在没有呼叫,我也需要能够看到呼叫时间的平均值。我做错了什么?

PerformanceCounter

1 个答案:

答案 0 :(得分:3)

问题是,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,然后在性能监视器中选择较低的缩放比例。