Static vs Non-Static Function Performance

  • Thread starter Thread starter Steve - DND
  • Start date Start date
S

Steve - DND

We're currently doing some tests to determine the performance of static vs
non-static functions, and we're coming up with some odd(in our opinion)
results. We used a very simple setup. One class had a static function, and
the one class had a non-static function. Both of these functions did the
exact same thing.

The test function:
public void Test(){
decimal y = 2;
decimal x = 3;
decimal d = 0;

for(decimal z = 0; z < 1000000;z++){
if(z % 2 == 0){
d = y*d;
} else {
d = x*d;
}
}
}

The test running code:
for (int i = 0; i < 1000; i++) {
StaticTest.Test();
}

for (int i = 0; i < 1000; i++) {
NonStaticTest nst = new NonStaticTest();
nst.Test();
}

To our suprise the non-static approach ran in 15 minutes, and the static
approach ran in 17 minutes. We had figured that due to the need to
instantiate a new object with each call for the non-static approach, that
this way would take longer. We also tried running the non-static approach
first, and the static approach second, the results were the same. We ran
these tests 3 times each to make sure that we got a nice average.

Did we somehow bias the test towards the non-static approach? How is it that
with an object instantion going on, the non-static approach is able to run
in 2 minutes less time. This is of course a substantially large margin, and
could have some definite performance implications for those building
performance oriented code.

Thanks,
Steve
 
Hi Steve,

There could be some optimisations going on that are giving false results.
 
Michael Culley said:
Hi Steve,

There could be some optimisations going on that are giving false results.

Any idea what these enhancements could be? They should be doing the same
thing, should they not?

Steve
 
Steve - DND said:
Any idea what these enhancements could be? They should be doing the same
thing, should they not?

I can see several posibilities. The compiler might work out that nothing is returned from the function so optimise out some of the
code in the function. It could treat the function as static because it doesn't use an module level variables and it might not even
bother creating the object at all. All of these are just guesses though.
 
Thats because static methods are using locks to be Thread-safe. The always
do internally a Monitor.Enter() and Monitor.exit() to ensure Thread-safety.
 
Michael Culley said:
I can see several posibilities. The compiler might work out that nothing
is returned from the function so optimise out some of the
code in the function. It could treat the function as static because it
doesn't use an module level variables and it might not even
bother creating the object at all. All of these are just guesses though.

Looks like you were correct. There seemed to be some optimizations going on.
When I changed things up a bit, I got *very* different results(static
running in less than 50% of the time).

Thanks,
Steve
 
codymanix said:
Thats because static methods are using locks to be Thread-safe. The always
do internally a Monitor.Enter() and Monitor.exit() to ensure Thread-safety.

Are you sure? Do you have a pointer to some docs that describe this?

I find it hard to believe that it would do this automatically, since
it's easy enough to place the entire method body in a lock statement
block, and there are many cases where static methods would have no need
to use Monitors to ensure thread safety.
 
Are you sure? Do you have a pointer to some docs that describe this?
Alvin Bruney said:
He is right. Take a look at the Il code or google for it.

I took a look at the IL code and disassembled code for both a static and
non-static function, and they're identical. Can you provide an example where
Monitor.Enter() or Monitor.Exit() is used automatically?

public class StaticTest {
public static void Test() {
decimal d = 2;
}
}

public class NonStaticTest {
public void Test() {
decimal d = 2;
}
}

***** Disassembly *****
..method public hidebysig instance void Test() cil managed
{
// Code size 8 (0x8)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Decimal d)
IL_0000: ldc.i4.2
IL_0001: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
IL_0006: stloc.0
IL_0007: ret
} // end of method NonStaticTest::Test



..method public hidebysig static void Test() cil managed
{
// Code size 8 (0x8)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Decimal d)
IL_0000: ldc.i4.2
IL_0001: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
IL_0006: stloc.0
IL_0007: ret
} // end of method StaticTest::Test

Steve
 
I think i am wrong on this one. The dissambly is painfully obvious that I
don't know what I am talking about :-)

--


-----------
Got TidBits?
Get it here: www.networkip.net/tidbits
Steve - DND said:
Alvin Bruney said:
He is right. Take a look at the Il code or google for it.

I took a look at the IL code and disassembled code for both a static and
non-static function, and they're identical. Can you provide an example where
Monitor.Enter() or Monitor.Exit() is used automatically?

public class StaticTest {
public static void Test() {
decimal d = 2;
}
}

public class NonStaticTest {
public void Test() {
decimal d = 2;
}
}

***** Disassembly *****
.method public hidebysig instance void Test() cil managed
{
// Code size 8 (0x8)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Decimal d)
IL_0000: ldc.i4.2
IL_0001: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
IL_0006: stloc.0
IL_0007: ret
} // end of method NonStaticTest::Test



.method public hidebysig static void Test() cil managed
{
// Code size 8 (0x8)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Decimal d)
IL_0000: ldc.i4.2
IL_0001: newobj instance void [mscorlib]System.Decimal::.ctor(int32)
IL_0006: stloc.0
IL_0007: ret
} // end of method StaticTest::Test

Steve
 
codymanix said:
Thats because static methods are using locks to be Thread-safe. The always
do internally a Monitor.Enter() and Monitor.exit() to ensure Thread-safety.

They definitely, definitely don't.

Here's an example program which shows two threads being in the same
method at the same time:

using System;
using System.Threading;

public class Test
{
static void Main()
{
Thread t1 = new Thread (new ThreadStart(Count));
Thread t2 = new Thread (new ThreadStart(Count));

t1.Name = "First thread";
t2.Name = "Second thread";

t1.Start();
t2.Start();
}

static void Count()
{
for (int i=0; i < 10; i++)
{
Console.WriteLine ("{0} {1}", i,
Thread.CurrentThread.Name);
Thread.Sleep (500);
}
}
}

If you put a lock in yourself, eg lock (typeof(Test)) round the body of
Count, you get radically different results (i.e. one thread does the
whole count, then the second one does).
 
Alvin Bruney said:
He is right. Take a look at the Il code or google for it.

Like Steve at DND, I did try this, and found no evidence of a simple
static method being automatically locked.
 
I took a look at the IL code and disassembled code for both a static and
non-static function, and they're identical. Can you provide an example where
Monitor.Enter() or Monitor.Exit() is used automatically?

It is done internally, there is no need that the il explicitly states it.
 
codymanix said:
It is done internally, there is no need that the il explicitly states it.

No, it's *not* done internally, as my other post showed. The only
locking which goes on at all is to make sure that the type has been
initialised.

Do you have any evidence at all for your claim?
 
Jon Skeet said:
Do you have any evidence at all for your claim?

This could be a myth that has been started because static methods are generally thread safe. It's kinda logical for someone to
conclude that some call is automatically made to make the method thread safe, when in fact it is thread safe (AFAIK, my knowledge of
threads is limited) because it does not use module level variables.
 
Stu Smith said:
Does anyone know where this urban myth about static methods got started?

I think it stems from the help files:

"Any public static (Shared in Visual Basic) members of this type are safe
for multithreaded operations. Any instance members are not guaranteed to be
thread safe."

I think people read that as "whats that skip.... the static memebers are
thread safe, they must be using some sort of locking mechanism...wicked i'll
pass that along"

andrew
 
Back
Top