Fasterflect vs HyperDescriptor vs FastMember vs Reflection

The other day I had a small task to inspect return values of methods and if the following property exists then set it to empty array.

        public long[] Achievements { get; set; }

This needed to happen once on every web request, and I decided to implement it as a PostSharp attribute. WHY I needed to do this is another interesting discussion, but broadly speaking boils down to assumptions baked into base class’s control flows  no longer holds true but is inflexible to change.

A major refactoring is in order, but given we have a deadline to meet, let’s take a technical debt and make sure it’s in the backlog so we know to come back to it.

 

So I went about finding a more efficient way of doing this than hand-writing some reflection code.

There’s Jon Skeet’s famous reflection post but to make it work across all types and incorporating IL emit is more complex than this task warrants.

sidebar : if you’re still interested in seeing how Jon’s technique can be applied, check out FSharpx.Reflection to see how it’s used to make reflection over F# types fast.

Then there’s Marc Gravell’s HyperDescriptor although the Nuget  package itself was authored by someone else. Plus Marc’s follow-up to HyperDescriptorFastMember.

I also came across a package called Fasterflect which I wasn’t aware of before, from its project page the API looks pretty clean.

 

Test 1 – 1M instances of MyTypeA

Suppose I have a type, with the Achievements property that I want to set to empty whenever I see it returned by a method.

image

To do this with reflection is pretty straight forward:

image

With Fasterflect, this becomes:

image

I do like this API, it’s very intuitive.

And here’s how it looks with HyperDescriptor and FastMember:

image

Now let’s run this across 1M instance of MyTypeA and see how they do. Both Fasterflect and FastMember did really well although HyperDescriptor was 3x slower than basic reflection!

image

 

Test 2 – 1M instances of MyTypeA and MyTypeB

Ok, but since this code has to work across many types, so we have to expect both

  • types that has this property, and
  • types that don’t

To simulate that, let’s introduce another type into the test.

image

Instead of working with an array of MyTypeA, now we have a mixed array of both MyTypeA and MyTypeB for our test.

image

and the result over 1M objects makes for interesting readings:

image

some observations from this set of results:

  • we need to invoke the setter on only half the objects, so reflection is faster (almost halved) than before, makes sense;
  • both FastMember and HyperDescriptor are faster due to the same reason as above;
  • having less work to do had much smaller impact on FastMember suggests some caching around the call site (and indeed it does);
  • WTF is going on with Fasterflect!

 

Conclusions

The morale of this story is that – always verify claims against your particular use case.

Another perfect example of this is Kyle Kingsbury’s work with Jepsen. Where he uses a generative testing approach to verify whether NoSQL databases actually provide the consistency model that they claims to offer. His findings are very interesting to read, and in many cases pretty worrying

Oh, and stick with FastMember or reflection 

 

Links

7 Comments

  1. Yan Cui   •  

    ah, it’s using exceptions for control flow and trading worst-case performance for convenience (in implementation), it makes sense now.

    Appreciate that you can work around it but the presence of the TrySetPropertyValue method is going to lure people (like it did me) into using it instead of checking if the property exists first then call SetPropertyValue. A convenient method with a 1000x worst-case (what I showed in this post is not the worst-case yet, see this for the cost of throwing exceptions http://theburningmonk.com/2011/09/the-cost-of-throwing-exceptions/) performance is a recipe for nasty surprises…

    I’ve raised it as an issue on the project’s CodePlex page but not sure if it’s being actively maintained, hopefully it gets fixed

  2. Andrew   •  

    It does not look like it is. This is an extremely fast and robust library but there are a few other issues like that. I did not raise them as the codeplex issue tracker is not active at all.

  3. theburningmonk   •     Author

    That’s a pity, good reflection libraries are few and far between in the .Net space, as I raised the issue I did notice a few open issues that’s been outstanding for a long time too, so looks like the project has been abandoned.

  4. Kurren Nischal   •  

    Very informative, thank you

  5. Pingback: Fasterflect, reflection do jeito simples e rápido – Pablo D. Pagués Ernst

  6. Kiran Singh Randhawa   •  

    Really liked your article! Thank you.

Leave a Reply

Your email address will not be published.