为什么使用平均值时图形会出现尖峰?
Why is the graph spiky when using average?
我在我的 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,只要我什么都不做?即使目前没有通话,我也需要能够查看通话时间平均值现在的样子。我做错了什么?
问题是,AverageTimer32
没有显示历史平均值。来自 documentation:
An average counter that measures the time it takes, on average, to complete a process or operation. Counters of this type display a ratio of the total elapsed time of the sample interval to the number of processes or operations completed during that time. This counter type measures time in ticks of the system clock.
Formula: ((N1 - N0)/F)/(B1 - B0), where N1 and N0 are performance counter readings, B1 and B0 are their corresponding AverageBase values, and F is the number of ticks per second.
有趣的部分是公式。性能计数器仅显示两个性能计数器读数之间的平均值。因此,如果没有发出请求,则结果值为 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,然后在性能监视器中选择较低的缩放比例。
我在我的 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,只要我什么都不做?即使目前没有通话,我也需要能够查看通话时间平均值现在的样子。我做错了什么?
问题是,AverageTimer32
没有显示历史平均值。来自 documentation:
An average counter that measures the time it takes, on average, to complete a process or operation. Counters of this type display a ratio of the total elapsed time of the sample interval to the number of processes or operations completed during that time. This counter type measures time in ticks of the system clock. Formula: ((N1 - N0)/F)/(B1 - B0), where N1 and N0 are performance counter readings, B1 and B0 are their corresponding AverageBase values, and F is the number of ticks per second.
有趣的部分是公式。性能计数器仅显示两个性能计数器读数之间的平均值。因此,如果没有发出请求,则结果值为 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,然后在性能监视器中选择较低的缩放比例。