2

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

性能计数器

4

1 回答 1

3

问题是,AverageTimer32它没有显示一些历史平均值。从文档中:

一个平均计数器,用于测量平均完成一个过程或操作所花费的时间。这种类型的计数器显示采样间隔的总经过时间与在此期间完成的进程或操作数的比率。这种计数器类型以系统时钟的刻度来测量时间。公式:((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,然后在性能监视器中选择较低的缩放比例。

于 2015-06-10T10:27:05.340 回答