How long does it takes now? On Fri, Sep 18, 2009 at 2:56 AM, Tyler Burd <[email protected]> wrote:
> Indeed it is! Thank you very much, Ayende. This is a HUGE improvement! > Waiting 1+ minutes to see the result of a controller change was an enormous > drag on productivity. > > > > Again, thank you, and I am very impressed with the solution. > > > > *From:* [email protected] [mailto: > [email protected]] *On Behalf Of *Ayende Rahien > *Sent:* Thursday, September 17, 2009 5:44 PM > > *To:* [email protected] > *Subject:* Re: long startup time > > > > No, it doesn't. > It is easier with code. > Test code is interesting, it shows a pathological case of adding only > invalid components. > And the problem only show up when we have a large number of invalid > components. > > var kernel = new DefaultKernel(); > for (int i = 0; i < 500; i++) > { > kernel.AddComponent("key" + i, typeof(string), typeof(string)); > } > > Before optimization, this runs in 9.2 seconds > > After optimization, this runs in 0.5 seconds. > > Raising the number of components to 5,000 leads to about: 44.5 seconds (no > idea how much before optimization, don't have the patience. > > Using this approach, however: > > var kernel = new DefaultKernel(); > using(kernel.OptimizeDependencyResolution()) > { > for (int i = 0; i < 300; i++) > { > kernel.AddComponent("key" + i, typeof(string), typeof(string)); > } > } > > Resolve everything in 1.9 seconds. > The OptimizeDependencyResolution defer dependency resolution to the Dispose > part, and allow us to both gain significant optimization in registering > component while at the same time work nicely with all the usual tools and > facilities. > > I also optimized GetHandlers(Type) and GetAssignableHandlers(Type) > > I think that this is good enough for now :-) > > On Fri, Sep 18, 2009 at 1:44 AM, Tyler Burd <[email protected]> wrote: > > I fully accept that. Does this mean that the startable facility will not > be usable with this feature? > > > > *From:* [email protected] [mailto: > [email protected]] *On Behalf Of *Ayende Rahien > *Sent:* Thursday, September 17, 2009 3:53 PM > > > *To:* [email protected] > *Subject:* Re: long startup time > > > > Hm, that is a bit complex, though. > In particular, it effect the way the startable facility behaves. > I think that I will make this an opt in feature. > > On Thu, Sep 17, 2009 at 10:55 PM, Ayende Rahien <[email protected]> wrote: > > 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<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 -~----------~----~----~----~------~----~------~--~---
