.Net最佳实践3:使用性能计数器收集性能数据
本文讨论我们如何使用性能计数器从应用程序收集数据。我们将先了解的基本知识,然后我们将看到一个简单的示例,我们将从中收集一些性能数据。
介绍: - 我的应用程序的性能是最好的,像火箭
让我们这篇文章从一个客户和开发人员之间的简短交谈开始。
场景1
客户:- 你们的应用程序的性能怎么样?
主观的开发者:- Well,它真的很快,它是最好的... huuh aaa ooh,它就像火箭一样。
场景2
客户:- 你们的应用程序的性能怎么样?
量化的开发者:- 使用2 GB RAM,xyz处理器和20000客户记录的情况下,客户屏幕在20秒内加载完成。
我肯定比第一个开发的第二个开发者看起来更有前途的。在这篇文章中,我们将探讨我们如何使用性能计数器来测量应用程序的性能。让我们开始计数1,2,3,4 ......
欢迎下载我的免费的500 Q&A电子书,内容涉及NET,ASP.NET,SQL Server,WCF,WPF,WWF@ http://www.questpond.com . (译者:作者在原文中做了一些广告,作为对他劳动成果的尊重,我将照原文翻译)
感谢Javier和Michael
我真的没有才智来写一些关于性能计数器的东西。但阅读下面的文章中,我能对付着写一些东西了。因此,首先请允许我感谢这些人,然后我们再继续本文。
感谢Javier Canillas创建了performance counter helper,它确实简化了很多代码http://perfmoncounterhelper.codeplex.com/
感谢Michael Groeger精彩的文章,我从你的文章中摘取了计数器创建的代码http://www.codeproject.com/KB/dotnet/perfcounter.aspx
我也从以下文章中摘取了不少内容:
http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter.aspx
归根结底,它们是:计数,计算(calculate)和显示
任何性能评估的工作无外乎计数,计算和显示。例如,如果你要计算在内存中每秒处理多少分页,我们首先我们需要对处理的页面的数量和其间流逝的时间(多少秒)进行计数。一旦我们完成计数,我们就需要进行计算,如用分页数除以秒数。最后,我们需要显示我们的性能数据。
现在,我们知道这是一个3步骤的过程,即计数,计算和显示。计数的部分由应用程序来完成。因此,在计数阶段应用程序需要提供数据。请注意,数据不会被性能计数器自动检测到,而需要应用程序提供一些帮助。而计算和显示由性能计数器和监视器完成。
性能计数器不是魔术师
如果应用程序不提供计数器数据,性能计数器无法仅凭自身去衡量应用程序性能。性能计数器需要应用程序来提供性能数据用于衡量应用程序。换句话说,应用程序需要通过创建性能计数器对象来提供数据。
应用程序性能测量的类型
几乎所有的应用程序的性能测量属于以下六大类。
瞬时值:- 很多时候,我们只是要测量当前值。例如,我们希望衡量有多少客户记录已被处理,有多少RAM内存已被使用等,这些指标被称为瞬时值或者绝对值。性能计数器通过瞬时计数器支持这些类型的测量。
平均值:- 有时瞬间/当前值并不展现真实的情况。例如,只是说应用程序消耗1GB的空间是不够的。但是,如果我们能够得到某种内存消耗的平均数据,如1000个记录消耗的空间是10MB,也许你可以更深入了解应用程序里面发生了什么。性能计数器通过使用像AverageBase,AverageTimer32,AverageCount64等类型支持这些种类型的测量。
速率值:- 有些情况下,当你想知道事件相对于时间的比率。例如,你想知道每秒有多少条记录被处理。速率计数器帮助我们计算这些性能指标。
百分比值:- 很多时候,我们想看到以百分比值来作比较。比如你要比较两台计算机之间的性能数据。比较直接的值将不会是一个公平的比较。因此,如果我们能有两台计算机的%值,比较会更有意义。如果我们要比较不同性能计数器的值,百分比是更好的选择,而不是绝对值。
例如,如果你想把RAM使用情况和硬盘空间使用情况做比较。把50GB硬盘使用情况和1GB RAM的使用情况做比较,就如同比较苹果与橘子。如果你使用百分比来表达,这样的比较更公平和合理。百分比性能计数器可以帮助我们以百分比来表达绝对值。
差异值:- 很多时候,我们希望得到差值的性能数据,比如从应用程序开始有多少时间流逝,从应用程序开始有多少硬盘消耗。为了收集这些类型的性能数据,我们需要记录原始值和最新值。为了得到最终的性能数据,我们需要从当前值减去原始值。性能计数器提供差值计数器计算这样的性能数据。
总之,有5种类型的性能计数器,可满足上述所有计数需求。正如下图所表现的:
将用于被性能计数器测试的示例程序
在整篇文章中,我们将用接下来要说明的一个简单的程序作为计数器的例子。在这个例子中,我们将有一个定时器,每隔100毫秒产生一个随机数。这些随机数将被检查看它是否小于2。如果是,那么函数‘MyFunction’将被调用。
下面的代码中,计时器将每100毫秒运行一次并产生随机数,如果随机数小于2则调用‘MyFunction’函数。
private void timer1_Tick(object sender, EventArgs e) { // Generate random number between 1 to 5. Random objRnd = new Random(); int y = objRnd.Next(1, 5); // If random number is less than 2 call my Function if (y > 2) { MyFunction(); } }
下面是'MyFunction'函数的代码,它是当随机数的值小于2时被调用的。该方法不会做任何事情。
private void MyFunction() { }
本文中我们所有的性能计数器的例子,将使用上述定义的代码示例。
加入我们的第一个瞬时性能计数器的4个步骤
在我们深入‘如何增加一个性能计数器’这个问题之前,让我们先来了解一下性能计数器的结构。当我们创建性能计数器,它需要被加入某些类别。因此,我们需要创建一个类别,并且把所有性能计数器放在该类别下。
我们来计数‘MyFunction’ 被调用了多少次。首先让我们来创建一个名为“NumberOfTimeFunctionCalled”的即时计数器。在此之前,让我们来看看有多少不同类型的瞬时计数器被性能计数器所支持: -
一下定义摘自:http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx
NumberOfItems32:- 即时计数器,它显示最近观测到的值。
NumberOfItems64:- 即时计数器,它显示最近观测到的值。 例如,用于维护大量的项或操作的简单计数。 它与 NumberOfItems32 相同,但它使用更大的字段来容纳较大的值。
NumberOfItemsHEX32:- 即时计数器,它以十六进制形式显示最近观测到的值。 例如,用于维护项或操作的简单计数。
NumberOfItemsHEX64:- 即时计数器,它显示最近观测到的值。 例如,用于维护大量的项或操作的简单计数。 它与 NumberOfItemsHEX32相同,但它使用更大的字段来容纳较大的值。
第1步 创建计数器:- 对于我们的当前的场景,‘NumberOfItems32’足够了。所以,我们首先创建'NumberOfItems32‘即时计数器。有两种方式,一种是通过代码,另一种是使用VS 2008的server explorer来创建计数器。代码的方法,我们将在后面看到。现在我们先使用server explorer来创建我们的计数器。因此,打开您的Visual Studio,点击View,打开Server explorer,你会看到下面的图中所示的“Performance Counters”节点。右键单击“Performance Counters”节点,选择“create new category”。
当我们创建了一个新的类别,您可以指定的类别名称,并在类别中添加计数器。对于当前的例子,我们给定类别的名称为“MyApplication”,并且添加类型为'NumberOfItem32',名称为'NumberOfTimeFunctionCalled”的计数器。
第2步 在你的Visual Studio应用程序中添加计数器:- 一旦你已经把计数器添加到server explorer上,你可以把计数器控件拖放到ASPX页面上,如下图所示。
你需要把“只读”属性标记为false,这样你可以从代码中修改计数器的值。
第3步 添加为计数器计数的代码:- 最后,我们需要递增计数器的值。窗体加载过程中,我们首先清除所有计数器的旧值。请注意,计数器的值是作为全局值保存的,所以他们不会自己重置,需要我们显式地重置。因此,在窗体加载时把原始值设置为零。
private void Form1_Load(object sender, EventArgs e) { perfNumberOfTimeFunctionCalled.RawValue = 0; }
当函数被调用时,我们通过使用‘Increment’方法来递增计数器的值。每次increment函数的调用,值增加1。
private void MyFunction() { perfNumberOfTimeFunctionCalled.Increment(); }
第4步 查看计数器数据:- 现在,我们已经指定了计数器在每次‘MyFunction’函数被调用时,递增其值。现在我们使用性能监视器(performance monitor)来显示性能计数器。打开‘Run’并输入‘perfmon’。你会看到有很多默认的性能计数器,清晰起见,我们现在删除所有的计数器,加入我们的性能计数器即‘NumberofTimeFunctionCalled‘。
现在,您可以看到如下图所示的图表。请确保您的应用程序正在运行,因为需要由应用程序发出数据,然后展现在performance monitor上。
上述视图是图表视图,要查看相同数据的文本格式,你可以使用性能监视器提供的‘view report’选项卡。你可以看到该报告显示,从程序开始运行,‘MyFunction的’被调用了9696次。
创建更合理的计数器
在前面的章节中,我们测量了‘MyFunction’被调用的次数。但这样的性能计数并没有真正显示任何的测量价值。最好是,我们也能看到计时器被调用次数,然后我们就能够把计时器被调用的次数和‘MyFunction’被调用的次数做比较。
因此,我们创建一个即时计数器,当定时器触发时递增该计数器。如下面的代码所示。
private void timer1_Tick(object sender, EventArgs e) { perfNumberOfTimeTimerCalled.Increment(); Random objRnd = new Random(); int y = objRnd.Next(1, 5); if (y > 2) { MyFunction(); } }
你可以在下面的图表中可以看到这两个计数器,蓝色的线表示‘MyFunction’被调用的次数,黑色的线表示timer被调用的次数。
如果我们看一下‘report view’,我们也可以看到timer被触发多少次,‘MyFunction’被调用多少次。
平均性能计数器
在前面的章节中,我们用到了2个性能计数器,一个告诉我们timer被触发了多少次,另一个告诉我们‘MyFunction’被调用了多少次。如果我们能有某种平均数据,告诉我们timer每调用一次‘MyFunctionCalled’计数多少次,它将更有意义。
为了得到这些类型的指标,需要用到平均性能计数器。因此,对于我们的场景,我们需要计数函数的调用次数和timer的触发次数。然后,我们需要将他们相除,得到timer每触发一次函数调用多少次。
我们需要添加两个计数器,一个作为分子另一个作为分母。对于作为分子的计数器,我们需要添加‘AverageCount64’类型的计数器,同时为分母,我们需要添加‘AverageBase’类型的计数器。
在‘AverageCount64’类型计数器之后,你需要添加‘AverageBase‘计数器,否则,你会得到一个错误,如下图所示。
我们对于每一个timer触发,我们都对用于记录timer调用的计数器进行递增。
private void timer1_Tick(object sender, EventArgs e) { perfAvgNumberofTimeTimerCalled.Increment(); Random objRnd = new Random(); int y = objRnd.Next(1, 5); if (y > 2) { MyFunction(); } }
为每一次函数调用我们都对用于记录函数调用次数的计数器进行递增
private void MyFunction() { perfNumberOfTimeFunctionCalled.Increment(); }
如果你运行该程序,在view report模式下你应该会看到如下图所示。你可以看到平均‘MyFunction’被调用约0.5次(每timer触发一次)。
如果你自己做计算,你将得到和性能监视器相同的计算值。
速率性能计数器
在我们的示例中,我们现在想找出‘MyFunction’相对于时间的比率。我们想知道每秒钟被调用了多少次。因此,浏览server explorer,并添加‘rateofCountsPerSecond32’计数器如下面的图所示。当‘MyFunction’每次被调用,递增此计数器。
如果您运行的应用程序,你将能够看到“RateofMyFunctionCalledPerSecond”的值。下面是一个简单的报告,该报告显示运行15秒后计数器的速率数据。在这15秒中总调用次数为72次。因此,平均每秒调用5次‘MyFunction’。
剩下的性能计数器
我们还剩下百分比计数器和差异计数器,因为他们是非常简单和直接的,为了保持本文的焦点和特性,我在文中不再介绍这两种计数器
通过C#代码添加计数器
到现在我们已经通过server explorer来增加性能计数器。你还可以通过代码来添加计数器。第一件事就是,我们需要导入System.Diagnostics命名空间。
然后,我们需要创建‘CounterCreationDataCollection’ 对象。
CounterCreationDataCollection Mycounters = new CounterCreationDataCollection();
创建实际的计数器并指定计数器的类型。
CounterCreationData totalOps = new CounterCreationData(); totalOps.CounterName = "Numberofoperations"; totalOps.CounterHelp = "Total number of operations executed"; totalOps.CounterType = PerformanceCounterType.NumberOfItems32; Mycounters.Add(totalOps);
最后,在类别中创建计数器。下面的代码片断用于在‘MyCategory’类别中创建计数器。
PerformanceCounterCategory.Create("MyCategory","Sample category for Codeproject", Mycounters);
让我们用Performance counter helper来缓解我们的痛苦
写性能计数器创建代码是很痛苦的。使用performance counter helper可以帮助你缓解这种痛苦并使你的代码更小巧。你可以一下网站找到performance counter helper:http://perfmoncounterhelper.codeplex.com/
不要在产品中使用
是的,只在开发时使用性能计数器。如果您在产品中使用,确保有一个启用和禁用机制,否则会影响应用程序的性能。
使用性能计数器测量应用程序的数据。
性能计数器包含多种类型,如瞬时,平均,速率等。
性能计数器不应该在产品中用到。如果用到了,确保有一个禁用机制。
性能计数器自身并不能进行测量,它需要应用程序提供数据,这样性能监视器才可以计算并显示的数据。
源代码
从这里你可以找到并下载上述性能计数器讨论的示例源代码。
其他最佳实践
最佳实践第1部分,请单击此处
最佳实践第2部分,请单击此处
最佳实践第4部分,请单击此处
最佳实践第5部分,请单击此处
我的FAQ文章
(译者:广告时间)
我明白这不是谈论我FAQ文章正确的地方。只是想称赞一下自己花费一年时间来完成的FAQ系列。下面是全部的链接:
Silverlight FAQ :- http://www.codeproject.com/KB/WPF/WPFSilverLight.aspx
LINQ FAQ :- http://www.codeproject.com/KB/linq/LINQNewbie.aspx
WWF FAQ :- http://www.codeproject.com/KB/WF/WWF.aspx
WCF FAQ :- WCF.aspx
Sharepoint FAQ :- SharePoint.aspx
Ajax FAQ :- AjaxQuickFAQ.aspx
Architecture FAQ :- SoftArchInter1.aspx
Localization and globalization :- LocalizationGlobalizPart1.aspx
Project management FAQ :- ProjectManagementFAQ.aspx
关于作者
我是微软ASP / ASP.NET MVP,目前
|
本文由知平软件的刘斌华翻译,转载请注明出处。原文地址:http://www.codeproject.com/Articles/42001/NET-Best-Practice-No-3-Using-performance-counters
最佳实践1和2已经有其他网友翻译,一下给出链接:http://www.cnblogs.com/mickeychang/archive/2009/09/17/1568670.html
http://www.cnblogs.com/mickeychang/archive/2009/08/29/1556527.html
本人暂时没有翻译最佳实践4和5的计划。