[Mono-devel-list] [GMCS] [PATCH] helper_compile_generic_method and poor performance

Michal Moskal michal.moskal at gmail.com
Wed Jul 20 17:48:16 EDT 2005


Hello,

I've been further investigating poor mono performance on generic code, reported
in #75444.  By comparing profiler[1] logs of the generic and non-generic
compiler I found a method that now takes 20x more time to execute and later
created a micro benchmark:

#v+
class C {
  public void foo<T> (T t)
  {
  }

  public static void Main ()
  {
    for(int i = 0; i < 10000; ++i) {
          C q = new C();
          q.foo ("foo");
    }
  }
}
#v-

This gives:

Mono Jit statistics
Compiled methods:       10040

(and yes, of you increase the loop counter you'll get more methods compiled).
This takes lots of time.

Anyway the problem is that helper_compile_generic_method calls 
mono_class_inflate_generic_method which doesn't cache the results,
which in turn means g_hashtable misses in jit_code_hash. 

Note that this is not about code sharing -- the instances are exactly
the same, moreover from the same call site.

Now helper_compile_generic_method is ,,called'' from mono_method_to_ir
(in mini.c), opcode CEE_CALLVIRT. It is called only for callvirt (not
for regular call), and only when the method called is generic. I disabled
it there (so it handled it like non-virt calls), and the compile time
drop down from 55s to 30s.

The question is what is it for? I guess this is for the case when a
generic method is overridden in a derived class. If so maybe the attached
patch, which enables helper_compile_generic_method only when the method
is virtual and non-final could be applied? It works for me 
performance-wise like disabling this altogether.

I actually wanted to test if I didn't break anything, so I come up with
a test (I couldn't find anything in tests/gmcs):

#v+
class C1 {
  public virtual int foo<T> ()
  {
    return 1;
  }
}

class C2 : C1 {
  public override int foo<T> ()
  {
    return 2;
  }
}

class T {
  public static int Main ()
  {
    	C1 c1 = new C1 ();
        for (int pass = 1; pass <= 2; ++pass) {
          if (c1.foo<int>() != pass)
            return 1;
          c1 = new C2 ();
        }
        return 0;
  }
}
#v-

However even with unpatched mono it gives:

** ERROR **: file object.c: line 1149 (mono_object_get_virtual_method):
assertion failed: (res)

-- 
   Michal Moskal,
   http://nemerle.org/~malekith/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: perf.patch
Type: application/octet-stream
Size: 638 bytes
Desc: not available
Url : http://lists.ximian.com/pipermail/mono-devel-list/attachments/20050720/14a683b2/attachment.obj 


More information about the Mono-devel-list mailing list