[Mono-dev] Patch: Fast virtual generic method calls

Paolo Molaro lupus at ximian.com
Wed Oct 1 14:12:04 EDT 2008


On 10/01/08 Mark Probst wrote:
> Here's the patch again, updated with code to keep track of how many
> times a generic virtual method is invoked and to insert it in the thunk
> only if a threshold (currently 100) is reached.

100 seems high, especially since the lookup can be a O(n) list walk.
Maybe 10 is more appropriate.

> Index: metadata/object.c
> ===================================================================
> --- metadata/object.c	(revision 114206)
> +++ metadata/object.c	(working copy)
> +static void
> +init_thunk_free_lists (MonoDomain *domain)
> +{
> +	if (domain->thunk_free_lists)
> +		return;
> +	domain->thunk_free_lists = mono_mempool_alloc0 (domain->mp, sizeof (gpointer) * NUM_FREE_LISTS);

mono_domain_alloc0 () should be used, so that all the domain allocations
are properly tracked.

> +/*
> + * LOCKING: The domain lock must be held.
> + */
> +static void
> +invalidate_generic_virtual_thunk (MonoDomain *domain, gpointer code)
> +{
> +	guint32 *p = code;
> +	MonoThunkFreeList *l = (MonoThunkFreeList*)(p - 1);
> +
> +	init_thunk_free_lists (domain);
> +
> +	while (domain->thunk_free_lists [0] && domain->thunk_free_lists [0]->length >= MAX_WAIT_LENGTH) {
> +		MonoThunkFreeList *item = domain->thunk_free_lists [0];
> +		int length = item->length;
> +		int i;
> +
> +		/* unlink the first item from the wait list */
> +		domain->thunk_free_lists [0] = item->next;
> +		domain->thunk_free_lists [0]->length = length - 1;
> +
> +		i = list_index_for_size (item->size);
> +
> +		g_print ("putting thunk of size %d in list %d\n", item->size, i);

Leftover.

> +/**
> + * mono_method_add_generic_virtual_case:

Maybe invocation is better than case? Any other suggestion?

> +void
> +mono_method_add_generic_virtual_case (MonoDomain *domain, gpointer *vtable_slot,
> +	MonoGenericInst *method_inst, gpointer code)
> +{
> +	static gboolean inited = FALSE;
> +	static int num_added = 0;
> +
> +	GenericVirtualCase *gvc, *list;
> +	MonoImtBuilderEntry *entries;
> +	int i;
> +	GPtrArray *sorted;
> +
> +	mono_domain_lock (domain);
> +	if (!domain->generic_virtual_cases)
> +		domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
> +
> +	/* Check whether the case was already added */
> +	gvc = g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
> +	while (gvc) {
> +		if (gvc->inst == method_inst)
> +			break;
> +		gvc = gvc->next;
> +	}

This is the O(n) loop I mentioned. It shouldn't be a big deal, though.

> +
> +	/* If not found, make a new one */
> +	if (!gvc) {
> +		gvc = mono_mempool_alloc (domain->mp, sizeof (GenericVirtualCase));

mono_domain_alloc () here.

> Index: metadata/domain-internals.h
> ===================================================================
> --- metadata/domain-internals.h	(revision 114206)
> +++ metadata/domain-internals.h	(working copy)
> @@ -141,6 +141,12 @@
>  	MONO_APPDOMAIN_UNLOADED
>  } MonoAppDomainState;
>  
> +typedef struct _MonoThunkFreeList {
> +	guint32 size;
> +	struct _MonoThunkFreeList *next;
> +	int length;		/* only valid for the wait list */

Put the pointer first, so sie and length fit inside the other 8 bytes on
64 bit systems and the total size will be 16 instead of 24.

> --- mini/tramp-x86.c	(revision 114206)
> +++ mini/tramp-x86.c	(working copy)
> @@ -94,7 +94,7 @@
>  	} else {
>  		printf ("Invalid trampoline sequence: %x %x %x %x %x %x %x\n", code [0], code [1], code [2], code [3],
>  				code [4], code [5], code [6]);
> -		g_assert_not_reached ();
> +		//g_assert_not_reached ();

Leftover.

The rest of the code looks fine to me.
It would be nice to also see some speedup numbers from this change:)
Thanks!

lupus

-- 
-----------------------------------------------------------------
lupus at debian.org                                     debian/rules
lupus at ximian.com                             Monkeys do it better


More information about the Mono-devel-list mailing list