You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by pw...@apache.org on 2015/05/01 10:37:47 UTC

[5/5] spark git commit: [SPARK-3468] [WEBUI] Timeline-View feature

[SPARK-3468] [WEBUI] Timeline-View feature

I sometimes trouble-shoot and analyse the cause of long time spending job.

At the time, I find the stages which spends long time or fails, then I find the tasks which spends long time or fails, next I analyse the proportion of each phase in a task.

Another case, I find executors which spends long time for running a task and analyse the details of a task.

In such situation, I think it's helpful to visualize timeline  for each application, job, task and the details of proportion of activity for each task.

I added 3 timeline features to existing Web UI.

[Application Timeline View]
This view shows following things.

* When each executor was added/removed and the reason why it's removed.
* When each job  was started/finished.
* Status of each job.

![screenshot from 2015-04-01 16 49 25](https://cloud.githubusercontent.com/assets/4736016/6936886/e35fd582-d891-11e4-980d-8de13f50e442.png)

[Stage Timeline View]
Similar to Application Timeline View, this view shows following things.

* When each executor was added/removed and the reason why it's removed.
* When each job was started/finished.
* Status of each stage.

![screenshot from 2015-04-01 16 50 59](https://cloud.githubusercontent.com/assets/4736016/6936900/0dca6526-d892-11e4-84a8-efd9037af444.png)

[Task Assignment Timeline View]
This view shows following things.

* When each task started/finished
* How long each task spent and the proportion.
* Status of each task.
* Where each task ran on.

![screenshot from 2015-04-01 16 51 54](https://cloud.githubusercontent.com/assets/4736016/6936910/20fd5acc-d892-11e4-9018-80e463881fc2.png)

All the view above is zoomable by mouse wheel action and scrollable by drag action.

Author: Kousuke Saruta <sa...@oss.nttdata.co.jp>

Closes #2342 from sarutak/timeline-viewer-feature and squashes the following commits:

11fe67d [Kousuke Saruta] Fixed conflict
79ac03d [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
a91abd3 [Kousuke Saruta] Merge branch 'master' of https://github.com/apache/spark into timeline-viewer-feature
ef34a5b [Kousuke Saruta] Implement tooltip using bootstrap
b09d0c5 [Kousuke Saruta] Move `stroke` and `fill` attribute of rect elements to css
d3c63c8 [Kousuke Saruta] Fixed a little bit bugs
a36291b [Kousuke Saruta] Merge branch 'master' of https://github.com/apache/spark into timeline-viewer-feature
28714b6 [Kousuke Saruta] Fixed highlight issue
0dc4278 [Kousuke Saruta] Addressed most of Patrics's feedbacks
8110acf [Kousuke Saruta] Added scroll limit to Job timeline
974a64a [Kousuke Saruta] Removed unused function
ee7a7f0 [Kousuke Saruta] Refactored
6a91872 [Kousuke Saruta] Temporary commit
6693f34 [Kousuke Saruta] Added link to job/stage box in the timeline in order to move to corresponding row when we click
8f88222 [Kousuke Saruta] Added job/stage description
aeed4b1 [Kousuke Saruta] Removed stage timeline
fc1696c [Kousuke Saruta] Merge branch 'timeline-viewer-feature' of github.com:sarutak/spark into timeline-viewer-feature
999ccd4 [Kousuke Saruta] Improved scalability
0fc6a31 [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
19815ae [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
68b7540 [Kousuke Saruta] Merge branch 'timeline-viewer-feature' of github.com:sarutak/spark into timeline-viewer-feature
52b5f0b [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
dec85db [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
fcdab7d [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
dab7cc1 [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
09cce97 [Kousuke Saruta] Cleanuped
16f82cf [Kousuke Saruta] Cleanuped
9fb522e [Kousuke Saruta] Cleanuped
d05f2c2 [Kousuke Saruta] Merge branch 'master' of git://git.apache.org/spark into timeline-viewer-feature
e85e9aa [Kousuke Saruta] Cleanup: Added TimelineViewUtils.scala
a76e569 [Kousuke Saruta] Removed unused setting in timeline-view.css
5ce1b21 [Kousuke Saruta] Added vis.min.js, vis.min.css and vis.map to .rat-exclude
082f709 [Kousuke Saruta] Added Timeline-View feature for Applications, Jobs and Stages


Project: http://git-wip-us.apache.org/repos/asf/spark/repo
Commit: http://git-wip-us.apache.org/repos/asf/spark/commit/7fe0f3f2
Tree: http://git-wip-us.apache.org/repos/asf/spark/tree/7fe0f3f2
Diff: http://git-wip-us.apache.org/repos/asf/spark/diff/7fe0f3f2

Branch: refs/heads/master
Commit: 7fe0f3f2b46c61a5cc4af9166781624409fda8a4
Parents: c24aeb6
Author: Kousuke Saruta <sa...@oss.nttdata.co.jp>
Authored: Fri May 1 01:39:56 2015 -0700
Committer: Patrick Wendell <pa...@databricks.com>
Committed: Fri May 1 01:39:56 2015 -0700

----------------------------------------------------------------------
 .rat-excludes                                   |   3 +
 .../apache/spark/ui/static/timeline-view.css    | 182 +++++++++++++++++
 .../org/apache/spark/ui/static/timeline-view.js | 168 ++++++++++++++++
 .../org/apache/spark/ui/static/vis.map          |   1 +
 .../org/apache/spark/ui/static/vis.min.css      |   1 +
 .../org/apache/spark/ui/static/vis.min.js       |  39 ++++
 .../org/apache/spark/scheduler/StageInfo.scala  |  12 ++
 .../scala/org/apache/spark/ui/UIUtils.scala     |   5 +
 .../org/apache/spark/ui/exec/ExecutorsTab.scala |  11 +
 .../org/apache/spark/ui/jobs/AllJobsPage.scala  | 200 +++++++++++++++++--
 .../org/apache/spark/ui/jobs/JobPage.scala      | 174 +++++++++++++++-
 .../spark/ui/jobs/JobProgressListener.scala     |   7 +
 .../org/apache/spark/ui/jobs/JobsTab.scala      |   6 +-
 .../org/apache/spark/ui/jobs/StageTable.scala   |   3 +-
 .../scala/org/apache/spark/ui/jobs/UIData.scala |   5 +
 15 files changed, 785 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/spark/blob/7fe0f3f2/.rat-excludes
----------------------------------------------------------------------
diff --git a/.rat-excludes b/.rat-excludes
index 8aca5a7..4468da1 100644
--- a/.rat-excludes
+++ b/.rat-excludes
@@ -30,6 +30,9 @@ log4j-defaults.properties
 bootstrap-tooltip.js
 jquery-1.11.1.min.js
 sorttable.js
+vis.min.js
+vis.min.css
+vis.map
 .*avsc
 .*txt
 .*json

http://git-wip-us.apache.org/repos/asf/spark/blob/7fe0f3f2/core/src/main/resources/org/apache/spark/ui/static/timeline-view.css
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/spark/ui/static/timeline-view.css b/core/src/main/resources/org/apache/spark/ui/static/timeline-view.css
new file mode 100644
index 0000000..35ef14e
--- /dev/null
+++ b/core/src/main/resources/org/apache/spark/ui/static/timeline-view.css
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+div#application-timeline, div#job-timeline {
+  margin-bottom: 30px;
+}
+
+#application-timeline div.legend-area {
+  margin-top: 5px;
+}
+
+.vis.timeline div.content {
+  width: 100%;
+}
+
+.vis.timeline .item.stage {
+  cursor: pointer;
+}
+
+.vis.timeline .item.stage.succeeded {
+  background-color: #D5DDF6;
+}
+
+.vis.timeline .item.stage.succeeded.selected {
+   background-color: #D5DDF6;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.completed-stage-legend {
+  fill: #D5DDF6;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.stage.failed {
+   background-color: #FF5475;
+}
+
+.vis.timeline .item.stage.failed.selected {
+   background-color: #FF5475;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.failed-stage-legend {
+  fill: #FF5475;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.stage.running {
+   background-color: #FDFFCA;
+}
+
+.vis.timeline .item.stage.running.selected {
+   background-color: #FDFFCA;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.active-stage-legend {
+  fill: #FDFFCA;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.job {
+  cursor: pointer;
+}
+
+.vis.timeline .item.job.succeeded {
+  background-color: #D5DDF6;
+}
+
+.vis.timeline .item.job.succeeded.selected {
+   background-color: #D5DDF6;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.succeeded-job-legend {
+  fill: #D5DDF6;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.job.failed {
+   background-color: #FF5475;
+}
+
+.vis.timeline .item.job.failed.selected {
+   background-color: #FF5475;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.failed-job-legend {
+  fill: #FF5475;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.job.running {
+   background-color: #FDFFCA;
+}
+
+.vis.timeline .item.job.running.selected {
+   background-color: #FDFFCA;
+   border-color: #97B0F8;
+   z-index: auto;
+}
+
+.legend-area rect.running-job-legend {
+  fill: #FDFFCA;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.executor.added {
+  background-color: #D5DDF6;
+}
+
+.legend-area rect.executor-added-legend {
+  fill: #D5DDF6;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.executor.removed {
+  background-color: #EBCA59;
+}
+
+.legend-area rect.executor-removed-legend {
+  fill: #EBCA59;
+  stroke: #97B0F8;
+}
+
+.vis.timeline .item.executor.selected {
+  border-color: #FFC200;
+  background-color: #FFF785;
+  z-index: 2;
+}
+
+tr.corresponding-item-hover>td, tr.corresponding-item-hover>th {
+  background-color: #FFE1FA !important;
+}
+
+#application-timeline.collapsed {
+  display: none;
+}
+
+#job-timeline.collapsed {
+  display: none;
+}
+
+.control-panel {
+  margin-bottom: 5px;
+}
+
+span.expand-application-timeline, span.expand-job-timeline {
+  cursor: pointer;
+}
+
+.control-panel input+span {
+  cursor: pointer;
+}
+
+.vis.timeline .item.range .content {
+  position: unset;
+}
+
+.vis.timeline .item .tooltip-inner {
+  max-width: unset !important;
+}

http://git-wip-us.apache.org/repos/asf/spark/blob/7fe0f3f2/core/src/main/resources/org/apache/spark/ui/static/timeline-view.js
----------------------------------------------------------------------
diff --git a/core/src/main/resources/org/apache/spark/ui/static/timeline-view.js b/core/src/main/resources/org/apache/spark/ui/static/timeline-view.js
new file mode 100644
index 0000000..e4a891d
--- /dev/null
+++ b/core/src/main/resources/org/apache/spark/ui/static/timeline-view.js
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function drawApplicationTimeline(groupArray, eventObjArray, startTime) {
+  var groups = new vis.DataSet(groupArray);
+  var items = new vis.DataSet(eventObjArray);
+  var container = $("#application-timeline")[0];
+  var options = {
+    groupOrder: function(a, b) {
+      return a.value - b.value
+    },
+    editable: false,
+    showCurrentTime: false,
+    min: startTime,
+    zoomable: false
+  };
+
+  var applicationTimeline = new vis.Timeline(container);
+  applicationTimeline.setOptions(options);
+  applicationTimeline.setGroups(groups);
+  applicationTimeline.setItems(items);
+
+  setupZoomable("#application-timeline-zoom-lock", applicationTimeline);
+  setupExecutorEventAction();
+
+  function setupJobEventAction() {
+    $(".item.range.job.application-timeline-object").each(function() {
+      var getJobId = function(baseElem) {
+        var jobIdText = $($(baseElem).find(".application-timeline-content")[0]).text();
+        var jobId = jobIdText.match("\\(Job (\\d+)\\)")[1];
+       return jobId;
+      };
+
+      $(this).click(function() {
+        window.location.href = "job/?id=" + getJobId(this);
+      });
+
+      $(this).hover(
+        function() {
+          $("#job-" + getJobId(this)).addClass("corresponding-item-hover");
+          $($(this).find("div.application-timeline-content")[0]).tooltip("show");
+        },
+        function() {
+          $("#job-" + getJobId(this)).removeClass("corresponding-item-hover");
+          $($(this).find("div.application-timeline-content")[0]).tooltip("hide");
+        }
+      );
+    });
+  }
+
+  setupJobEventAction();
+
+  $("span.expand-application-timeline").click(function() {
+    $("#application-timeline").toggleClass('collapsed');
+
+    // Switch the class of the arrow from open to closed.
+    $(this).find('.expand-application-timeline-arrow').toggleClass('arrow-open');
+    $(this).find('.expand-application-timeline-arrow').toggleClass('arrow-closed');
+  });
+}
+
+function drawJobTimeline(groupArray, eventObjArray, startTime) {
+  var groups = new vis.DataSet(groupArray);
+  var items = new vis.DataSet(eventObjArray);
+  var container = $('#job-timeline')[0];
+  var options = {
+    groupOrder: function(a, b) {
+      return a.value - b.value;
+    },
+    editable: false,
+    showCurrentTime: false,
+    min: startTime,
+    zoomable: false,
+  };
+
+  var jobTimeline = new vis.Timeline(container);
+  jobTimeline.setOptions(options);
+  jobTimeline.setGroups(groups);
+  jobTimeline.setItems(items);
+
+  setupZoomable("#job-timeline-zoom-lock", jobTimeline);
+  setupExecutorEventAction();
+
+  function setupStageEventAction() {
+    $(".item.range.stage.job-timeline-object").each(function() {
+      var getStageIdAndAttempt = function(baseElem) {
+        var stageIdText = $($(baseElem).find(".job-timeline-content")[0]).text();
+        var stageIdAndAttempt = stageIdText.match("\\(Stage (\\d+\\.\\d+)\\)")[1].split(".");
+        return stageIdAndAttempt;
+      };
+
+      $(this).click(function() {
+        var idAndAttempt = getStageIdAndAttempt(this);
+        var id = idAndAttempt[0];
+        var attempt = idAndAttempt[1];
+        window.location.href = "../../stages/stage/?id=" + id + "&attempt=" + attempt;
+      });
+
+      $(this).hover(
+        function() {
+          var idAndAttempt = getStageIdAndAttempt(this);
+          var id = idAndAttempt[0];
+          var attempt = idAndAttempt[1];
+          $("#stage-" + id + "-" + attempt).addClass("corresponding-item-hover");
+          $($(this).find("div.job-timeline-content")[0]).tooltip("show");
+        },
+        function() {
+          var idAndAttempt = getStageIdAndAttempt(this);
+          var id = idAndAttempt[0];
+          var attempt = idAndAttempt[1];
+          $("#stage-" + id + "-" + attempt).removeClass("corresponding-item-hover");
+          $($(this).find("div.job-timeline-content")[0]).tooltip("hide");
+        }
+      );
+    });
+  }
+
+  setupStageEventAction();
+
+  $("span.expand-job-timeline").click(function() {
+    $("#job-timeline").toggleClass('collapsed');
+
+    // Switch the class of the arrow from open to closed.
+    $(this).find('.expand-job-timeline-arrow').toggleClass('arrow-open');
+    $(this).find('.expand-job-timeline-arrow').toggleClass('arrow-closed');
+  });
+}
+
+function setupExecutorEventAction() {
+  $(".item.box.executor").each(function () {
+    $(this).hover(
+      function() {
+        $($(this).find(".executor-event-content")[0]).tooltip("show");
+      },
+      function() {
+        $($(this).find(".executor-event-content")[0]).tooltip("hide");
+      }
+    );
+  });
+}
+
+function setupZoomable(id, timeline) {
+  $(id + '>input[type="checkbox"]').click(function() {
+    if (this.checked) {
+      timeline.setOptions({zoomable: false});
+    } else {
+      timeline.setOptions({zoomable: true});
+    }
+  });
+
+  $(id + ">span").click(function() {
+    $(this).parent().find('input:checkbox').trigger('click');
+  });
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org