Click here to Skip to main content
15,896,269 members
Articles / Programming Languages / Visual Basic

Application dashboard for tracking .NET application performance

Rate me:
Please Sign up or sign in to vote.
3.39/5 (12 votes)
26 Jul 2006CPOL 94.6K   3.1K   50  
Provides graphical feedback on the performance (memory usage, garbage collection, threads, exceptions, loaded classes) of a .NET application.
Public Class Form_Dashboard

#Region "Public constants"
    '\\ Categories
    Public Const COUNTER_CATEGORY_MEMORY As String = ".NET CLR Memory"
    Public Const COUNTER_CATEGORY_EXCEPTIONS As String = ".NET CLR Exceptions"
    Public Const COUNTER_CATEGORY_LOADING As String = ".NET CLR Loading"
    Public Const COUNTER_CATEGORY_THREADS As String = ".NET CLR LocksAndThreads"

    '\\ Instance names
    Public Const COUNTER_NAME_TOTALBYTES As String = "# Bytes in all Heaps"
    Public Const COUNTER_NAME_GARBAGECOLLECTION As String = "% Time in GC"
    Public Const COUNTER_NAME_EXCEPTIONS As String = "# of Exceps Thrown"
    Public Const COUNTER_NAME_CLASSESLOADED As String = "Current Classes Loaded"
    Public Const COUNTER_NAME_THREADS As String = "# of current logical Threads"

#End Region

#Region "Private members"
    Private _MemoryCounter As PerformanceCounter
    Private _GarbageCollectionCounter As PerformanceCounter
    Private _ExceptionsCounter As PerformanceCounter
    Private _LoadedClassesCounter As PerformanceCounter
    Private _ThreadsCounter As PerformanceCounter
#End Region

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.Timer_Sample.Interval = My.Settings.TimerGranularity
        Call RefreshSettings()

    End Sub

    Private Sub Timer_Sample_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer_Sample.Tick

        Try
            If Not _MemoryCounter Is Nothing Then
                Me.Dial_Memory.CurrentValue = CInt(_MemoryCounter.NextValue / 1024)
            End If
            If Not _GarbageCollectionCounter Is Nothing Then
                Me.Dial_GarbageCollection.CurrentValue = CInt(_GarbageCollectionCounter.NextValue)
            End If
            If Not _ExceptionsCounter Is Nothing Then
                Me.Dial_Exceptions.CurrentValue = CInt(_ExceptionsCounter.NextValue)
            End If
            If Not _LoadedClassesCounter Is Nothing Then
                Me.Dial_Classes.CurrentValue = CInt(_LoadedClassesCounter.NextValue)
            End If
            If Not _ThreadsCounter Is Nothing Then
                Me.Dial_Threads.CurrentValue = CInt(_ThreadsCounter.NextValue)
            End If
        Catch ex As System.InvalidOperationException
            '\\ Failed to read from a counter - possibly the target application is closed
            If Not PerformanceCounterCategory.InstanceExists(My.Settings.MonitoredInstanceName, COUNTER_CATEGORY_MEMORY) Then
                My.Application.Log.WriteException(ex, TraceEventType.Information, "Instance closed or doesn't exist")
                _MemoryCounter.Dispose()
                _MemoryCounter = Nothing
                _GarbageCollectionCounter.Dispose()
                _GarbageCollectionCounter = Nothing
                _ExceptionsCounter.Dispose()
                _ExceptionsCounter = Nothing
                _LoadedClassesCounter.Dispose()
                _LoadedClassesCounter = Nothing
                _ThreadsCounter.Dispose()
                _ThreadsCounter = Nothing
                Me.Timer_Sample.Enabled = False
            Else
                My.Application.Log.WriteException(ex, TraceEventType.Error, "Updating dials from performance counter instances")
            End If
        End Try

    End Sub


    Private Sub SettingsToolStripMenuItem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles SettingsToolStripMenuItem.Click

        Dim fSettings As New SettingsForm
        If fSettings.ShowDialog = Windows.Forms.DialogResult.OK Then
            '\\ Settings changed
            My.Settings.MonitoredInstanceName = fSettings.SelectedInstanceName
            My.Settings.DialMemoryMinimum = Integer.Parse(fSettings.TextBox_Min_Memory.Text)
            My.Settings.DialMemoryMaximum = Integer.Parse(fSettings.TextBox_Max_Memory.Text)
            My.Settings.DialExceptionsMinimum = Integer.Parse(fSettings.TextBox_Min_Exceptions.Text)
            My.Settings.DialExceptionsMaximum = Integer.Parse(fSettings.TextBox_Max_Exceptions.Text)
            My.Settings.DialGarbageMinimum = Integer.Parse(fSettings.TextBox_Min_Garbage.Text)
            My.Settings.DialGarbageMaximum = Integer.Parse(fSettings.TextBox_Max_Garbage.Text)
            My.Settings.DialThreadsMinimum = Integer.Parse(fSettings.TextBox_Min_Threads.Text)
            My.Settings.DialThreadsMaximum = Integer.Parse(fSettings.TextBox_Max_Threads.Text)
            My.Settings.DialClassesMinimum = Integer.Parse(fSettings.TextBox_Min_Classes.Text)
            My.Settings.DialClassesMaximum = Integer.Parse(fSettings.TextBox_Max_Classes.Text)

            '\\ Reset the counters etc,
            Call RefreshSettings()
        End If
    End Sub

    Private Sub RefreshSettings()

        If My.Settings.MonitoredInstanceName <> "" Then
            Me.Text = "Application Dashboard : " & My.Settings.MonitoredInstanceName
            If PerformanceCounterCategory.InstanceExists(My.Settings.MonitoredInstanceName, COUNTER_CATEGORY_MEMORY) Then
                Me.Timer_Sample.Enabled = True
                '\\ Create the performance counter instances
                If _MemoryCounter Is Nothing Then
                    _MemoryCounter = New PerformanceCounter(COUNTER_CATEGORY_MEMORY, COUNTER_NAME_TOTALBYTES, My.Settings.MonitoredInstanceName)
                End If
                _MemoryCounter.InstanceName = My.Settings.MonitoredInstanceName
                If _GarbageCollectionCounter Is Nothing Then
                    _GarbageCollectionCounter = New PerformanceCounter(COUNTER_CATEGORY_MEMORY, COUNTER_NAME_GARBAGECOLLECTION, My.Settings.MonitoredInstanceName)
                End If
                _GarbageCollectionCounter.InstanceName = My.Settings.MonitoredInstanceName
                If _ExceptionsCounter Is Nothing Then
                    _ExceptionsCounter = New PerformanceCounter(COUNTER_CATEGORY_EXCEPTIONS, COUNTER_NAME_EXCEPTIONS, My.Settings.MonitoredInstanceName)
                End If
                _ExceptionsCounter.InstanceName = My.Settings.MonitoredInstanceName
                If _LoadedClassesCounter Is Nothing Then
                    _LoadedClassesCounter = New PerformanceCounter(COUNTER_CATEGORY_LOADING, COUNTER_NAME_CLASSESLOADED, My.Settings.MonitoredInstanceName)
                End If
                _LoadedClassesCounter.InstanceName = My.Settings.MonitoredInstanceName
                If _ThreadsCounter Is Nothing Then
                    _ThreadsCounter = New PerformanceCounter(COUNTER_CATEGORY_THREADS, COUNTER_NAME_THREADS, My.Settings.MonitoredInstanceName)
                End If
                _ThreadsCounter.InstanceName = My.Settings.MonitoredInstanceName
            End If

            '\\ Set the min/max for the dials
            With My.Settings
                Me.Dial_Classes.MaximumValue = .DialClassesMaximum
                Me.Dial_Exceptions.MaximumValue = .DialExceptionsMaximum
                Me.Dial_GarbageCollection.MaximumValue = .DialGarbageMaximum
                Me.Dial_Memory.MaximumValue = .DialMemoryMaximum
                Me.Dial_Threads.MaximumValue = .DialThreadsMaximum
                Me.Dial_Classes.MinimumValue = .DialClassesMinimum
                Me.Dial_Exceptions.MinimumValue = .DialExceptionsMinimum
                Me.Dial_GarbageCollection.MinimumValue = .DialGarbageMinimum
                Me.Dial_Memory.MinimumValue = .DialMemoryMinimum
                Me.Dial_Threads.MinimumValue = .DialThreadsMinimum
            End With

        End If

    End Sub
End Class

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Ireland Ireland
C# / SQL Server developer
Microsoft MVP (Azure) 2017
Microsoft MVP (Visual Basic) 2006, 2007

Comments and Discussions