db4o Developer Community

db4o open source object database, native to Java and .NET
Welcome to db4o Developer Community Sign in | Join
in Search
More Search Options

Product News from the Core Team

This blog features product news right from the core developer team, once new features and functions get checked into Subversion, available as Continuous Build every 2 hours.

Fast Reflection for .Net

Hi,

Recently we decided to evaluate how much impact (in performance) reflection represented in db4o.

In .Net side we already knew (due to previous experience) that reflection is not as fast as we would like to.

At the same time, profiling proved that reflection was not a bottleneck in Java side.

So we settled up for trying to replace the reflection layer (in .Net) used to set / get field values at store / retrieval time.

What we did was basically emit a setter / getter method dynamically (using DynamicMethod) for each field. These setters/getters are able to directly access object's fields (even private ones),completly avoiding reflection (to be more precise, reflection is used to some extent to generate the setter/getter methods). Once generated we keep these setter/getter methods cached to avoid regenerating them needlessly. In other words we are trading space (memory) for performance.

One aspect of current implementation is that the getter/setters cache grows indefinitely. If we do get reports about performance improvements, and so we decide to use this mechanism (either by default or through a configuration) we can introduce MRU (or MFU) and cache expiration strategies to keep memory usage as low as possible).

Even doing some benchmarks we don't have enough data to take conclusions. For instance, our benchmarks pointed to a 8 ~ 10% improvement but when we tried to run our full test suite with this new "reflection" layer we got worst results (more time to run) (but surely our test suite is not a good candidate as a benchmark for this setting; it has lots of different classes and do lots of disk accesses to emit assemblies for regression tests and the like).

The version in trunk still uses the traditional reflection layer by default. You can configure your application to use the fast reflection layer with:

IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();
config.Common.ReflectWith(new FastNetReflector());
IObjectContainer db = Db4oEmbedded.OpenFile(config, "database.odb");

Alternatively you can recompile the Db4objects.Db4o assembly so it uses the new reflection by default. All you have to do is to define a USE_FAST_REFLECTION symbol and recompile db4o assembly.

So, if you think this "reflection less" getters/setters could improve performance for you and you are willing to help db4o community, please, use it (either by configuring the reflector or by recompiling db4o with USE_FAST_REFLECTION) and deploy your application to an environment as close to a live one as possible and gather some data regarding performance and let us known.

Best

Adriano / Rodrigo

Published Monday, November 10, 2008 5:30 PM by Adriano Verona
Filed under: , , ,


Comments

 

Adam Dixon-Chapman said:

Hi guys... I haven't visited for a long while, but thought I'd stick my head in and see what was new :)

Interesting that you have only just moved to using DynamicMethod to speed up your runtime access to fields... I had assumed you would have been doing this already (guess I should have had a proper look thru the source).

Something which you guys may like to try in the same vein is generating a dynamic method for each class/type to act as a factory for creating object instances... so instead of using Activator.CreateInstance, you cook up a delegate which is hard-wired to just contain the IL to "return new Foo()" ... e.g.

public delegate T ConstructorDelegate<T>();

...

public static ConstructorDelegate<T> CreateConstructorMethod<T>()

{

           Type type = typeof(T);

           DynamicMethod method = new DynamicMethod(type.FullName + "_InstanceFactory_StrongTyped" + type.Name, type, null, type, true);

           ILGenerator ilGen = method.GetILGenerator();

           ConstructorInfo constructor = type.GetConstructor(Type.EmptyTypes);

           // emit code to instantiate new instace of the type using the 'new' operator

           // (rather than rely on Activator.CreateInstance)

           ilGen.Emit(OpCodes.Newobj, constructor);

           ilGen.Emit(OpCodes.Ret);

           return method.CreateDelegate(typeof(ConstructorDelegate<T>)) as ConstructorDelegate<T>;

}

From this, you should see a very decent increase in performance for object instantiation... a contrived test that just loops creating objects should demonstrate it to be about 3-4X faster - pretty much exactly the same as justing statically calling 'new'.

Between that little trick and using DynamicMethod delegates to move data in and out of private fields directly, I saw about a 5-6X speed increase (for instantiation and loading of objects) in my little home-brewed O/R mapper.

Anyway, hope that was useful in some way ;)

Adam

November 13, 2008 12:15 AM
 

Adriano Verona said:

Hi,

Thanks for the suggestion.

In the desktop we probably want to stick to FormatterServices.GetUninitializedObject() so we don't require a valid constructor.

Since this API doesn't exist in Compact Framework we DO want to emit code to call the constructor avoiding Activator.CreateInstance() altogether.

We created a Jira issue for it: http://tracker.db4o.com/browse/COR-1464

Thanks.

Adriano

November 18, 2008 11:00 AM
Anonymous comments are disabled

This Blog

Syndication RSS Feeds

News

Get the latest features every 2 hours with the Continuous Build!