5

I'm trying to troubleshoot some startup time concerns. After doing some profiling, I've found the main culprit is ClassProxyGenerator.GenerateCode. This takes 400-600ms per type the first time. So if the entry point to the application has 8 dependencies (in a chain) which need proxies generated, the startup time of the application goes up by 4.8 seconds. This might not seem like a lot, but to a user, it seems like ages.

Any advice for improving this?

Update:

I can reproduce the time with the following console application:

        var container = new WindsorContainer();
        container.Register(Component.For<Interceptor>()); // dummy IInterceptor...does nothing
        container.Register(Component.For<IMyRepository, MyAbstractRepository>().Interceptors<Interceptor>());
        var t = DateTime.Now;
        var instance = container.Resolve<IMyRepository>();
        Debug.WriteLine("Resolved in " + (DateTime.Now - t).TotalMilliseconds);

Outputs somewhere between 550ms and 750ms.

IMyRepository is a repository interface for 30 entity types (generated by a T4 template). It has 31 IQueryables, 31 Save overloads, and 31 Delete overloads. MyAbstractRepository is a partial abstract class. It declares the same 3 x 31 methods.

If I remove all the save and delete methods and leave just the 31 IQueryables AND don't register the abstract repository

  container.Register(Component.For<IMyRepository>().Interceptors<Interceptor>());

I still run around 250ms for the initial generation.

This is a very (very very) fast machine...so anything in the real world will likely perform slower than the numbers listed above.

Jeff
  • 35,755
  • 15
  • 108
  • 220
  • 1
    That's ridiculous - unless your types have hundreds/thousands of methods (or you're running the code on a 20 yo machine) that should not be the case. Can you create isolated reproduction? – Krzysztof Kozmic Sep 03 '11 at 04:13
  • I know...and it's not a 20 year old machine...It seems to be a specific set of types that have this holdup (others generate in 5-10ms)...I will isolate and provide a code sample. – Jeff Sep 03 '11 at 04:51
  • 1
    If you have dependencies where usage can be deferred, you might be able to hide that part of the dependency graph behind a virtual proxy. See here for an overview of the concept: http://blog.ploeh.dk/2011/03/04/ComposeObjectGraphsWithConfidence.aspx – Mark Seemann Sep 03 '11 at 06:28
  • 2
    @Mark - that'a a really good thought. I just cut down startup time by 2 of the 5 seconds. I'm still trying to reproduce in an isolated environment since Krzysztof's point that it's ridiculous is quite valid. – Jeff Sep 03 '11 at 21:42
  • Ok...so I thought I was going to eat my words and not be able to reproduce it in a console app...but lo and behold I did (updated question). Granted, the interface has more than 10 methods on it, but it's not hundreds... – Jeff Sep 04 '11 at 08:36
  • can you post entire, compilable code (or put it in dropbox and link to it?) – Krzysztof Kozmic Nov 06 '11 at 02:23
  • So, can you post the entire code of that reproduction to github or somewhere I can play with it? – Krzysztof Kozmic Jul 01 '12 at 20:49
  • Sorry, I know you asked for this a while ago....been very busy. I just put together a sample. Is email ok or should I create an item and upload it as an attachment? Whatever works best for you. – Jeff Jul 01 '12 at 21:59
  • I have the sample...just tell me how you want me to get it to you. – Jeff Jul 10 '12 at 18:44

1 Answers1

1

You might be able to perform the proxy initialization in a different thread, so that the application itself can continue to initialize while the proxies are generated. Consider queuing this into the threadpool.

Another option might be to compile the proxies into a persisted assembly file, which is then saved to disk. Doing this would significantly lower the startup time after the first run.

I'm not sure why Castle's dynamic proxies take so long to initialize. I don't use them, I usually emit code directly (either as LCG for simple methods, and via full Reflection.Emit for complete implementations). I never had such long delays, even when generating hundreds of LCG methods. Maybe using a different approach/library (LinFu etc.) might fix the issue as well.

Lucero
  • 59,176
  • 9
  • 122
  • 152