Use of Return Statement

J

jamil

While browsing MSDN, I found an article related to performance in
VB.NET programs. The article is dated 2002, and I am not sure if the
information below is still correct:

http://msdn2.microsoft.com/en-us/library/aa289513(VS.71).aspx#vbtchperfoptanchor5

Calling and Returning

....

Use the Return statement whenever your logic permits it. For more
information, see Return Statement. The compiler can optimize the code
better than if you use Exit Function, Exit Property, or Exit Sub, or
allow the End Function, End Get, End Set, or End Sub statement to
generate a return.


Now reading this, I get the impressions that I should add a return to
all of my subroutines instead of relying on End Sub. If this is
indeed true, this seems like a compiler bug that I hope has been fixed
by now.

Any comments on this?
 
B

Bill McCarthy

Hi,

I don't believe that is correct. There is a very minor difference with
Functions where the default value can be assumed if you don't return, or if
you use the Function's name as a data holder, but that isn't what this
document seems to be referring to.
For Subs, Exit Sub and Return are identical. For Functions, Exit Function
implies the data stored in an implied variable of the same name as the
function is returned. So for functions it's a lot clearer if you use Return.

Regards,

Bill.
 
S

Scott M.

But also remember that the "Exit ..." syntax is VB specific, while the
"Return" sytax is portable to C#.
 
C

Cor Ligthert[MVP]

Jamil,

Remember that all external actions like a .show cost more time than all
other actions from an application. With this you almost in any situation for
sure can not make your program faster for your user.

(There are some application when you can win time, however then the question
comes if the managed code based programs are the best for that. In those
situation can C++ be a good choise). Know that it should be very extreme, we
have seen a real live big sample of an application in this newsgroup where
the VB.Net program had more performance than the same applications in C++.

Cor
 
J

jamil

Cor,

I know what you are stating, but I am not quite sure why you are
stating it. I am not debating whether VB.NET or C/C++ is a better
development language. I simply wanted confirmation on a published
Microsoft recommendation. They spent time and resources on publishing
it, so it must have been for a reason.

Given a VB.NET application that executes as a batch process with code
that executes repeatedly, I would be willing to make code changes that
saves fractions of seconds in a single procedure.

So, based on the link I provided, which actually executes in less
time?

Example 1:
Public Sub Test1(ByRef val As Long)
val += 1
Return
End Sub

Example 2:
Public Sub Test2(ByRef val As Long)
val += 1
End Sub

According to the link, Example 1 is more efficient. My point is that
if this is true, I think it's a defect in the compilation. There
should be absolutely no difference between the two.

Here's a bit more code to put this into perspective:

Public Sub Main()
Dim start1 As Date
Dim finish1 As Date
Dim start2 As Date
Dim finish2 As Date

start1 = Now

For i As Long = 0L To 10000000000L
Call Test1(i)
Next i

finish1 = Now
start2 = Now

For i As Long = 0L To 10000000000L
Call Test2(i)
Next i

finish2 = Now

Call MsgBox(String.Format("Test1: {0} ms Test2: {1} ms", _
finish1.Subtract(start1).TotalMilliseconds, _
finish2.Subtract(start2).TotalMilliseconds))

Executing this test, I received a savings of over one second. There
is a difference in time, and the MSDN article is accurate with Visual
Studio 2005 containing the latest service packs.
 
J

jamil

What I also find interesting in this is that the generated MSIL code
is identical between the two subroutines:

..method public static void Test1(int64& val) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i8
IL_0003: ldc.i4.1
IL_0004: conv.i8
IL_0005: add.ovf
IL_0006: stind.i8
IL_0007: ret
} // end of method Module1::Test1


..method public static void Test2(int64& val) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i8
IL_0003: ldc.i4.1
IL_0004: conv.i8
IL_0005: add.ovf
IL_0006: stind.i8
IL_0007: ret
} // end of method Module1::Test2
 
A

Armin Zingler

Given a VB.NET application that executes as a batch process with
code that executes repeatedly, I would be willing to make code
changes that saves fractions of seconds in a single procedure.

So, based on the link I provided, which actually executes in less
time?

Example 1:
Public Sub Test1(ByRef val As Long)
val += 1
Return
End Sub

Example 2:
Public Sub Test2(ByRef val As Long)
val += 1
End Sub

According to the link, Example 1 is more efficient. My point is
that if this is true, I think it's a defect in the compilation.
There
should be absolutely no difference between the two.

Here's a bit more code to put this into perspective:

Public Sub Main()
Dim start1 As Date
Dim finish1 As Date
Dim start2 As Date
Dim finish2 As Date

start1 = Now

For i As Long = 0L To 10000000000L
Call Test1(i)
Next i

finish1 = Now
start2 = Now

For i As Long = 0L To 10000000000L
Call Test2(i)
Next i

finish2 = Now

Call MsgBox(String.Format("Test1: {0} ms Test2: {1} ms", _
finish1.Subtract(start1).TotalMilliseconds,
_
finish2.Subtract(start2).TotalMilliseconds))

Executing this test, I received a savings of over one second. There
is a difference in time, and the MSDN article is accurate with
Visual Studio 2005 containing the latest service packs.


I don't now what execatly the statement that Return can be optimized better
was referrring to, so I can not give a good reason for it. Though, you are
creating an example where Return really doesn't make sense: Just at the end
of a Sub (Sub, not Function).

In your example, it is very simple why Test1 is slower: Return causes a jump
to the end of the procedure. In Test2 this superfluous step is left out,
therefore it's faster.

I pasted the IL code below. You don't have to speak IL, but you see that, in
Test2, there is a "br.s" command at position IL_0010. "br" = branch = jump
(to position IL_0012).

Test1:

IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldind.i8
IL_0004: ldc.i8 0x1
IL_000d: add.ovf
IL_000e: stind.i8
IL_000f: nop
IL_0010: ret

Tets2:

IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldind.i8
IL_0004: ldc.i8 0x1
IL_000d: add.ovf
IL_000e: stind.i8
IL_000f: nop
IL_0010: br.s IL_0012
IL_0012: nop
IL_0013: ret


This is the Debug build. Using the Release build, the execution time is
exactly the same, which means that the superfluous jump has been
optimized-away.

Well, it was /you/ putting an additional Return statement there to make it
slower. ;-)


Armin
 
J

jamil

On Thu, 9 Aug 2007 01:37:53 +0200, "Armin Zingler"

In my test, Test1 is actually faster with a release build. I have a
savings of over one second (which corresponds to the MSDN article).
Is it a hardware difference? Not sure.

Your MSIL is also very different than mine though.
 
J

jamil

I just ran the test a second time to make sure I wasn't imagining
things. These are my results:

With Return: 30062.5 Without Return: 31218.75

Test1 ran in around 30 seconds.
Test2 ran in over 31 seconds.

My build is Release:

Remove integer overflow checks is unchecked
Enable optimizations is checked

Target CPU: AnyCPU

Intel Core 2 Duo 6600
4 gigs RAM
Windows kernel loaded in RAM
 
?

=?ISO-8859-1?Q?G=F6ran_Andersson?=

On Thu, 9 Aug 2007 01:37:53 +0200, "Armin Zingler"

In my test, Test1 is actually faster with a release build. I have a
savings of over one second (which corresponds to the MSDN article).
Is it a hardware difference? Not sure.

Either hardware difference, or differences in the test situation. Have
you tried to switch the order of the loops, for example?

The result that I get is the opposite of yours.

I used System.Diagnostics.StopWatch to get a bit better resolution in
the timing, and I have tried to switch the loops, running each version
several times (but with a bit shorter loops, as the run time doesn't
have to be that long with a high resolution timer).
 
J

jamil

Interesting -- I tried switching the order of the loops to find that
on my machine, whichever loop executes first always has the best time.

So, my test proves absolutely nothing at all :)
 
C

Cor Ligthert[MVP]

Jamil,

It is an old publication based on technical facts. It is discussed more
times and a general answer is to make your program, see where 80 procent of
the time is spent and than optimize this.

Mostly you will see that between 0 and 20% of your program needs the most
time. This will however most probably not be in actions intern in memory
which are done in steps in the cycles which runs in pico seconds however in
the IO including screen handling. The later is often forgot and people makes
easily an extra show or refresh just to be sure it is showed.

Cor
 
A

Armin Zingler

Interesting -- I tried switching the order of the loops to find that
on my machine, whichever loop executes first always has the best
time.

So, my test proves absolutely nothing at all :)


Yes, the only difference I see is in Debug build. If you IL code is the same
(release config) for both subs, both /must/ take the same time (in theory),
so the 1 second for such a long loop - I made a shorter loop and used the
StopWatch, as Göran did - can vary for any reason.


Armin
 
J

jamil

Actually, I had totally forgotten one important thing in regards to
this test. Look at the size of the code in the MSIL. During runtime
execution, the compiler is not going to create a sub routine at all.
The code will be executed inline.

I am still curious on the results, so I will correct the experiment.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top