deep appendChild is too slow! (Safari wins on all but one JavaScript microbenchmark) http://idanso.dyndns.org/maps/jsbench/ DOM Node.cloneNone and appendChild Tests speed of shallow Node.cloneNode and deep Node.appendChild 335ms All the other benchmarks we beat FireFox/MacIE/Opera on the same hardware. We need to fix this one remaining case.
According to Shark, appendChild is spending all it's time in RenderContainer::removeLeftoverAnonymousBoxes(). It's not necessarily due to a deep DOM tree, though. I was able to get numbers for this by appending a relatively small subtree a large number of times. My test setup uses the DOM API in Cocoa directly. It iteratively creates a small group of elements DIV( P(textNode) INPUT(textNode) ) and appends that to the BODY element in a loop. It then removes everything with [body removeChild:]. It's spending all of it's time in the removeLeftoverAnonymousBoxes() routine, recursively walking up the tree on every call - and it gets called again for each sibling in both directions as each element is added. My understanding of that routine is that it's coalescing any anonymous boxes from neighboring inline elements, as the spec dictates. It just seems to be going about it in a terribly inefficient manner - especially considering none of this ever actually gets rendered to the screen. I've varied the number of iterations from 100 to 500000 - and performance falls off dramatically as soon as you start getting VM faults. Not really surprising, really, but it effectively makes doing anything remotely complex in terms of DOM/AJAX/Web2.0/Whatever unworkable in Safari. To be fair, Firefox isn't exactly a Ferrari, but it's about an order of magnitude faster than Safari at this task. To be thorough, I duplicated this test in pure Javascript and executed it from my test application as well (using evaluateWebScript:) with roughly the same results. I expected this as both implementations end up calling into the same WebKit code, but I wanted to be thorough.
It's surprising that removeLeftoverAnonymousBoxes would be hit over and over again. It's only supposed to be hit when a block has to change from having inline children to having block children. That can only happen once for a block.
It's also not clear to me why removeLeftoverAnonymousBoxes recurs up to the parent. That is totally wrong unless the block that removeLeftoverAnonymousBoxes is invoked on is also anonymous.
Created attachment 8465 [details] Limit the recursion of removeLeftoverAnonymousBoxes to improve performance. This helps get us closer, but we still don't win. I think I may be able to totally rewrite this removal check to be much faster.
Actually I tried commenting out this method completely and it had no effect on the benchmark whatsoever, so while I appreciate the second comment, maybe you could file a separate bug with your test case. removeLeftoverAnonymousBoxes does not seem to be relevant to this particular micro-benchmark (but could be relevant to your new test case that you wrote).
Comment on attachment 8465 [details] Limit the recursion of removeLeftoverAnonymousBoxes to improve performance. This is a nice easy safe change, though, so going ahead and flagging for review.
Comment on attachment 8465 [details] Limit the recursion of removeLeftoverAnonymousBoxes to improve performance. Not relevant to the reported bug, so removing from here.
The link seems to be bad... Strange I even filed this bug. I have no recollection of what the original test suite was, so I think this should be closed.
Mass moving XML DOM bugs to the "DOM" Component.