14

It seems that every post I have come across comes to the same consensus: properties that merely return a field are inlined by JIT and have nearly identical performance to fields.

However, this doesn't seem to be the case with my current scenario. My program does intensive calculations that access many properties that are simply auto-getters and private setters. In this particular case, however, I am just copying an object.

Profiling the code in release mode with optimizations enabled resulted in many calls to the get functions of the property. The calls to Copy() total up to ~5.6ms.

Properties benchmark

However, when the properties are converted into fields, the function runs 6x faster than it did with properties:

enter image description here

Comparing equality of two properties seems to incur even more of a performance hit compared to using fields. Here's a benchmark of a class's IEquatable implementation, using the same code but swapping properties with fields.

enter image description here

If JIT is supposed to optimize properties by inlining them, why is this occuring? I would like to keep properties, as the access control aspect of them is very convenient, but if they are this much slower I will stick to fields.

EDIT: It seems like some (but not all) cases affected by this problem are using properties declared in interfaces. No other polymorphism is being used in these cases, but removing the interface brings the performance variance into expected levels in these cases.

EDIT 2: As stated in the previous edit, it seems that a part of the problem was due to Interface virtual calls. After more investigation, it seems that running a benchmark in the CLR properly inlines properties, but JetBrains dotTrace does not, even with "Enable inline" checked.

Haus
  • 1,492
  • 7
  • 23
  • Is this `Release` or `Debug` version – Hasan Emrah Süngü Dec 14 '18 at 02:51
  • Release, 64 bit, Dotnet Core 2.1 with optimizations on – Haus Dec 14 '18 at 02:53
  • I am just doing a simple test on my local as the following `obj.Property = 5;` and `obj.Field = 5;` During the debugging when I turn on Dissassembly window I can see that both of the calls are the same. So I am assuming your Objects accessed by Auto Properties are a little bit big in size so they are not getting inlined... There are many rules to inlining her you can check some of them https://stackoverflow.com/questions/4660004/when-is-a-method-eligible-to-be-inlined-by-the-clr – Hasan Emrah Süngü Dec 14 '18 at 03:08
  • if you access the same property many times `var a = obj.PropertyA.Something();` then next line `var b = obj.PropertyA.Anotherthing();` then next line `var c = obj.PropertyA.OneAnotherthing();` I suggest get `PropertyA` into a local variable then call methods etc `var localProp = obj.PropertyA` – Hasan Emrah Süngü Dec 14 '18 at 03:16
  • In the consuming code are you making interface calls or direct calls? If interface calls see [Performance of “direct” virtual call vs. interface call in C#](https://stackoverflow.com/q/7225205). – dbc Dec 14 '18 at 04:12
  • Does this answer your question? [Why are public fields faster than properties?](https://stackoverflow.com/questions/632831/why-are-public-fields-faster-than-properties) – Peter Duniho Jun 24 '21 at 17:54

1 Answers1

3

Unfortunately the is not much more you can do except try to help the JITTER out by using

[MethodImpl(MethodImplOptions.AggressiveInlining)]

AggressiveInlining The method should be inlined if possible.

Now technically this can only be used on a method or construtor, however you can seemingly test it on the getters and setters them selves. ie it compiles (i haven't tested this though)

public int someType
{
   [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
   get;
   [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
   set;
}

Note : in-lining is a blackbox of wonderment, the jitter may feel like it or not, even the attribute is only a suggestion. also note that the bitness may also affect what it inlines.

Lastly, i think you are going about this the right way, you should just use a bechmarker or profiler, and micro-optimize accordingly,

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Hmm, even manually suggesting inlining like that doesn't seem to help performance at all. Interestingly enough, it seems like (in some, but not all cases) the culprit is that the properties are declared in an interface that the class inherits. No abstract inheritance, just implementing the interface. I guess the JIT doesn't optimize those? – Haus Dec 14 '18 at 03:25
  • @Haus as for interfaces, yeah there might more going on. i am guessing you will have to just go with feilds, and intuative optimizations based on your performance results. im not sure there is a way around forcing the jitter to inline in certain cases – TheGeneral Dec 14 '18 at 03:54