Did you ever write a program that needed to check the available disk space, the free memory, or the status of a printer? When 640K was a lot of memory and hard disk drives had just started becoming popular, these kinds of checks were prevalent in software, at least software that didn't crash due to a lack of disk space or memory. These simple problems can occur, but in modern software we are just as likely to check TCP connections, threads, the status of IIS, Terminal Services, or the status of a service application.
Until recently programmers had to have some highly specialized knowledge of a lot of hardware and protocols to keep tabs on a wide variety of hardware and services. Fortunately, .NET captures all of this and more as performance counters . Performance counters converge the ability to measure an application's performance in the context of a computer and network into a common hierarchy of related interactions. If you examine the Server Explorer under the machine name , Performance Counters section, you will quickly see that it might be easier to figure out what can't be measured than what can be measured with a performance counter.
The key to using performance counters is to figure out what needs to be measured and then find the correct category of counter or counters. Finding the right counter is harder than using the counter because performance counters are components , and you can simply drag them onto your application to begin using them. For the most part everything else boils down to reading properties from the counter. You no longer have to know how to call some obscure API method to calculate available memory or disk-free space ”just read the information from the appropriate performance counter.
The information available from each kind of counter is as varied as the counters are. CategoryName describes the category under which the counter is stored in the registry. CounterName describes what is being counted. InstanceName describes the instance of the counter if the same counter can be divided into different instances. For example, the percentage of time spent in the garbage collector ( % Time in GC ) is divided into two instances, the total time spent in the garbage collector ( _Global_ ) and the amount of time Visual Studio .NET spends in the garbage collector ( devenv ). MachineName indicates the machine from which the counter is being read.
To demonstrate a performance counter we could express concern over using objects to represent operands and operators. (In our system this is not a real concern because we keep only two operands and one operator around at a time, but we might have valid concerns in a system with thousands or millions of instances of such objects.) We could use the Available Mbytes counter and display the amount of available physical memory in a status bar as our application is running. To include the Available MBytes performance counter I dragged the Available MBytes counter from the Memory category in the Server Explorer onto the main form for the Calculator application. I included a Timer to update the displayed value at one-second intervals. In the Timer's Tick event handler I wrote the value of the counter with some additional text explaining the scale of the counter. Listing 17.10 shows the event handler for the Timer and some extra code that displays the meaning of the counter as a tool tip in the status bar.
Listing 17.10 Displaying and Regularly Updating a Performance Counter Value in a Windows Application
Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Calculator = New Calculator() AddHandler Calculator.OnSendKey, AddressOf SendKeyEvent ToolTip1.SetToolTip(StatusBar1, PerformanceCounter1.CounterHelp) End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles Timer1.Tick StatusBar1.Text = PerformanceCounter1.RawValue & "M Bytes Available" End Sub
Listing 17.10 comes from the completed Calculator example. (You can review the entire listing from 17.1 ”the Timer1_Tick event handler and use of the performance counter represents the revision ”to regain context if you jumped to the middle of this chapter.) The Load event creates the Calculator object, adds an event handler, and sets the status bar's tool tip. In Visual Basic .NET tool tips are added by dragging a ToolTip control onto a form. This step dynamically binds a ToolTip property to Controls . You can literally set the dynamic ToolTip property in the Properties window or programmatically as shown in Listing 17.10.
The Tick event handler reads the current RawValue from the performance counter at regular intervals, adding some text to indicate what RawValue means, and assigns this information to the StatusBar.Text property. The net effect of using the tool tip, status bar, Timer, and performance counter in this way facilitates tracking memory usage as the application is running.