Property accessors and Optimization

G

Guest

Given a property define like this:

public decimal ControlAmount
{
get { return mControlAmount; }
set { mControlAmount = value; }
}

I expected (under release mode) that when used as a variable in normal code
(ie, nothing that is enumerating properties or requiring metadata) eg:

ControlAmount += MyValue;

That the get accessor would be "optimized out", and replaced with direct
access to the variable (like an "inline function"). This is what would have
happened in C++ or Delphi.

However, I am finding that this is not the case in my code, even in release
mode. I profile my application, and find that the get_ControlAmount function
not only gets called *all the time*, but that it has significant overhead -
much more so than a simple member variable access.

Is there any way to optimize simple properties like this, or ensure that the
optimizer is able to remove the call?
 
W

Willy Denoyette [MVP]

Did you compile with optimizations turned on (command line argument
/optimize+)?
If you didn't, the JIT will not optimize the getter body.
Note also that the getter is inlined, what's not inlined is the code
generated by:
return mControlAmount;
guess this is done in order to reduce the code size.

Note that System.Decimal is a complex type, and the JIT will try to optimize
it's behavior by using MMX instructions when available on the platform.

Willy.

| Given a property define like this:
|
| public decimal ControlAmount
| {
| get { return mControlAmount; }
| set { mControlAmount = value; }
| }
|
| I expected (under release mode) that when used as a variable in normal
code
| (ie, nothing that is enumerating properties or requiring metadata) eg:
|
| ControlAmount += MyValue;
|
| That the get accessor would be "optimized out", and replaced with direct
| access to the variable (like an "inline function"). This is what would
have
| happened in C++ or Delphi.
|
| However, I am finding that this is not the case in my code, even in
release
| mode. I profile my application, and find that the get_ControlAmount
function
| not only gets called *all the time*, but that it has significant
overhead -
| much more so than a simple member variable access.
|
| Is there any way to optimize simple properties like this, or ensure that
the
| optimizer is able to remove the call?
|
|
 
M

Mattias Sjögren

Jaimi,
Is there any way to optimize simple properties like this, or ensure that the
optimizer is able to remove the call?

Which profiler are you using? It's possible that it prevents certain
jit optimizations from happening. Simple property accessors like these
should definitely be inlined.


Mattias
 
G

Guest

Thank you for your response. I'm using the profiler that is built into
"Visual Studio 2005 Team Edition for Software Developers", and I configured
it to use Instrumentation instead of sampling. Are there any known issues
with this profiler or configuration? It appears that it instruments the
module after compiling, and I would have thought that these kind of
optimizations would be done by the compiler (and not by the JIT). Is this not
the case?
 
G

Guest

Yes, definitely optimizations are on, and in release mode. I was dealing with
a performance problem (testing with the VSTE profiler in release mode), when
I saw all of the getters on the classes taking a considerable amount of time.
I solved the original issue, but just that fact that the getters existed was
disturbing - on every property, even ints.
Mattias suggested that perhaps this is caused by the profiler itself an is
not indicative of normal behavior (which leads me to question the usefulness
of the profiler, if the very use of it will remove such basic optimization).
 
J

Jon Skeet [C# MVP]

Jaimi McEntire said:
Thank you for your response. I'm using the profiler that is built into
"Visual Studio 2005 Team Edition for Software Developers", and I configured
it to use Instrumentation instead of sampling. Are there any known issues
with this profiler or configuration? It appears that it instruments the
module after compiling, and I would have thought that these kind of
optimizations would be done by the compiler (and not by the JIT). Is this not
the case?

No, inlining is done by the JIT. This is absolutely necessary, as
properties are used by classes which wouldn't have access in the IL to
the backing fields. The compiler has to emit valid IL, which can't
access the field, so the JIT has to do the inlining.
 
G

Guest

Ok - a better use of Google found the following post from Microsoft. It
appears that the JIT doesn't optimize release builds when run from Visual
Studio. I'm still under the opinion that these sorts of optimization would be
better handled at the compiler instead of relying on the JIT, but oh well. I
suppose the profiler isn't completely worthless, though it now seems
considerably less handy. Thanks for the responses.
 
W

Willy Denoyette [MVP]

Note that in this case (a Decimal property) the JIT doesn't inline the
property accessor.
My guess is that the JIT chooses to 'not inline' in favor of working set
size (a speed/space tradeoff).

Take a look at the disassembly of the getter:
00000000 57 push edi

00000001 56 push esi

00000002 8B FA mov edi,edx

00000004 83 C1 0C add ecx,0Ch

00000007 3B 09 cmp ecx,dword ptr [ecx]

00000009 8B F1 mov esi,ecx

0000000b F3 0F 7E 06 movq xmm0,mmword ptr [esi]

0000000f 66 0F D6 07 movq mmword ptr [edi],xmm0

00000013 F3 0F 7E 46 08 movq xmm0,mmword ptr [esi+8]

00000018 66 0F D6 47 08 movq mmword ptr [edi+8],xmm0

0000001d 5E pop esi

0000001e 5F pop edi

0000001f C3 ret



and compare it to the code generated for the direct field access.





00000113 8D 7D E4 lea edi,[ebp-1Ch]

00000116 8B 45 D0 mov eax,dword ptr [ebp-30h]

00000119 3A 40 0C cmp al,byte ptr [eax+0Ch]

0000011c 8D 70 0C lea esi,[eax+0Ch]

0000011f F3 0F 7E 06 movq xmm0,mmword ptr [esi]

00000123 66 0F D6 07 movq mmword ptr [edi],xmm0

00000127 F3 0F 7E 46 08 movq xmm0,mmword ptr [esi+8]

0000012c 66 0F D6 47 08 movq mmword ptr [edi+8],xmm0



The first has 13 instructions, the second 8. That means that the latter must
be something like 35% faster, but at the expense of 30 bytes injected at
each call site.



Willy.






| Ok - a better use of Google found the following post from Microsoft. It
| appears that the JIT doesn't optimize release builds when run from Visual
| Studio. I'm still under the opinion that these sorts of optimization would
be
| better handled at the compiler instead of relying on the JIT, but oh well.
I
| suppose the profiler isn't completely worthless, though it now seems
| considerably less handy. Thanks for the responses.
|
| >James,
| >The Energy function should be inlined. Were you running your test from
| >within Visual Studio? If so, be aware that the JIT generates
non-optimized
| >code if you start the application from with VS, even if it is a release
| >build. I suggest that you use the cordbg debugger and look at the
| >disassembly. You will have to set the JitOptimization mode on before the
| >containing method is JITted.
| >
| >Gregor
| >CLR Performance PM
| >Microsoft
|
|
| "Jaimi McEntire" wrote:
|
| > Given a property define like this:
| >
| > public decimal ControlAmount
| > {
| > get { return mControlAmount; }
| > set { mControlAmount = value; }
| > }
| >
| > I expected (under release mode) that when used as a variable in normal
code
| > (ie, nothing that is enumerating properties or requiring metadata) eg:
| >
| > ControlAmount += MyValue;
| >
| > That the get accessor would be "optimized out", and replaced with direct
| > access to the variable (like an "inline function"). This is what would
have
| > happened in C++ or Delphi.
| >
| > However, I am finding that this is not the case in my code, even in
release
| > mode. I profile my application, and find that the get_ControlAmount
function
| > not only gets called *all the time*, but that it has significant
overhead -
| > much more so than a simple member variable access.
| >
| > Is there any way to optimize simple properties like this, or ensure that
the
| > optimizer is able to remove the call?
| >
| >
 

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