Benchmarking MicroLite 4.0 part 2

Following on from the findings in Benchmarking MicroLite 4.0 part 1 there are a few more things that are worth mentioning.

The cost of params – we use the params keyword throughout the MicroLite codebase for convenience where there there are an unknown number of parameter values which could be passed to a method (which is exactly what the params keyword is for).

Take the following piece of code for example:

var sqlQuery = new SqlQuery(
    "SELECT * FROM Table WHERE Column = @p0",
    "Foo");

When it is compiled, it essentially becomes this:

var args = new object[1];
args[0] = "Foo";

var sqlQuery = new SqlQuery(
    "SELECT * FROM Table WHERE Column = @p0", args);

Notice that the compiler has actually created an array of the correct size for the number of arguments, it does this even if there are no params:

var sqlQuery = new SqlQuery("SELECT * FROM Table");

Compiles to:

var args = new object[0];

var sqlQuery = new SqlQuery("SELECT * FROM Table", args);

This means for every call to a method with params signature, we require the allocation and garbage collection of an array even if there are no values to pass!

Resulting Change – We have added method overloads without params or with additional fixed size args where we might not have any arguments or only 1.

// Additional constructor for SqlQuery with no args
public SqlQuery(string commandText) { }
public SqlQuery(string commandText, params object[] arguments) { }

// Additional method for SqlBuilder with a single arg
IOrderBy OrderByAscending(string column);
IOrderBy OrderByAscending(params string[] columns);

Lesson – Understand the implications of convenience and allow alternatives to avoid unnecessary object allocations/collections.

Re-Generating the same SQL every time – in MicroLite 4.0, we were building the SQL statement every time we inserted/selected/updated/deleted/ an object, however thinking about this a bit more, the command text is always the same for a given class, only the values change per instance.

Resulting Change – We have implemented a query cache per mapped type for each of the CRUD operations (INSERT, SELECT, UPDATE and DELETE) which are generated the first time the action is invoked for a given class.

Lesson – DRY (don’t repeat yourself) can apply to the code executed inside a single method even if the code within that method is not duplicated elsewhere.

Moving to generated MSIL – in MicroLite up to version 5.0 we were using reflection to get and set property values and although the approach evolved over time to be faster it’s still nowhere near as quick as the method would be if you coded it by hand.

Resulting Change – We now generate a dynamic method at runtime by emitting the MSIL which would be produced to access the property.

// Generating the equivalent of:
var value = customer.Name;
Advertisements

One thought on “Benchmarking MicroLite 4.0 part 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s