Yes & yes. On Thu, Sep 17, 2009 at 11:05 PM, Cesar Sanz <[email protected]>wrote:
> Hi, > > I've followed this thread very close. > > Think this is an important performance issue to consider. > > Do you think, seriously, in improve this? > Do you think this is achievable? > > Regards > > ----- Original Message ----- > *From:* Ayende Rahien <[email protected]> > *To:* [email protected] > *Sent:* Thursday, September 17, 2009 1:55 PM > *Subject:* Re: long startup time > > Tyler, > No, it isn't. > Basically, I think we need to restructure the way we do this so we will > defer that as late as possible (to the first resolve call, I think.). > > > On Thu, Sep 17, 2009 at 8:09 PM, Tyler Burd <[email protected]> wrote: > >> Attached is the profiling screenshot for a VERY simple console app (code >> below). It took so long to profile that I didn't have the patience to wait >> until all 1000 services were registered, but this clearly shows where the >> problem lies. >> >> Total calls to AddComponent: 409 >> Total calls to AbstractHandler.DependencySatisfied: 83,773 >> >> >> If I try to profile my original app, it times out and causes a profiler >> error even when left overnight to finish starting up. When I stopped the >> profiler after 30 minutes of running I saw over 600,000 calls to >> DependencySatisfied. >> >> Am I wrong in thinking that 1000 services is not THAT many in a well >> designed app? I have a large financial app that has many complicated >> processes, so I split out every process into isolated services. I also use >> a service to encapsulate ever query with a dedicated service interface. The >> number of services registered adds up fast, but it sure seems like the >> right, maintainable, and testable way to do things. >> >> >> Profiled code: >> >> var container = new WindsorContainer(); >> var kernel = container.Kernel; >> >> for (int i = 0; i < 1000; i++) >> { >> kernel.AddComponent("key" + i, typeof(string), typeof(string)); >> } >> >> Console.ReadLine(); >> >> >> >> -----Original Message----- >> From: [email protected] [mailto: >> [email protected]] On Behalf Of Mauricio Scheffer >> Sent: Wednesday, September 16, 2009 8:28 PM >> To: Castle Project Users >> Subject: Re: long startup time >> >> >> It's definitely the HandlerRegistered event, or more likely >> AbstractEventHandler.DependencySatisfied()... here's a little test: >> >> import System >> import System.Diagnostics >> import Castle.Windsor from Castle.Windsor >> import Castle.MicroKernel from Castle.MicroKernel >> import Castle.MicroKernel.Handlers from Castle.MicroKernel >> import Castle.MicroKernel.SubSystems.Naming from Castle.MicroKernel >> import Castle.MicroKernel.ModelBuilder from Castle.MicroKernel >> >> def KernelAddComponent(k as IKernel): >> for i in range(1000): >> w = Stopwatch() >> w.Start() >> k.AddComponent("key${i}", typeof(string), typeof(string)) >> w.Stop() >> print "${i} took ${w.ElapsedMilliseconds}" >> >> class CustomKernel(DefaultKernel): >> override def RaiseHandlerRegistered(h as IHandler): >> pass >> >> KernelAddComponent(DefaultKernel()) >> >> Change the DefaultKernel() to CustomKernel() and the perf hit goes >> away. >> >> >> On Sep 16, 2:00 pm, Tuna Toksoz <[email protected]> wrote: >> > N! times? How? >> > >> > Tuna Toksöz >> > Eternal sunshine of the open source mind. >> > >> > >> http://devlicio.us/blogs/tuna_toksozhttp://tunatoksoz.comhttp://twitter.com/tehlike >> > >> > >> > >> > On Wed, Sep 16, 2009 at 12:59 PM, Ayende Rahien <[email protected]> >> wrote: >> > > IIRC, the culprit is the ComponentRegistered event, that is being >> raised N! >> > > times >> > > We had to do that when we use the AddComponent model, but with >> Register, we >> > > can probably optimize this. >> > >> > > On Wed, Sep 16, 2009 at 7:54 PM, Tyler Burd <[email protected]> wrote: >> > >> > >> I'm not sure how feasible that idea could be. SO much of an >> application >> > >> depends on having everything registered and ready to go before any >> actual >> > >> services are invoked. For instance, my project uses Rhino Service >> Bus, >> > >> which depends heavily on the GetAssignableHandlers and similar >> methods on >> > >> the kernel. If a critical message came in and we weren't finished >> > >> registering services (AKA Message Consumers), that message could be >> lost >> > >> forever since GetAssignableHandlers would not return all of the >> expected >> > >> handlers. >> > >> > >> I'd much rather have some form of lazy initialization of handlers and >> > >> dependencies to amortize whatever this startup cost is, but I'm not >> sure >> > >> right now how that might look. >> > >> > >> -----Original Message----- >> > >> From: [email protected] [mailto: >> > >> [email protected]] On Behalf Of James Curran >> > >> Sent: Wednesday, September 16, 2009 10:31 AM >> > >> To: [email protected] >> > >> Subject: Re: long startup time >> > >> > >> This leads to interesting question. Since, one presumes you won't >> > >> need all 1000 service immediately, could building the container be >> > >> spun off as a background task? This of course would lead to some >> > >> interesting race conditions, but if most of those services are for >> > >> corner cases (ie, say 90% of your functionality could be handled by >> > >> 10% of the services), then it just become a case of filling it in th >> > >> eproper order, and releasing semaphores as you go. >> > >> > >> On Wed, Sep 16, 2009 at 12:05 PM, Tyler Burd <[email protected]> wrote: >> > >> > I have another similar project that has around 300 services, and >> the >> > >> average >> > >> > AddComponent time there is 20ms, so that would make sense. I'll >> try to >> > >> get >> > >> > profile results today (have to buy dotTrace first). >> > >> > >> > From: [email protected] >> > >> > [mailto:[email protected]] On Behalf Of Ayende >> > >> Rahien >> > >> > Sent: Wednesday, September 16, 2009 3:00 AM >> > >> > To: [email protected] >> > >> > Subject: Re: long startup time >> > >> > >> > IIRC, >> > >> > >> > We saw something like that previously, I think that there is an >> O(N) >> > >> > operation in Windsor somewhere. >> > >> > >> > On Wed, Sep 16, 2009 at 7:19 AM, Tyler Burd <[email protected]> >> wrote: >> > >> > >> > Hi all, >> > >> > >> > I've got a large application that takes about 1 minute to start up. >> I >> > >> > investigated today what could be the cause of this very long delay, >> and >> > >> > narrowed it down to the WindsorContainer.AddComponent method. I >> have >> > >> about >> > >> > 1000 service classes, each with an interface (the service type). >> The >> > >> > average time to call WindsorContainer.AddComponent is 52ms on my >> system. >> > >> > 52ms * 1000 is 52 seconds, which is the vast majority of the app's >> > >> startup >> > >> > time. >> > >> > >> > My system is a Quad Core, 2.66GHz Core2 running Windows XP. The >> same >> > >> > approximate startup time can be verified on multiple machines, >> servers, >> > >> and >> > >> > OS's. >> > >> > >> > Is this normal? Do I have to just bite the bullet on a long >> startup >> > >> time, >> > >> > or is there something I can do to help this? >> > >> > >> > Here is the block of code in a small executable I used to calculate >> the >> > >> > times. I can provide a profile report if necessary. I normally >> use >> > >> > AllTypes along with the fluent registration, but I wanted to get as >> > >> > low-level as possible. This code outputs: >> > >> > >> "Called AddComponent 957 times. Average AddComponent time: >> 52.0267175572519ms" >> > >> > >> > var container = new WindsorContainer(); >> > >> > >> > //calculates the time for each AddComponent call >> > >> > >> > var watch = new Stopwatch(); >> > >> > >> > var totalAddComponentCalls = 0; >> > >> > >> > //keeps track of the average ms to call AddComponent >> > >> > >> > var allAddComponentTimes = new List<long>(1000); >> > >> > >> > foreach (var classType in >> > >> > >> typeof(TheBigApplicationThingyWithAllTheServices).Assembly.GetTypes()) >> > >> > >> > { >> > >> > >> > if (classType.IsInterface) >> > >> > >> > continue; >> > >> > >> > if (classType.Namespace == null) >> > >> > >> > continue; >> > >> > >> > if (!classType.Namespace.Contains("Services")) >> > >> > >> > continue; >> > >> > >> > var interfaces = classType.GetInterfaces(); >> > >> > >> > if (interfaces.Length == 0) >> > >> > >> > continue; >> > >> > >> > var firstInterface = interfaces[0]; >> > >> > >> > var serviceName = >> totalAddComponentCalls.ToString(); >> > >> > //simple way to get unique name >> > >> > >> > watch.Start(); >> > >> > >> > container.AddComponent(serviceName, firstInterface, >> > >> > classType); >> > >> > >> > watch.Stop(); >> > >> > >> > >> allAddComponentTimes.Add(watch.ElapsedMilliseconds); >> > >> > >> > watch.Reset(); >> > >> > >> > ++totalAddComponentCalls; >> > >> > >> > } >> > >> > >> > var avgAddCompTime = (from ms in allAddComponentTimes select >> > >> ms).Average(); >> > >> > >> > Console.Out.WriteLine(string.Format("Called AddComponent {0} times. >> > >> Average >> > >> > AddComponent time: {1}ms", totalAddComponentCalls, >> avgAddCompTime)); >> > >> > >> -- >> > >> Truth, >> > >> James >> >> >> >> > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Castle Project Users" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/castle-project-users?hl=en -~----------~----~----~----~------~----~------~--~---
