[Mono-devel-list] Cross application domain call optimization

Lluis Sanchez lluis at ximian.com
Fri Oct 15 16:53:34 EDT 2004


Here is the first version of a patch that improves the performance of
cross app domain calls. I still have a small regression when using
ContextBoundObjects but I hope I'll fix it soon. Other than that, the
patch is fully working.

The idea is to use special fast remoting wrappers for proxies that
reference objects in another domain in the same process. Those wrappers
are fast because they bypass the remoting infrastructure and make direct
calls from one domain to the other (doing the proper marshalling). I've
written a more detailed explanation in docs/remoting (included in the
mono patch).

The performance improvement varies depending on the signature of the
method, since different types have different marshalling needs, and some
marshalling operations can be faster than others.

Here are some numbers. I ran a series of 100.000 method invocations
using different method signatures, which are the following:

loc:  void Test (int i) (local call, not xdomain, just for reference)
int:  void Test (int i)
virt: virtual void Test (int i)
data: void Test (Data d) (where Data is: class Data { int p; })
str:  void Test (string s) (test run with s = "hola")
byte: void Test (byte[] b) (test run with b = new byte[1000])

The first set of numbers is for the current implementation of the cross
app domain channel (values are in milliseconds):

loc:  47,754	
int:  6775,998
virt: 6719,187
data: 29211,734
str:  6941,107
byte: 8076,06

This set is with the patch:

loc:  45,629
int:  585,221
virt: 532,792
data: 21213,898
str:  661,101
byte: 1310,84

We are getting an important speed up, 10x in some cases. The worst case
is the one with the Data instance, since it needs to use serialization
and most of the time is spent in BinaryFormatter. The other cases
(primitive types and arrays of primitive types) don't need serialization
and the improvement is really noticeable.

However, there is a drawback: we need to generate two additional methods
for each remotable method. As an example, a monodevelop run creates
around 80 wrapper methods + 80 helper methods, averaging 435 bytes of IL
per couple, which means 34kb of IL code (plus the memory of internal
data structures). And all this is dead code, since monodevelop does not
use app domains, but the wrappers are generated for every call to a non-
virtual MarshalByRefObject method. The reason is that those calls are
made through the remoting-invoke-with-check wrapper, wich has a
reference to the other wrappers.

One solution is to modify remoting-invoke-with-check and dynamically
generate the xdomain wrapper only if needed. There is a slowdown doing
this since it needs to check the hashtable of wrappers for every call,
but we still get a good performance. These are the numbers (define
REMOTING_INDIRECT_WRAPPER to enable this behavior):

loc:  47,456
int:  1668,613
virt: 529,636
data: 22501,112
str:  1743,557
byte: 2511,292

The virtual call is not made through the remoting-invoke-with-check
wrapper, so the time don't change here. I'm sure it is possible to do
some tricks in the JIT to lazily create the wrappers and get a better
performance without the memory penalty.

OK, that's all for now. Comments are wellcome.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: mcs.diff
Type: text/x-patch
Size: 8627 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20041015/b39fe2bd/attachment.bin 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mono.diff
Type: text/x-patch
Size: 88570 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20041015/b39fe2bd/attachment-0001.bin 

More information about the Mono-devel-list mailing list