PDA

View Full Version : Why is adding Sprites 1 at a time faster than adding all to items[] during init?!?!



stahlman
3 Oct 2011, 9:55 AM
This really took me by surprise, especially as I had gone out of my way to ensure that all Sprites were present in this.items[] prior to calling parent's initComponent. Since Sprite creation seemed to be a bottleneck, I was hoping to amortize some of the creation work by letting Ext have all the Sprite definitions up front, rather than hitting it with several dozen separate calls to surface.add(). I ran 2 test cases (shown below) in Firefox: case #1 adds each Sprite with a separate surface.add(), while case #2 puts all the Sprites into this.items[] before invoking parent initComponent. The results were quite surprising to me: in particular, case #1 usually took around 1.3s to load, whereas case #2 (which I expected to be faster) took an average of nearly 2.1s to load! I used Firefox 6.0.1 for the tests, using Firebug to profile. Can anyone explain these counter-intuitive results? Here are the 2 test cases:

Case #1 (Separate calls to add for each Sprite)
Ext.define('DM.view.DbgAdd', {
extend: 'Ext.panel.Panel',
layout: 'fit',
alias: 'widget.draw-add',
config: {
numSprites: 50
},
items: [{
xtype: 'draw',
viewBox: false,
itemId: 'draw'
}],
initComponent: function() {
this.addListener('resize', this.resizeHandler, this);
this.callParent(arguments);
},
resizeHandler: function() {
if (!this.initComplete) {
this.initComplete = true;
var surface = this.getComponent('draw').surface;
for (var i = 0; i < this.config.numSprites; i++) {
surface.add({
type: 'rect',
fill: '#ff00ff',
x: i, y: i,
width: 10, height: 20,
opacity: 1.0
}).show(true);
surface.add({
type: 'text',
x: i, y: i,
text: 'Text sample #' + i
}).show(true);
}

}
}

});

Case #2 (All Sprite definitions in this.items[])
Ext.define('DM.view.DbgItems', {
extend: 'Ext.panel.Panel',
layout: 'fit',
alias: 'widget.draw-items',
config: {
numSprites: 50
},
items: [{
xtype: 'draw',
viewBox: false,
itemId: 'draw',
items: drawItems = [],
}],
initComponent: function() {
for (var i = 0; i < this.config.numSprites; i++) {
drawItems.push({
type: 'rect',
fill: '#ff00ff',
x: i, y: i,
width: 10, height: 20,
opacity: 1.0
}, {
type: 'text',
x: i, y: i,
text: 'Text sample #' + i
});
}
this.callParent(arguments);
}

});

LesJ
3 Oct 2011, 10:32 AM
Looks like a bug to me.:-?

I think the Ext.draw.Surface.add() method should be refactored to make it more efficient.

I'd create a ticket using the official ticket form.

LesJ
3 Oct 2011, 11:07 AM
I tried the Ext Tiger example.

http://docs.sencha.com/ext-js/4-0/#!/example/draw/Tiger.html

On my test machine (Win FF7) it took 519ms to draw the Tiger.

However, if I added the sprites one by one, it took only 452ms to draw the Tiger.

I can conclude same as you that adding sprites one by one is faster.

stahlman
3 Oct 2011, 11:19 AM
I appreciate your trying the example. These results seem very odd to me. Clearly, there's something wrong with the implementation if providing more information up front causes layout to take longer! Incidentally, layout performance in 4.0 has been killing us. I've spent countless hours trying to optimize my views after discovering that the flashy application we've developed is so slow as to be painful to use in any browser but Chrome. I believe the Ext JS layout engine was effectively optimized for Chrome, given the designers' reliance upon Chrome Speed Tracer during design... Not surprisingly, the component I'm attempting to optimize loads quite quickly in Chrome, regardless of how the sprites are added. It's only Firefox and IE where I notice the significant disparity. Alas, if only we could convince our customer to use Chrome...

LesJ
5 Oct 2011, 5:24 AM
stahlman, hi!

I'd recommend reporting a bug instead of posting in the Q&A area.

http://www.sencha.com/forum/showthread.php?138165-How-to-report-a-bug

Some of your posts fall into the "performance" bug category.

For instance, the Ext.draw.Surface.add() method is slow when using array params. This is because Sencha reused the Ext.container.AbstractContainer.add() method. While the add() method is very versatile as far as the possible inputs and its performance is acceptable for small arrays, it's also not efficient for large arrays.

stahlman
5 Oct 2011, 5:33 AM
LesJ,
Thanks. I'll probably move it there. If there's a "performance bug" category, that's probably where my other recent SVG post belongs as well...

LesJ
19 Oct 2011, 5:31 AM
This is single line of code in Ext.draw.Surface.add() is inefficient, and it is called recursively.

var args = Array.prototype.slice.call(arguments),

http://bonsaiden.github.com/JavaScript-Garden/#function.arguments
http://stackoverflow.com/questions/5325554/javascript-functions-and-arguments-object-is-there-a-cost-involved
http://www.jspatterns.com/arguments-considered-harmful/

stahlman
19 Oct 2011, 6:10 AM
Les,
While I agree that use of arguments is more expensive than explicit parameters (and that use of slice to copy the arguments array is more expensive still), I don't believe the performance penalty incurred is of a magnitude sufficient to explain the time discrepancies I was seeing (1.3 seconds vs 2.1 seconds total load time in Firefox). Keep in mind that even a 100% penalty for use of arguments would not translate into anywhere near 100% penalty for total creation time, given that the line of code you mentioned represents a very small fraction of the total work required to create and render all the sprites.

Incidentally, if the Ext designers are concerned about the performance of sprite creation, they have much bigger fish to fry than the use of the arguments array: e.g., the extensive RegExp and String manipulations used in converting VML path strings to SVG ones (my suggestion would be to force user to specify the path definitions as Arrays rather than Strings); the needless but expensive calls to tuneText for every invocation of setAttributes on a text sprite (regardless of whether the attributes being set can impact text wrapping/alignment), etc...

Thanks,
Brett S.

LesJ
26 Nov 2011, 5:59 AM
How do you show the sprites?

Adding the sprites one by one is faster, but showing them individually is slower than showing the added group.

In my test case I see a difference in FF 725ms vs 600ms.