Skip to content

Conversation

@2ooom
Copy link
Contributor

@2ooom 2ooom commented Aug 6, 2017

This is a backport of PR #18783 to the latest released branch 2.2.

What changes were proposed in this pull request?

As described in JIRA ticket, History page is taking ~1min to load for cases when amount of jobs is 10k+.
Most of the time is currently being spent on DOM manipulations and all additional costs implied by this (browser repaints and reflows).
PR's goal is not to change any behavior but to optimize time of History UI rendering:

  1. The most costly operation is setting innerHTML for duration column within a loop, which is extremely unperformant. Refactoring this helped to get page load time down to 10-15s

  2. Second big gain bringing page load time down to 4s was was achieved by detaching table's DOM before parsing it with DataTables jQuery plugin.

  3. Another chunk of improvements ([1]criteo-forks@aeeeeb5), 2, 3) was focused on removing unnecessary DOM manipulations that in total contributed ~250ms to page load time.

How was this patch tested?

Tested by existing Selenium tests in org.apache.spark.deploy.history.HistoryServerSuite.

Changes were also tested on Criteo's spark-2.1 fork with 20k+ number of rows in the table, reducing load time to 4s.

2ooom added 5 commits August 6, 2017 14:03
…table DOM before processing

Currently all the DOM manipulations are handled in a loop after Mustache
template is parsed. This causes severe performance issues especially within
loops iteration over thousands of (attempt/application) records and causing
all kinds of unnecessary browser work: reflow, repaint, etc.

This could be easily fixed by preparing a DOM node beforehand and doing all
manipulations within the loops on detached node, reattaching it to the document
only after the work is done.

The most costly operation in this case was setting innerHTML for `duration`
column within a loop, which is extremely unperformant:

https://jsperf.com/jquery-append-vs-html-list-performance/24

While duration parsing could be done before mustache-template processing without
any additional DOM alteratoins.
Check whether to display pagination or not on large data sets (10-20k rows)
was taking up to 50ms because it was iterating over all rows. This could be
easily done by testing length of array before passing it to mustache.
…OM processing

Logic related to `hasMultipleAttempts` flag:

 - Hiding attmptId column (if `hasMultipleAttempts = false`)
 - Seting white background color for first 2 columns (if `hasMultipleAttempts = true`)

was updating DOM after mustache template processing, which was causing 2 unnecessary
iterations over full data set (first through jquery selector, than through for-loop).

Refactoring it inside mustache template helps saving 80-90ms on large data sets (10k+ rows)
…anipulations

Refactoring incomplete requests filter behavior due to inefficency in DOM
manipulations. We were traversing DOM 2 more times just to hide columns
that we could have avoided rendering in mustache. Factoring this logic in
mustache template (`showCompletedColumn`) saves 70-80ms on 10k+ rows.
…DataTables plugin processing

Detaching history table wrapper from document before parsing it with DataTables plugin
and reattaching back right after plugin has processed nested DOM. This allows to avoid
huge amount of browser repaints and reflows, reducing initial page load time in Chrome
from 15s to 4s for 20k+ rows
@jiangxb1987
Copy link
Contributor

Do we really need to backport this? @srowen

@SparkQA
Copy link

SparkQA commented Aug 6, 2017

Test build #3880 has finished for PR 18860 at commit 3630ca2.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@srowen
Copy link
Member

srowen commented Aug 6, 2017

Yes, tough call on the back-port. I'd normally say we don't back-port optimizations to maintenance branches. If the optimization relieved a significant usability problem, you could consider it a bug fix. For this one I'm on the fence about it, and would prefer to hear someone else in support of it.

@ajbozarth
Copy link
Member

I like the idea of back porting this, but I agree with @srowen that this falls into a grey area between an improvement and a bug fix. If there's opposition to the back-port I won't argue, but I'm personally in favor.

@srowen
Copy link
Member

srowen commented Aug 28, 2017

@2ooom how useful would that be for y'all ?

@2ooom
Copy link
Contributor Author

2ooom commented Aug 29, 2017

@srowen At criteo the issue has grown critical about 3 month ago and at that point (we had 11k rows in history table at a time and) when history page was taking at least 1min to load. Now we're at 26k+ rows and we're increasing spark adoption.
So I would actually treat this PR as a bug fix and try to merge in all supported branches (2.2, 2.3, maybe even 2.1) to save frustration for other spark-users.

@SparkQA
Copy link

SparkQA commented Aug 30, 2017

Test build #3911 has finished for PR 18860 at commit 3630ca2.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

asfgit pushed a commit that referenced this pull request Aug 30, 2017
## This is a backport of PR #18783 to the latest released branch 2.2.

## What changes were proposed in this pull request?

As described in JIRA ticket, History page is taking ~1min to load for cases when amount of jobs is 10k+.
Most of the time is currently being spent on DOM manipulations and all additional costs implied by this (browser repaints and reflows).
PR's goal is not to change any behavior but to optimize time of History UI rendering:

1. The most costly operation is setting `innerHTML` for `duration` column within a loop, which is [extremely unperformant](https://jsperf.com/jquery-append-vs-html-list-performance/24). [Refactoring ](criteo-forks@b7e56ee) this helped to get page load time **down to 10-15s**

2. Second big gain bringing page load time **down to 4s** was [was achieved](criteo-forks@3630ca2) by detaching table's DOM before parsing it with DataTables jQuery plugin.

3. Another chunk of improvements ([1]criteo-forks@aeeeeb5), [2](criteo-forks@e25be9a), [3](criteo-forks@9169707)) was focused on removing unnecessary DOM manipulations that in total contributed ~250ms to page load time.

## How was this patch tested?

Tested by existing Selenium tests in `org.apache.spark.deploy.history.HistoryServerSuite`.

Changes were also tested on Criteo's spark-2.1 fork with 20k+ number of rows in the table, reducing load time to 4s.

Author: Dmitry Parfenchik <d.parfenchik@criteo.com>

Closes #18860 from 2ooom/history-ui-perf-fix-2.2.
@srowen
Copy link
Member

srowen commented Aug 30, 2017

@2ooom merged to 2.2. You can close this PR now; it won't auto-close.

@2ooom
Copy link
Contributor Author

2ooom commented Aug 30, 2017

Thank you @srowen

@2ooom 2ooom closed this Aug 30, 2017
MatthewRBruce pushed a commit to Shopify/spark that referenced this pull request Jul 31, 2018
## This is a backport of PR apache#18783 to the latest released branch 2.2.

## What changes were proposed in this pull request?

As described in JIRA ticket, History page is taking ~1min to load for cases when amount of jobs is 10k+.
Most of the time is currently being spent on DOM manipulations and all additional costs implied by this (browser repaints and reflows).
PR's goal is not to change any behavior but to optimize time of History UI rendering:

1. The most costly operation is setting `innerHTML` for `duration` column within a loop, which is [extremely unperformant](https://jsperf.com/jquery-append-vs-html-list-performance/24). [Refactoring ](criteo-forks@b7e56ee) this helped to get page load time **down to 10-15s**

2. Second big gain bringing page load time **down to 4s** was [was achieved](criteo-forks@3630ca2) by detaching table's DOM before parsing it with DataTables jQuery plugin.

3. Another chunk of improvements ([1]criteo-forks@aeeeeb5), [2](criteo-forks@e25be9a), [3](criteo-forks@9169707)) was focused on removing unnecessary DOM manipulations that in total contributed ~250ms to page load time.

## How was this patch tested?

Tested by existing Selenium tests in `org.apache.spark.deploy.history.HistoryServerSuite`.

Changes were also tested on Criteo's spark-2.1 fork with 20k+ number of rows in the table, reducing load time to 4s.

Author: Dmitry Parfenchik <d.parfenchik@criteo.com>

Closes apache#18860 from 2ooom/history-ui-perf-fix-2.2.
@Willymontaz Willymontaz deleted the history-ui-perf-fix-2.2 branch April 2, 2019 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants