Version: 54.0.2801.0 (Developer Build)
On a signed out profile, MD History is considerably slower than non-MD history.
To test, I created a new profile, loaded 60 random Wikipedia pages, then tested page load time of both pages. Using devtools timeline, I measured the time of the first frame which has history items painted. These numbers are from a Z620, they increase by about 6x on a low-spec Chromebook.
Old history page: 325ms average
New history page: 900ms average
Relative difference: 2.75x
Note that on a signed-in profile, result loading in the old history page will block on a network request to history.google.com, which increases load time by at least 200ms on my Australian internet.
Here's a typical trace of the old history page: https://drive.google.com/file/d/0B_y5JvvhV806NHpJVXU4VTVnMUk/view?usp=sharing
It seems to roughly break down like this:
0-250ms: Loading resources
250-450ms: Parsing JS and initialising various things
450-650ms: Creating and attaching the <history-app> element and all its children
650-900ms: Stamping <history-item> elements into the <iron-list>
900ms: First meaningful paint
950-1300ms: Stamping more <history-item> elements offscreen.
esprehn, kschaaf, sorvell: Any help digging further into this would be appreciated. MD History is currently enabled by default on Chrome Canary.
Version: 54.0.2801.0 (Developer Build)
On a signed out profile, MD History is considerably slower than non-MD history.
To test, I created a new profile, loaded 60 random Wikipedia pages, then tested page load time of both pages. Using devtools timeline, I measured the time of the first frame which has history items painted. These numbers are from a Z620, they increase by about 6x on a low-spec Chromebook.
Old history page: 325ms average
New history page: 900ms average
Relative difference: 2.75x
Note that on a signed-in profile, result loading in the old history page will block on a network request to history.google.com, which increases load time by at least 200ms on my Australian internet.
Here's a typical trace of the MD history page: https://drive.google.com/file/d/0B_y5JvvhV806NHpJVXU4VTVnMUk/view?usp=sharing
It seems to roughly break down like this:
0-250ms: Loading resources
250-450ms: Parsing JS and initialising various things
450-650ms: Creating and attaching the <history-app> element and all its children
650-900ms: Stamping <history-item> elements into the <iron-list>
900ms: First meaningful paint
950-1300ms: Stamping more <history-item> elements offscreen.
esprehn, kschaaf, sorvell: Any help digging further into this would be appreciated. MD History is currently enabled by default on Chrome Canary.
Here are some suggestions.
Resource loading and registration time:
* vulcanize the resources
* use the polymer-css-build (https://github.com/PolymerLabs/polymer-css-build)
* upgrade to Polymer version 1.6. This version added support for native css custom properties.
Creation and runtime:
* create elements on demand when first needed. Here are some examples:
* history-app's #side-bar (history-side-bar)
* history-app's #dialog' (cr-dialog)
* history-list's #sharedMenu (cr-shared-menu)
* optimize history-item. Consider, for example:
* remove the #sizing-container and push this styling to the list container.
* avoid creating #date-accessed when it's not displayed
* use a higher performance version of paper-checkbox (contact @bicknellr)
* avoid use of history-searched-label and put its functionality into history-item
* avoid creating hidden #bookmark-star buttons
upgrading to 1.6.0 for the native CSS custom properties support is blocked on https://github.com/Polymer/polymer/issues/3802. Sounds like Polymer may have a fix for the release next week.
NOTE: no custom props were actually harnessed in this ^ roll :(
I had to disable them[1] because they were breaking a lot of our UIs.
Sorry for any confusion.
[1] https://codereview.chromium.org/2181073002/
I've now experimented with almost all of the suggestions in comment #3 (thanks!), and have a bunch of CLs in progress.
Here are the (very very approximate) load time improvements I expect to see from everything I've tried, based off 1000ms to load the page at master on my machine at the moment.
vulcanizing the page: 250ms
using native custom props: 50ms
lazily stamping menus, dialogs, etc: 80ms
paper-checkbox-light: 30ms
If all these work out as expected, that gets us a significant portion of the way towards where we need to be.
We're now targeting M55.
Since this bug was filed, we've made big strides. We're now down to ~2x, and we're tracking performance in the wild to make sure this is the case across all devices.
Upcoming improvements:
* polymer-css-build saves a few percent (https://codereview.chromium.org/2268863002/)
* paper-checkbox-light saves 1-2% (https://github.com/PolymerElements/paper-checkbox/pull/145)
* Shuffling around load order looks like it could improve first meaningful paint by 10-15% by preventing certain elements from loading until after paint.
* I've filed a feature request on iron-list to try and reduce jankiness immediately after first meaningful paint (https://github.com/PolymerElements/iron-list/issues/301)
On top of that:
* <cr-toolbar> is kinda expensive (removing it entirely saves ~7%), I'd like to try and reduce its impact
* There's probably more optimisations we can do within <history-list>/<history-item>, I'll spend some time tearing these apart to figure out where time is spent.
Some more ideas:
I talked briefly with Tim about lazily (or just not) loading code for synced tabs when loading the main list. What happened with that?
Are we loading grouped mode code in non-grouped mode?
Have we tried running Closure Compiler to eliminate dead code or do performance optimizations on the crisped JavaScript (without renaming)?
How much is saved if we make <history-item> into vanilla <div>s instead of using shadow DOM?
Can we move time gap separators to being created imperatively (i.e. createElement('div').className='time-gap') instead of just being hidden in the DOM?
Can we drop <paper-checkbox> (which is creating a whole bunch of labels but not actually filling the <content>)? I think just making an <iron-icon> with tabindex=0 and lazily creating a ripple and responding to up/down actions would probably give us gains.
Responding inline
> lazily loading code for synced tabs when loading the main list
It's basically implemented. There's just a couple of other things that I'm waiting to shake out before I send it to review. In particular:
- Lazy-loading invisible things has a pretty small perf impact since they're already lazy registered and rendered. The big win comes from lazy-loading checkboxes and buttons, but I'm waiting for paper-checkbox-light to see if that changes the situation.
- Lazy-loading all these things means they need to be loaded some time after first paint, and scheduling when that happens is kind of nasty. I'm waiting for iron-list stamping [1] to shake out before I try this.
> Are we loading grouped mode code in non-grouped mode?
See above.
> Have we tried running Closure Compiler to eliminate dead code
We've been talking to our friendly local devrel (notably, author of [2]) about this, but haven't actually tried anything yet
> How much is saved if we make <history-item> into vanilla <div>s instead of using shadow DOM?
Do you mean removing the <history-item> element and making that code a direct descendant of iron-list? We can't do that because of Grouped History, but it's still a worthwhile thing to try to see if it improves things. I'll look into it.
> Can we move time gap separators to being created imperatively
As discussed, this fits into the category of "changes which should improve things but are too small to measure"
> Can we drop <paper-checkbox>
paper-checkbox takes about 40% of the time to stamp a <history-item>. I think <paper-checkbox-light> will about halve that (I'm not really sure exactly).
The next step after that is probably to do some fancy styling with a native <input type="checkbox"> (similar to the Polymer Shop demo [3]), but at that point there's enough extra things to get right that we might not save much compared to <paper-checkbox-light>.
> also, can we dynamically create these <paper-ripple>s?
Yup, although this will be a very minor impact.
> also, why do we need <history-search-label>?
<history-searched-label> exists to share code between <history-list> and <synced-device-card>. We could probably implement it with a behavior instead, but we haven't ever been able to measure any significant performance impact from using it. I've also now removed the extra layer of shadow dom (#23) which has a minor saving and makes it look nicer in devtools.
[1] https://github.com/PolymerElements/iron-list/issues/301
[2] https://developers.googleblog.com/2016/08/closure-compiler-in-javascript.html
[3] https://github.com/Polymer/shop/blob/91d21477f030db1ce97981fcd7d503550d9730ba/src/shop-checkbox.html
esprehn@, tsergeant@, calamity@: ^ I think this helped a lot. can we check/quantify on Canary? I'm getting fairly similar numbers between old and new history UIs on my Mac Book Pro.
note: screen height matters a lot to these numbers in this brave new virtual list world.
Just wanted to point out that the title of this bug seems to be incorrect: page load performance is not 3x of the old history page (if it were, that would be a good thing). I assume it should instead read something like "page load time is 3x of the old history page". Maybe at this late date it doesn't make a difference, but it's not a helpful description to someone coming across this bug.
Summary: [MD History Page] takes 3x longer to load than old history page (signed out, local history) (was: [MD History] Signed out page load performance is 3x old history page)
As an update, we're now pretty close to load-time performance parity on machines with SSDs (1.2x or so).
We're seeing higher numbers (2x or so) on machines with spinning disks, presumably because we're loading significantly more resources off disk (although there might be other factors at play).
We'll work towards driving this difference down over the next week before branch point.
[Auto-generated comment by a script] We noticed that this issue is targeted for M-55; it appears the fix may have landed after branch point, meaning a merge might be required. Please confirm if a merge is required here - if so add Merge-Request-55 label, otherwise remove Merge-TBD label. Thanks.
Comment 1 by dbeam@chromium.org
, Jul 20 2016