
System Information and the PerformanceCounter Class
The
other day I discussed retrieving system information using the
.NET framework. I guess the main focus of that post was to discuss using
PInvoke to call unmanaged WIN32 DLL exports, more so than actually retrieving different pieces of system information.

The objective of that post was retrieving
memory information (I also retrieve
disk information in my
‘AboutBox’ discussed in that post). In the '
managed codeworld' there is another way to get different information values. Using the
System.Diagnostics.PerformanceCounter Class you can retrieve
‘counter’ information from a local or remote machine. Many of you may be familiar with some of the information accessible through
PerformanceCounters if you run the
performance monitor control panel applet.
The information accessible via the
System.Diagnostics.PerformanceCounter Class is not limited to just system information. Many services and applications also make
‘counter’ information available for retrieval. Performance Counters are broken out by category (
System.Diagnostics.PerformanceCounterCategory). Within each category there many be multiple instances, for example the Logical Disk category will have an instance for each drive, as well as an instance for the
_Total of all drives. Each instance will have its own set of counters that can be retrieved. In keeping with the same example, the
_Total instance of the Logical Disk category has counters such as
‘% Free Space’,
‘Free Megabytes’ and
‘% Disk Write Time’ to name a few.
Reading counter information is a lot easier than one would expect (the
.NET Framework almost made things too easy). I had created a basic-sample PerformanceCounter application that allows for the selection of one of the available (on the local machine) performance counter categories. Once the category is selected, each instance is listed (if there is more than one). Once the counter to be retrieved is selected the value is displayed in a
System.Windows.Forms.ListBox (using a
System.Timers.Timer for interval). Note: When I use
Delphi for development I use the
TChart component to display graphs (as I had in
BPSNMPMon). If anyone knows of a decent charting control that works with
Visual Studio 2005 let me know.
1
System.Diagnostics.PerformanceCounter perfcounter;
2
3
private void cbxPerfCategories_SelectedIndexChanged(object sender, EventArgs e)
4
...{
5
cbxInstances.Enabled = true;
6
cbxInstances.Items.Clear();
7
cbxCounters.Items.Clear();
8
lstOutput.Items.Clear();
9
timer1.Enabled = false;
10
11
if (cbxPerfCategories.SelectedIndex != -1)
12
...{
13
if (PerformanceCounterCategory.Exists(cbxPerfCategories.Text))
14
...{
15
PerformanceCounterCategory perfcategory =
16
new PerformanceCounterCategory(cbxPerfCategories.Text);
17
18
cbxInstances.Items.AddRange(perfcategory.GetInstanceNames());
19
if (cbxInstances.Items.Count == 0)
20
...{
21
cbxInstances.Enabled = false;
22
// Get the counters for a category that has only one
23
// instance
24
GetCounters(perfcategory, "",cbxCounters);
25
}
26
}
27
}
28
}
29
30
private void GetCounters(PerformanceCounterCategory perfcategory,
31
string instancename,
32
ComboBox combobox)
33
...{
34
System.Diagnostics.PerformanceCounter[] counters;
35
if (instancename.Equals(""))
36
...{
37
counters = perfcategory.GetCounters();
38
}
39
else
40
...{
41
counters = perfcategory.GetCounters(instancename);
42
}
43
for (int i = 0; i < counters.Length; i++)
44
...{
45
combobox.Items.Add(counters[i].CounterName);
46
}
47
}
48
49
private void frmMain_Load(object sender, EventArgs e)
50
...{
51
PerformanceCounterCategory[] perfcategories;
52
try
53
...{
54
perfcategories = PerformanceCounterCategory.GetCategories();
55
for (int i = 0; i < perfcategories.Length; i++)
56
...{
57
cbxPerfCategories.Items.Add(perfcategories[i].CategoryName);
58
}
59
}
60
catch (Exception ex)
61
...{
62
MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK,
63
MessageBoxIcon.Error);
64
}
65
}
66
67
private void cbxInstances_SelectedIndexChanged(object sender, EventArgs e)
68
...{
69
cbxCounters.Items.Clear();
70
lstOutput.Items.Clear();
71
timer1.Enabled = false;
72
73
if (cbxInstances.SelectedIndex != -1)
74
...{
75
if (PerformanceCounterCategory.InstanceExists(cbxInstances.Text, cbxPerfCategories.Text))
76
...{
77
PerformanceCounterCategory perfcategory =
78
new PerformanceCounterCategory(cbxPerfCategories.Text);
79
GetCounters(perfcategory, cbxInstances.Text, cbxCounters);
80
}
81
}
82
}
83
84
private void cbxCounters_SelectedIndexChanged(object sender, EventArgs e)
85
...{
86
lstOutput.Items.Clear();
87
if (cbxInstances.Text.Equals(""))
88
...{
89
perfcounter = new System.Diagnostics.PerformanceCounter(cbxPerfCategories.Text,
90
cbxCounters.Text, true);
91
}
92
else
93
...{
94
perfcounter = new System.Diagnostics.PerformanceCounter(cbxPerfCategories.Text,
95
cbxCounters.Text, cbxInstances.Text,true);
96
}
97
timer1.Enabled = true;
98
}
99
100
private void timer1_Tick(object sender, EventArgs e)
101
...{
102
float value;
103
value = perfcounter.NextValue();
104
lstOutput.Items.Insert(0,value.ToString("#,##0.00"));
105
} Labels: .NET, C#, Code