性能计数器辅助类
一个性能计数器助手类,使在您的系统中使用性能计数器更容易,特别是用于测量持续时间和总持续时间
引言
在上次我参与的项目中,我们需要添加一些性能计数器来测量系统各个部分的持续时间。有关性能计数器的信息可以在 MSDN 和 CodeProject 中找到,但我们无法找到我们正在寻找的确切信息。
我们首先为系统的一部分创建了一个性能计数器管理器,该管理器专门处理操作持续时间的计数。但是后来,我们意识到我们在系统的其他部分也需要类似的功能。所以我们创建了一个基类 PerformanceCountersManagerBase
作为编写性能计数器的助手类。
Using the Code
附带的代码显示了 PerformanceCountersManagerBase
的简化用法。
该示例分为 3 部分
Core
. 这包含PerformanceCountersManagerBase
的实现。Impl
. 这包含一个继承自PerformanceCountersManagerBase
的MyPerformanceCountersManager
的实现。PerformanceCountersSample
. 这使用MyPerformanceCountersManager
来测量我们示例中某些操作的持续时间和总持续时间。
在您按照如下说明安装了性能计数器之后,您可以运行该示例,打开性能监视器并观察性能计数器随时间的变化。
以编程方式安装新的性能计数器
- 创建一个扩展
PerformanceCountersManagerBase
并定义所需性能计数器的性能计数器管理器
public class MyPerformanceCountersManager : PerformanceCountersManagerBase
{
/// <summary>
/// The category of the counters managed by this manager.
/// </summary>
public const string CategoryName = "SampleCategory";
/// <summary>
/// The name of the counter that measures duration of some operation.
/// </summary>
public const string SomeOperationDurationCounterName = "Some Operation Time";
private static int s_instanceCounter;
public static bool CountersInstalled
{
get { return PerformanceCounterCategory.Exists(CategoryName); }
}
public static void InstallCounters()
{
if (CountersInstalled) return;
var counters = new CounterCreationDataCollection
{
new CounterCreationData
{
CounterName =
SomeOperationDurationCounterName,
CounterHelp =
"Duration in milliseconds it takes to
execute some operation.",
CounterType =
PerformanceCounterType.NumberOfItems64,
},
};
PerformanceCounterCategory.Create(
CategoryName,
"Sample counters",
PerformanceCounterCategoryType.MultiInstance,
counters);
}
public MyPerformanceCountersManager(string instanceName)
{
instanceName = string.Format(
CultureInfo.InvariantCulture,
"{0}_{1}",
instanceName,
s_instanceCounter++);
PerformanceCounters.Add(
SomeOperationDurationCounterName,
CreateWritablePerformanceCounter(CategoryName,
SomeOperationDurationCounterName,
instanceName));
}
}
此类定义了一个名为 Some Operation Time
的性能计数器,位于类别 SomeCategory
下。该计数器的类型为 NumberOfItems64
,它每次使用时都会更新该值。有关可能的性能计数器的完整列表,请参考 MSDN。
static
InstallCounters
方法用于定义性能计数器。
此构造函数用于创建性能计数器的实例。此示例使用每个实例的性能计数器。
- 创建一个用于安装性能计数器的安装程序。
Impl
包含MyPerformanceCountersInstaller
来完成这项工作
[RunInstaller(true)]
public class MyPerformanceCountersInstaller : Installer
{
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
if (!PerformanceCounterCategory.Exists(MyPerformanceCountersManager.CategoryName))
{
MyPerformanceCountersManager.InstallCounters();
}
}
public override void Uninstall(IDictionary savedState)
{
base.Uninstall(savedState);
if (PerformanceCounterCategory.Exists(MyPerformanceCountersManager.CategoryName))
{
PerformanceCounterCategory.Delete(MyPerformanceCountersManager.CategoryName);
}
}
}
您可以通过打开 Visual Studio 命令提示符(以管理员身份),导航到 impl\bin\debug 目录并执行以下命令来安装性能计数器
installutil Impl.dll
如果一切顺利,您应该能够看到包含新性能计数器的新类别,类似于以下内容

使用测量持续时间的性能计数器
- 安装类型为
NumberOfItems64
的性能计数器(如前一节中所定义)。 - 确保您有一个相关的性能计数器管理器实例。您可以使用
NullPerformanceCountersManager
。这是Null
对象模式的实现,可以避免您每次想要使用性能计数器管理器时都检查null
引用。
private IPerformanceCountersManager m_performanceCountersManager =
new NullPerformanceCountersManager();
private void InitializePerformanceCountersManagerIfNecessary()
{
if (!MyPerformanceCountersManager.CountersInstalled) return;
m_performanceCountersManager = new MyPerformanceCountersManager
(Guid.NewGuid().ToString());
}
- 在您要测量的操作之前,请执行以下操作
m_performanceCountersManager.StartWatch
(MyPerformanceCountersManager.SomeOperationDurationCounterName);
- 在您要测量的操作之后,请执行以下操作
m_performanceCountersManager.StopWatch
(MyPerformanceCountersManager.SomeOperationDurationCounterName);
在调用 StopWatch
并从调用 StartWatch
经过的毫秒数之后,性能计数器会被更新。
使用测量总持续时间的性能计数器
有时,您需要将每个操作的持续时间相加到一个包含其总持续时间的性能计数器中。
- 安装类型为
NumberOfItems64
的性能计数器(如前一节中所定义)。 - 当您要开始测量周期时,请调用以下方法
m_performanceCountersManager.ResetCounterValue(
MyPerformanceCountersManager.TotalOperationDurationCounterName);
- 每次您需要使用某些其他计数器经过的时间来更新计数器值时,您可以执行以下操作
m_performanceCountersManager.IncrementCounterValueBy(
MyPerformanceCountersManager.TotalOperationDurationCounterName,
m_performanceCountersManager.GetElapsedMilliseconds(
MyPerformanceCountersManager.SomeOperationDurationCounterName));
请注意,在调用 IncrementCounterValueBy
时,计数器实际上并未更新。只有在性能计数器管理器中保存的内部值才会被更新。
- 当您要实际更新计数器(在测量周期结束时)时,请调用以下方法
m_performanceCountersManager.UpdateCounter
(MyPerformanceCountersManager.TotalOperationDurationCounterName);
性能计数器的其他操作
性能计数器具有类似 Increment
和 IncrementBy
的操作。如果您需要一个性能计数器(如每秒计数器),您可以通过使用类似以下的方法来更新计数器
m_performanceCountersManager.Increment
(MyPerformanceCountersManager.OperationsPerSecondCounterName);
历史
- 2012年1月16日:初始版本