Alex
Alex

Reputation: 65

Why calling class function is much slower

I'm trying to optimize an assembly which manipulate large data, but there is something I don't understand : why in the following code, looking for the minimum is two times longer if called from a class.

Sub Main()
    Dim t As New Stopwatch()
    Dim ar(100000) As Double
    For i = 0 To ar.Length - 1
        ar(i) = i
    Next

    t.Start()
    Dim Min As Double
    Dim idx As Integer
    For j = 1 To 1000
        Min = Double.MaxValue
        idx = -1
        For i = 0 To ar.Length - 1
            If ar(i) < Min Then
                idx = i
                Min = ar(i)
            End If
        Next
    Next
    t.Stop()
    Console.WriteLine("Min in Main sub : " & t.ElapsedMilliseconds & "ms")

    Dim test As New SomeArray
    test.ar = ar
    t.Reset() : t.Start()
    test.Minimum()
    t.Stop()
    Console.WriteLine("Min in class : " & t.ElapsedMilliseconds & "ms")
End Sub

Public Class SomeArray
    Public Property ar As Double()

    Public Function Minimum() As Double
        Dim Min As Double
        Dim idx As Integer
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To ar.Length - 1
                If ar(i) < Min Then
                    idx = i
                    Min = ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

Example of result:

Min in Main sub: 458 ms
Min in class   : 815 ms

SomeArray.Minimum is exactly a copy/past of the Main, so why it's so longer?

Tested with Framework 3.5.

UPDATE

First answers suggest that using fields instead of properties is faster. I confirm that until I'm in DEBUG mode. But as suggested by @SreeHarshaNellore result in RELEASE mode is a bit different. To perform some test I've used following class :

Public Class SomeArray 'Original one
    Public Property ar As Double()

    Public Function RecalcMinimum() As Double
        Dim Min As Double
        Dim idx As Integer
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To ar.Length - 1
                If ar(i) < Min Then
                    idx = i
                    Min = ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

Public Class SomeArray2 'with private field
    Private _ar As Double()
    Public Sub New(ar As Double())
        _ar = ar
    End Sub

    Public Function RecalcMinimum() As Double
        Dim Min As Double
        Dim idx As Integer

        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To _ar.Length - 1
                If _ar(i) < Min Then
                    idx = i
                    Min = _ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

Public Class SomeArray3 'Same as SomeArray2 but with local array in loop
    Private _ar As Double()
    Public Sub New(ar As Double())
        _ar = ar
    End Sub

    Public Function RecalcMinimum() As Double
        Dim Min As Double
        Dim idx As Integer
        Dim l As Double() = _ar
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To l.Length - 1
                If l(i) < Min Then
                    idx = i
                    Min = l(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

Public Class SomeArray4 'With property but access with private field
    Public Property ar As Double()

    Public Function RecalcMinimum() As Double
        Dim Min As Double
        Dim idx As Integer
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To _ar.Length - 1
                If _ar(i) < Min Then
                    idx = i
                    Min = _ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

Public Class SomeArray5 'Array as function argument
    Public Function RecalcMinimum(ar As Double()) As Double
        Dim Min As Double
        Dim idx As Integer
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To ar.Length - 1
                If ar(i) < Min Then
                    idx = i
                    Min = ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

And the result is a bit surprising in RELEASE mode:

Main sub   : 135 ms
SomeArray  : 143 ms '(property and property access)
SomeArray2 : 272 ms '(private field)
SomeArray3 : 143 ms '(private field + local array)
SomeArray4 : 261 ms '(property but field access)
SomeArray5 : 144 ms '(array as function argument)

As suggested by @SreeHarshaNellore, in RELEASE mode SomeArray is as fast as Main. Accessing to private filed is now slower (completely differente from DEBUG mode). Moreover, if I add a local variable that points to the private field ("l" in SomeArray3) I back to the Mais speed.

Any explanation ?

For information in DEBUG I get:

Main sub   : 402 ms
SomeArray  : 708 ms '(property and property access)
SomeArray2 : 415 ms '(private field)
SomeArray3 : 371 ms '(private field + local array)
SomeArray4 : 435 ms '(property but field access)
SomeArray5 : 409 ms '(array as function argument)

(SomArray 3 is again the fastest)

Upvotes: 1

Views: 137

Answers (2)

Sree Harsha Nellore
Sree Harsha Nellore

Reputation: 438

I got the same results as @Alex when I compiled for DEBUG config.
Then, I tested the code with both backing field and automatic BUT in RELEASE config using 
.NET 4.6.1

There is no difference between these 2 approaches

It takes approximately 
100ms for Main method
110ms for Class method

Which means that the code is greatly optimised in RELEASE mode.

Upvotes: 1

RBarryYoung
RBarryYoung

Reputation: 56755

If you change the SomeArray class to use the backing field instead of the Property, the difference goes away (this is what I always do in my own code):

Public Class SomeArray
    Public Property ar As Double()

    Public Function Minimum() As Double
        Dim Min As Double
        Dim idx As Integer
        For j = 1 To 1000
            Min = Double.MaxValue
            idx = -1
            For i = 0 To ar.Length - 1
                If _ar(i) < Min Then
                    idx = i
                    Min = _ar(i)
                End If
            Next
        Next
        Return Min
    End Function
End Class

So clearly, the difference is the property accessor overhead.

Upvotes: 0

Related Questions