Web design, SQL, and .NET for the young, up-and-coming developer - Dot Net Yuppie - Blog Archive » Simple .NET Benchmarking
Web design, SQL, and .NET for the young, up-and-coming developer Dot Net Yuppie

Simple .NET Benchmarking

March 21st, 2010

While code optimization is a controversial topic, curiosity often gets the best of me and I want to know which method of doing something in VB.NET is more efficient.

I’ve developed a very simple, fast method of benchmarking two different functions and determining which method is faster. If you’d like to download the entire code (and skip the article’s text), there is a ZIP file at the end of this page.

As with any benchmarking test, but especially with tests that can execute quickly, you need to select a high-performance timing method that can detect small differences in execution time — enter QueryPerformanceCounter().

QueryPerformanceCounter is an API function that returns by-reference the value of a high-performance counter in “counts” (which can be converted to milliseconds):

Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Short

To convert from “counts” to milliseconds, you’ll need to use the QueryPerformanceFrequency API function:

Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Short

By using the QueryPerformanceCounter() function, you can calculate the amount of time elapsed between beginning and ending a function:

Dim Speed1 As Long
Console.WriteLine("Starting benchmark test for function 1...")
QueryPerformanceCounter(lngStart)
Function1()
QueryPerformanceCounter(lngEnd)
Speed1 = lngEnd - lngStart

Finally, you can use this concept by comparing Function1() vs. Function2(). In this example, I’ve compared two different string concatenation method. Again, you can download the source code below.

Module Module1

    'Read more at: http://support.microsoft.com/kb/306978
    Declare Function QueryPerformanceCounter Lib "Kernel32" (ByRef X As Long) As Short
    Declare Function QueryPerformanceFrequency Lib "Kernel32" (ByRef X As Long) As Short

    Sub Main()

        Dim lngStart As Long, lngEnd As Long

        If QueryPerformanceCounter(lngStart) = False Then
            Console.WriteLine("High-resolution performance counter not supported - ending.")
            Console.ReadKey()
            Exit Sub
        End If

        Dim Speed1 As Long
        Console.WriteLine("Starting benchmark test for function 1...")
        QueryPerformanceCounter(lngStart)
        Function1()
        QueryPerformanceCounter(lngEnd)
        Speed1 = lngEnd - lngStart

        Dim Speed2 As Long
        Console.WriteLine("Starting benchmark test for function 2...")
        QueryPerformanceCounter(lngStart)
        Function2()
        QueryPerformanceCounter(lngEnd)
        Speed2 = lngEnd - lngStart

        Console.WriteLine(vbCrLf & "Speed of function 1: " & ConvertCountsToMSec(Speed1) & " ms")
        Console.WriteLine("Speed of function 2: " & ConvertCountsToMSec(Speed2) & " ms")
        Console.WriteLine("Absolute difference: " & ConvertCountsToMSec(Math.Abs(Speed2 - Speed1)) & " ms")

        If Speed2 > Speed1 Then
            Console.WriteLine(vbCrLf & "Function 2 was " & Math.Round(Speed2 / Speed1, 4) & "x faster")
        ElseIf Speed1 > Speed2 Then
            Console.WriteLine(vbCrLf & "Function 1 was " & Math.Round(Speed1 / Speed2, 4) & "x faster")
        Else ' Speed1 = Speed2
            Console.WriteLine(vbCrLf & "No difference in speed")
        End If

        Console.WriteLine(vbCrLf & "Press any key to end ...")
        Console.ReadKey()

    End Sub

    Public Sub Function1()
        'Do stuff (method #1)

        Dim s As String = "", i As Integer
        For i = 0 To 1000
            s &= Strings.StrDup(i, "A")
        Next
    End Sub

    Public Sub Function2()
        'Do stuff (method #2)

        Dim s As New Text.StringBuilder(""), i As Integer
        For i = 0 To 1000
            s.Append(Strings.StrDup(i, "A"))
        Next
    End Sub

    Public Function ConvertCountsToMSec(ByVal Counts As Long) As Double
        Dim Freq As Long
        QueryPerformanceFrequency(Freq)

        Return Math.Round(Counts / Freq * 1000, 4)
    End Function

End Module

Download the entire code: SimpleFunctionBenchmarking.zip [79kb]

Leave a Reply