1. #1
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default Initial rendering still slow compared to 2.3.0

    Initial rendering still slow compared to 2.3.0


    On a good note, the upcoming 3.1.1 release passes 2.3.0 for resizing:
    http://www.extjs.com/forum/showthrea...t=91302&page=2

    However, it's another story for "Initial Rendering" of components.

    Imagine a customer out there. The customer created the Layout Browser app under 2.3.0. The customer decides to upgrade to 3.1.1, but is not sure after seeing these results.

    The #inUse represents the number of DOM elements in use.
    What's causing the degraded performance?

    I have copied the layout-browser demo from 2.3.0 and ran that under 3.1.1. Then, I have commented out items and entered one item individually and timed that. At the end, I timed the actual demo.

    Basically, I'm simulating a customer making a decision to migrate from 2.3.0 to 3.1.1.

    Look at accordion, cardWizard, form and absoluteForm. Why does absoluteForm require 89 extra dom elements?

    The decision is still clear and that is to stay with 2.3.0. It's actually a difficult decision for many developers out there running with 2.3.0. Their app will take a hit for "Initial Rendering". Fortunately, 3.1.1's resizing is on par with 2.3.0 though.


    Code:
           Items        #inUse  Time
     
    2.3.0  empty          305   0.047
    3.1.1  empty          307   0.062
     
    2.3.0  start          310   0.062
    3.1.1  start          312   0.078
     
    2.3.0  accordion      344   0.078
    3.1.1  accordion      358   0.109
     
    2.3.0  anchor         329   0.078
    3.1.1  anchor         331   0.109
     
    2.3.0  border         335   0.078
    3.1.1  border         337   0.109
     
    2.3.0  cardTabs       335   0.062
    3.1.1  cardTabs       338   0.094
     
    2.3.0  cardWizard     356   0.078
    3.1.1  cardWizard     396   0.140
     
    2.3.0  column         334   0.062
    3.1.1  column         336   0.109
     
    2.3.0  fit            316   0.062
    3.1.1  fit            318   0.078
     
    2.3.0  form           360   0.078
    3.1.1  form           402   0.156
     
    2.3.0  table          376   0.078
    3.1.1  table          378   0.125
     
    2.3.0  rowLayout      326   0.062
    3.1.1  rowLayout      328   0.093
     
    2.3.0  centerLayout   327   0.062
    3.1.1  centerLayout   329   0.093
     
    2.3.0  absoluteForm   414   0.109
    3.1.1  absoluteForm   503   0.250
     
    2.3.0  nestedLayout   360   0.094
    3.1.1  nestedLayout   364   0.156
     
    2.3.0  demo           888   0.453
    3.1.1  demo          1069   0.718

  2. #2
    Sencha - Community Support Team mystix's Avatar
    Join Date
    Mar 2007
    Location
    Singapore
    Posts
    6,236
    Vote Rating
    5
    mystix will become famous soon enough

      0  

    Default


    just curious, but what exactly tools are you using to perform all these wicked profiling / DOM node usage tests?

  3. #3
    Ext JS Premium Member
    Join Date
    Apr 2008
    Posts
    352
    Vote Rating
    14
    rich02818 is on a distinguished road

      0  

    Default


    However, staying with 2.3.0 retains the problem of memory usage for a long-running single-page app, does it not? So, is this really an option for RIAs?

  4. #4
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default


    Quote Originally Posted by rich02818 View Post
    However, staying with 2.3.0 retains the problem of memory usage for a long-running single-page app, does it not? So, is this really an option for RIAs?
    In that case, I would go with 3.1.1 without a doubt as 3.1.0+ has addressed a lot of memory related issues.

    I'm just trying to understand why 2.3.0 renders so much faster for "Initial" rendering. I wanted to see where the bottleneck is with the layout-browser demo.

  5. #5
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default


    Quote Originally Posted by mystix View Post
    just curious, but what exactly tools are you using to perform all these wicked profiling / DOM node usage tests?
    For this one, I'm using sIEve 0.8 and testing with IE.

    I have included the StopWatch.js file in the html file.

    Code:
    //
    // http://www.codeproject.com/KB/script...Stopwatch.aspx
    //
    function StopWatch() {
        var startTime = null,
            stopTime = null,
            running = false;
        function getTime() {
            var day = new Date();
            return day.getTime();
        }
        this.start = function() {
            if (running == true) {
                return;
            } else if (startTime != null) {
                stopTime = null;
            }
            running = true;
            startTime = getTime();
        }
        this.stop = function() {
            if (running == false) {
                return;
            }
            stopTime = getTime();
            running = false;
        }
        this.duration = function() {
            if (startTime == null || stopTime == null) {
                return 'Undefined';
            } else {
                return (stopTime - startTime) / 1000;
            }
        }
    }
    At the top of Ext.onReady, I have the following:

    Code:
    var stopWatch = new StopWatch();
    stopWatch.start();
    At the end of Ext.onReady, I have:

    Code:
    stopWatch.stop();
    alert(stopWatch.duration() + ' seconds');
    For the individual times, I've made this change to layout-browser.js. BTW: I'm using the same layout-browser demo from 2.3.0 when testing under 3.1.1 (rev 5996).

    Code:
            var contentPanel = {
                    id: 'content-panel',
                    region: 'center', // this is what makes this panel into a region within the containing layout
                    layout: 'card',
                    margins: '2 5 5 0',
                    activeItem: 0,
                    border: false,
                    items: [
                            // from basic.js:
                            //start, absolute, accordion, anchor, border, cardTabs, cardWizard, column, fit, form, table,
                            // from custom.js:
                            //rowLayout, centerLayout,
                            // from combination.js:
                            //absoluteForm, tabsNestedLayouts
     
                            start   // I'm timing each one individually here
                    ]
            };

  6. #6
    Ext JS Premium Member stever's Avatar
    Join Date
    Mar 2007
    Posts
    1,406
    Vote Rating
    6
    stever will become famous soon enough stever will become famous soon enough

      0  

    Default


    Quote Originally Posted by meroy View Post
    However, it's another story for "Initial Rendering" of components.
    This seems to be the most important to me...

    Quote Originally Posted by meroy View Post
    The #inUse represents the number of DOM elements in use.
    What's causing the degraded performance?
    BTW: Anything that has a button in it will have more DOM elements since the structure of buttons changed. Note that you can make your own version of Button that is more optimized for very current css3 browsers (and defaulting to the normal ext3 version for all others). Actually, ExtJS should do this, and perhaps will in a future version. It is not too hard.

    As per our other discussion, I'm pushing for some changes in Mozilla that would help in Ext's rendering/layout process even if Ext doesn't fix some of their core issues. As it is involved in a revision of the DOM model standard, I've also contacted a rep at Opera, and will eventually contact WebKit (the person at Opera is in charge of clarifying some issues in the standard, so I'm waiting on that).

    Anyhow, keep up the good work testing and profiling the stock version of Ext. Everyone benefits, and thus I think everyone appreciates your efforts.

  7. #7
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default


    I'm testing with Firefox 3.6.0 on Leopard 10.5.8 and running on a 2.4 GHz MacBook Pro.

    Using the layout-browser 2.0 sample, I've gathered the following metrics. The time to render is what I'm interested in. The C4 build comes close to 2.3.0's rendering speed.

    Code:
    layout-browser-2:
    
      2.3.0    3.0.3    Ext JS
     ======   ======    ============================
      16192    43802    Initial Rendering # of calls
      0.346    0.561    Time to Render Initial App
      0.502    0.779    Time to Render Grid Tab
       3175    11077    Maximize/Restore Window Size
    The C4 build is nearly as fast as 2.3.0 for initial rendering.

    Code:
    layout-browser-2:
    
       (C4)     (C3)     3.1.1     3.1.0     R6073    Ext JS
     ======   ======    ======    ======    ======    ============================
      22880    21341     35663     22888     35829    Initial Rendering # of calls
      0.347    0.325     0.558     0.361     0.559    Time to Render Initial App
      0.531    0.774     0.776     0.797     0.773    Time to Render Grid Tab
       4460     4567      5530      7576      4802    Maximize/Restore Window Size
    
    
    test-form-a: http://www.extjs.com/forum/showthread.php?t=74092
    
       (C4)     (C3)     3.1.1     3.1.0     R6073    Ext JS
     ======   ======    ======    ======    ======    ============================
      22014    22913     23916     22307     23445    Initial Rendering # of calls
      0.422    0.462     0.505     0.463     0.470    Time to Render Form
    Regards,
    Mario

  8. #8
    Sencha User
    Join Date
    Jun 2009
    Posts
    750
    Vote Rating
    0
    meroy is on a distinguished road

      0  

    Default


    Here is my overhead-reducer-overrides.js:

    The first one (#1) helps cuts down the number of calls for the initial rendering of the layout browser app. The next two (#2) & (#3) helps reduce the overhead in Panel.js and affects everything which extends Ext.Panel to include Drag and Drop. This is what helps 3.1.x to reach 2.3.0 for rendering the Grid Tab in the the layout browser demo.

    The last one (#4) is only required if you're running with the 3.1.1 build, but not for 3.1.x or 3.2.x.

    I also attached as a zip file in the event copy/paste is failing for you.

    Enjoy,
    Mario

    Code:
    /*
     * #1:  Will reduce the overhead for initial rendering. Tested with 3.1.1+.
     *      It's a one line change to afterRender in Container.js
     *      From...: this.doLayout(false, true);
     *      To.....: this.doLayout(false, this.forceLayout);
     */
    
    Ext.override(Ext.Container, {
        afterRender: function(){
            // Render this Container, this should be done before setLayout is called which
            // will hook onResize
            Ext.Container.superclass.afterRender.call(this);
            if(!this.layout){
                this.layout = 'auto';
            }
            if(Ext.isObject(this.layout) && !this.layout.layout){
                this.layoutConfig = this.layout;
                this.layout = this.layoutConfig.type;
            }
            if(Ext.isString(this.layout)){
                this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
            }
            this.setLayout(this.layout);
    
            // If a CardLayout, the active item set
            if(this.activeItem !== undefined){
                var item = this.activeItem;
                delete this.activeItem;
                this.layout.setActiveItem(item);
            }
    
            // If we have no ownerCt, render and size all children
            if(!this.ownerCt){
                this.doLayout(false, this.forceLayout);
            }
    
            // This is a manually configured flag set by users in conjunction with renderTo.
            // Not to be confused with the flag by the same name used in Layouts.
            if(this.monitorResize === true){
                Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
            }
        }
    });
    
    /*
     * #2:  Helps reduce the overhead during initial rendering. Tested with 3.1.1+.
     *      It's 1 line for initComponent in Panel.js. Search for this.suspendInitialBodyResize.
     */
    
    Ext.override(Ext.Panel, {
        initComponent : function(){
            Ext.Panel.superclass.initComponent.call(this);
    
            this.addEvents(
                /**
                 * @event bodyresize
                 * Fires after the Panel has been resized.
                 * @param {Ext.Panel} p the Panel which has been resized.
                 * @param {Number} width The Panel body's new width.
                 * @param {Number} height The Panel body's new height.
                 */
                'bodyresize',
                /**
                 * @event titlechange
                 * Fires after the Panel title has been {@link #title set} or {@link #setTitle changed}.
                 * @param {Ext.Panel} p the Panel which has had its title changed.
                 * @param {String} The new title.
                 */
                'titlechange',
                /**
                 * @event iconchange
                 * Fires after the Panel icon class has been {@link #iconCls set} or {@link #setIconClass changed}.
                 * @param {Ext.Panel} p the Panel which has had its {@link #iconCls icon class} changed.
                 * @param {String} The new icon class.
                 * @param {String} The old icon class.
                 */
                'iconchange',
                /**
                 * @event collapse
                 * Fires after the Panel has been collapsed.
                 * @param {Ext.Panel} p the Panel that has been collapsed.
                 */
                'collapse',
                /**
                 * @event expand
                 * Fires after the Panel has been expanded.
                 * @param {Ext.Panel} p The Panel that has been expanded.
                 */
                'expand',
                /**
                 * @event beforecollapse
                 * Fires before the Panel is collapsed.  A handler can return false to cancel the collapse.
                 * @param {Ext.Panel} p the Panel being collapsed.
                 * @param {Boolean} animate True if the collapse is animated, else false.
                 */
                'beforecollapse',
                /**
                 * @event beforeexpand
                 * Fires before the Panel is expanded.  A handler can return false to cancel the expand.
                 * @param {Ext.Panel} p The Panel being expanded.
                 * @param {Boolean} animate True if the expand is animated, else false.
                 */
                'beforeexpand',
                /**
                 * @event beforeclose
                 * Fires before the Panel is closed.  Note that Panels do not directly support being closed, but some
                 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.  This event only
                 * applies to such subclasses.
                 * A handler can return false to cancel the close.
                 * @param {Ext.Panel} p The Panel being closed.
                 */
                'beforeclose',
                /**
                 * @event close
                 * Fires after the Panel is closed.  Note that Panels do not directly support being closed, but some
                 * Panel subclasses do (like {@link Ext.Window}) or a Panel within a Ext.TabPanel.
                 * @param {Ext.Panel} p The Panel that has been closed.
                 */
                'close',
                /**
                 * @event activate
                 * Fires after the Panel has been visually activated.
                 * Note that Panels do not directly support being activated, but some Panel subclasses
                 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
                 * activate and deactivate events under the control of the TabPanel.
                 * @param {Ext.Panel} p The Panel that has been activated.
                 */
                'activate',
                /**
                 * @event deactivate
                 * Fires after the Panel has been visually deactivated.
                 * Note that Panels do not directly support being deactivated, but some Panel subclasses
                 * do (like {@link Ext.Window}). Panels which are child Components of a TabPanel fire the
                 * activate and deactivate events under the control of the TabPanel.
                 * @param {Ext.Panel} p The Panel that has been deactivated.
                 */
                'deactivate'
            );
    
            if(this.unstyled){
                this.baseCls = 'x-plain';
            }
    
            this.suspendInitialBodyResize = true;
    
            this.toolbars = [];
            // shortcuts
            if(this.tbar){
                this.elements += ',tbar';
                this.topToolbar = this.createToolbar(this.tbar);
                delete this.tbar;
    
            }
            if(this.bbar){
                this.elements += ',bbar';
                this.bottomToolbar = this.createToolbar(this.bbar);
                delete this.bbar;
            }
    
            if(this.header === true){
                this.elements += ',header';
                delete this.header;
            }else if(this.headerCfg || (this.title && this.header !== false)){
                this.elements += ',header';
            }
    
            if(this.footerCfg || this.footer === true){
                this.elements += ',footer';
                delete this.footer;
            }
    
            if(this.buttons){
                this.fbar = this.buttons;
                delete this.buttons;
            }
            if(this.fbar){
                this.createFbar(this.fbar);
            }
            if(this.autoLoad){
                this.on('render', this.doAutoLoad, this, {delay:10});
            }
        }
    });
    
    /*
     * #3:  Helps reduce the overhead during initial rendering. Tested with 3.1.1+.
     *      It's 5 lines total added towards the end of onResize in Panel.js.
     *      Two if statements and a delete line.  Search for suspendInitialBodyResize.
     */
    
    Ext.override(Ext.Panel, {
        onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
            var w = adjWidth,
                h = adjHeight;
    
            if(Ext.isDefined(w) || Ext.isDefined(h)){
                if(!this.collapsed){
                    // First, set the the Panel's body width.
                    // If we have auto-widthed it, get the resulting full offset width so we can size the Toolbars to match
                    // The Toolbars must not buffer this resize operation because we need to know their heights.
    
                    if(Ext.isNumber(w)){
                        this.body.setWidth(w = this.adjustBodyWidth(w - this.getFrameWidth()));
                    } else if (w == 'auto') {
                        w = this.body.setWidth('auto').dom.offsetWidth;
                    } else {
                        w = this.body.dom.offsetWidth;
                    }
    
                    if(this.tbar){
                        this.tbar.setWidth(w);
                        if(this.topToolbar){
                            this.topToolbar.setSize(w);
                        }
                    }
                    if(this.bbar){
                        this.bbar.setWidth(w);
                        if(this.bottomToolbar){
                            this.bottomToolbar.setSize(w);
                            // The bbar does not move on resize without this.
                            if (Ext.isIE) {
                                this.bbar.setStyle('position', 'static');
                                this.bbar.setStyle('position', '');
                            }
                        }
                    }
                    if(this.footer){
                        this.footer.setWidth(w);
                        if(this.fbar){
                            this.fbar.setSize(Ext.isIE ? (w - this.footer.getFrameWidth('lr')) : 'auto');
                        }
                    }
    
                    // At this point, the Toolbars must be layed out for getFrameHeight to find a result.
                    if(Ext.isNumber(h)){
                        h = Math.max(0, this.adjustBodyHeight(h - this.getFrameHeight()));
                        this.body.setHeight(h);
                    }else if(h == 'auto'){
                        this.body.setHeight(h);
                    }
    
                    if(this.disabled && this.el._mask){
                        this.el._mask.setSize(this.el.dom.clientWidth, this.el.getHeight());
                    }
                }else{
                    // Adds an event to set the correct height afterExpand.  This accounts for the deferHeight flag in panel
                    this.queuedBodySize = {width: w, height: h};
                    if(!this.queuedExpand && this.allowQueuedExpand !== false){
                        this.queuedExpand = true;
                        this.on('expand', function(){
                            delete this.queuedExpand;
                            this.onResize(this.queuedBodySize.width, this.queuedBodySize.height);
                        }, this, {single:true});
                    }
                }
                if(!this.suspendInitialBodyResize){
                    this.onBodyResize(w, h);
                }
            }
            this.syncShadow();
            if(!this.suspendInitialBodyResize){
                Ext.Panel.superclass.onResize.call(this, adjWidth, adjHeight, rawWidth, rawHeight);
            }
            delete this.suspendInitialBodyResize;
        }
    });
    
    /*
     * #4:  Only required for 3.1.1.  Otherwise, not necessary for 3.1.x.
     */
    
    Ext.override(Ext.grid.GridPanel, {
        onResize : function(){
            Ext.grid.GridPanel.superclass.onResize.apply(this, arguments);
        //  if(this.viewReady){
        //      this.view.layout();
        //  }
        }
    });
    Attached Files

Thread Participants: 3