Performance of .Net reflection on mobile devices (via Xamarin and C#)

.Net reflection can be very handy to automate development tasks involving objects, without typing (or even knowing) the names of the properties.

For instance, if you need to copy properties between different types of objects (think of domain object to view model copies  – and vice versa – in MVC projects), it is difficult, today, to resist the comforts of frameworks like Automapper, EmitMapper, ValueInjecter, BLToolkit and others.

But how does reflection perform on mobile with Xamarin? In some cases, it can’t perform at all, because Apple doesn’t allow dynamic code creation (think System.Reflection.Emit). In other cases, it performs reasonably well only if we don’t ask the simulator (and more so the device) to crunch very big amounts of objects.

We created a little project  to test how copy of C# objects via reflection performs on mobile. We created a class (“Narcissus Copier”) that uses reflection to copy property among objects.

With Narcissus, we can do two things:

  • Copy values between two objects based on common property names and types (we check what these common properties are each time we copy two objects);
  • Copy values between two objects based on equal property names, with the premise that the corresponding property names and types are “registered” beforehand in the utility (we check what these common properties are only once in the app).

This is a link to the overall solution that includes both the “Narcissus” copier and the iOS project:

https://github.com/RickCSharp/NarcissusCopieriOStest

This is the method that copies the properties of a “source”object on a “destination” object.

// This method allows you to copy an object on another object, based on the common properties they have.
		// Syntax:
		// NarcissusCopier<TypeOfSourceObject, TypeOfDestinationObject>.CopyAnyObject(SourceObjectInstance, DestinationObjectInstance);
		// To improve performance in case the copies of two objects are executed more than once, 
		// the method pair RegisterObjectProperties and CopyRegisteredObject is more indicated
		public static void CopyAnyObject(TSource source, TDestination destination)
		{
			var propertiesOfSource =
                           source.GetType().GetProperties();
			var propertiesOfDestination =
                           destination.GetType().GetProperties();
			var propertiesInCommon =
				(from a in propertiesOfSource
				 join b in propertiesOfDestination
				 on new { a.Name, a.PropertyType }
                                 equals new { b.Name, b.PropertyType }
				 select a);
			foreach (var propertyInCommon in propertiesInCommon)
			{
			var valueOfPropertyToCopy =
propertyInCommon.GetValue(source, null);
			PropertyInfo propertyOfDestinationToReplace =
destination.GetType().GetProperty(propertyInCommon.Name);	
			propertyOfDestinationToReplace.SetValue(destination,
                          Convert.ChangeType(valueOfPropertyToCopy,
                          propertyOfDestinationToReplace.PropertyType),
                          null);
			}
		}

The idea to test how reflection copy performs is:

  • We create 1000, 10K, 100K, 200K, 500K instances of two pairs of mildly compatible complex classes (i.e.: each pair has some common properties, but some are not common);
  • We copy the values of the properties of the instances of the first type of objects on the properties of the second types of objects;
  • First we do it without reflection (“direct” copy);
  • Then we do it with reflection, but without “registering” the object pairs (that is to say the common properties are evaluated every time we ask the method to perform a copy);
  • Last, we do the copy with reflection more “prepared”, that is to say by first “registering” the object pairs (every time we ask the method to perform a copy, the common properties are already known).

 

We will take advantage of this test to also see how different the iOS simulator and the actual devices perform (or don’t perform, in a case).

Performance in the simulator (real device tests are below)

Here are the results of the direct copy / reflection copy on an iPhone 6plus (iOS 9.3) simulator (this is important to underline because on the real device it will be a totally different story) running on a macBookPro i7 8Gb RAM:

Test 1:
1,000 object copies in the simulator. Not a lot of difference between “direct” copy and copy via reflection

Simulator Screen Shot 02 Jul 2016 19.38.21

Test 2:
10,000 object copies in the simulator. The difference begins to be important (5x slower in the best reflection case).

Simulator Screen Shot 02 Jul 2016 19.39.00

Test 3:
100,000 object copies in the simulator. The non-reflection methods continue to perform well. Code is reused very well by the runtime. Reflection code is not.

Simulator Screen Shot 02 Jul 2016 19.39.38

Test 4:
200,000 object copies in the simulator. Performance degrades in the reflection part of the copy.

Simulator Screen Shot 02 Jul 2016 19.40.41

Test 5:
500,000 object copies in the simulator. This is an extreme case (it wouldn’t be a good idea to modify 500,000 objects in a mobile app, would it?), but this example does show some pitfalls of reflection.

Simulator Screen Shot 02 Jul 2016 20.11.40

Performance on a real device (iPhone 6plus)

Comparing the simulator to the real device is interesting because there is one particular case (the 500,000 objects) that the device cannot even work with because of insufficient memory. This reminds us once again that the simulators must be used with a grain of salt.

Test 1 on iPhone:
1,000 object copies in the real device. Not a lot of difference between “direct” copy and copy via reflection nor between Simulator and real device

IMG_1630

Test 2 on iPhone:
10,000 object copies in the real device. The performance of copy without reflection is still good. The performance of copy via reflection is comparable to that of the simulator.

IMG_1631

Test 3 on iPhone:
100,000 object copies in the real device. The performance of copy without reflection is still good. However, the device begins to degrade both compared to the “simple” copy and compared to the simulator.

IMG_1632

Test 4 on iPhone:
200,000 object copies in the real device. The performance of copy without reflection is still good. The device is three time slower than the simulator in this case.

IMG_1633

Test 5 on iPhone:
…last, 500,000 object copies in the real device. The performance cannot be shown as the creation of 500,000 complex objects on an iPhone 6plus results in the crash of the app.

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