Question

When i create an object of a class which implements an interface via Activator.CreateInstance or via the new keyword, the execution speed clearly differs. The creation-kind which i use first ist the faster one for the rest of the program execution. I wrote the following "Performance-Test":

static private void SpeedTest(IPlugin plugin)
{
    Console.Write("SpeedTest of \"" + plugin.Name + "\": ");

    Stopwatch sw = new Stopwatch();

    int workingNumber = 0;

    sw.Start();

    for (int i = 0; i < 2147483647; i++)
    {
        plugin.Add(ref workingNumber);
        plugin.DSub(ref workingNumber);
        plugin.Add(ref workingNumber);
    }

    sw.Stop();

    Console.WriteLine(sw.Elapsed.ToString());
}

I load the instances of the classes implementing IPlugin via:

static void Main(string[] args)
{
    IPlugin pluginInstance = null;
    IPlugin localInstance = new LocalPlugin();

    Assembly plugin = Assembly.LoadFile("Path\\Plugin.dll");

    Type pluginInterface = typeof(IPlugin);

    foreach (Type type in plugin.GetTypes())
        if (pluginInterface.IsAssignableFrom(type))
            pluginInstance = (IPlugin)Activator.CreateInstance(type);

    SpeedTest(localInstance);
    SpeedTest(pluginInstance);
    SpeedTest(localInstance);
    SpeedTest(pluginInstance);
}

IPlugin looks like:

public interface IPlugin
{
    string Name { get; }

    void Add(ref int number);
    void DSub(ref int number);
}

The "local" Plugin (and the remote Plugin from Plugin.dll, which is the same except that it has a public-modifier and returns "Remote" instead of "Local") are looking like:

class LocalPlugin : IPlugin
{
    public string Name
    {
        get { return "Local"; }
    }

    public void Add(ref int number)
    {
        number++;
    }

    public void DSub(ref int number)
    {
        number -= 2;
    }
}

Here are both projects for you to download: ZIP-File with example projects

You need to compile the PluginHost-Project before the Plugin-Project.

Now the program-output for this test-block

SpeedTest(pluginInstance);
SpeedTest(localInstance);
SpeedTest(pluginInstance);
SpeedTest(localInstance);

is:

SpeedTest of "Plugin": 00:00:25.9785649
SpeedTest of "Local": 00:00:38.8875138
SpeedTest of "Plugin": 00:00:25.8757588
SpeedTest of "Local": 00:00:38.5222134

If i move the first line to the last position:

SpeedTest(localInstance);
SpeedTest(pluginInstance);
SpeedTest(localInstance);
SpeedTest(pluginInstance);

I get the following output:

SpeedTest of "Local": 00:00:26.1881051
SpeedTest of "Plugin": 00:00:38.9942815
SpeedTest of "Local": 00:00:25.9634257
SpeedTest of "Plugin": 00:00:38.6881451

Conclusion: The instantiation-kind i use first is faster than the second. This behaviour is method-independed.

Questions:

  1. Why is this so?
  2. What can i do to gain the same performance on every execution-kind?

regards,

Matthias

Was it helpful?

Solution

Buried in the following article is the cause:
A curious subtlety about how CLR does interface dispatch on array types

The specific text of interest is the following:

Our interface dispatch logic has an important optimization where FOR EACH CALL SITE, it checks one particular target explicitly, and if that fails, does slower hash table lookup, and if that lookup fails, fall back to an expensive lookup. Thus for calls sites that tend to go to one destination it is very fast, and call sites that go to many targets, you get good, but not as great performance.

The call site optimization is initialized according to the concrete type of the first object that appeared.

You should be able to produce a fair comparison by replacing the IPlugin interface in your test with a PluginBase class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top