Skip to content

Commit ee33d52

Browse files
author
Andrew Or
committed
Separate HTML generating code from listener
1 parent f9830a2 commit ee33d52

File tree

5 files changed

+48
-36
lines changed

5 files changed

+48
-36
lines changed

core/src/main/resources/org/apache/spark/ui/static/spark-dag-viz.js

+3
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ function toggleDagViz(forJob) {
105105
* div#dag-viz-graph >
106106
* svg >
107107
* g#cluster_stage_[stageId]
108+
*
109+
* Note that the input metadata is populated by o.a.s.ui.UIUtils.showDagViz.
110+
* Any changes in the input format here must be reflected there.
108111
*/
109112
function renderDagViz(forJob) {
110113

core/src/main/scala/org/apache/spark/ui/UIUtils.scala

+39
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import java.util.{Locale, Date}
2323
import scala.xml.{Node, Text}
2424

2525
import org.apache.spark.Logging
26+
import org.apache.spark.ui.viz.VizGraph
2627

2728
/** Utility functions for generating XML pages with spark content. */
2829
private[spark] object UIUtils extends Logging {
@@ -329,4 +330,42 @@ private[spark] object UIUtils extends Logging {
329330
<div class="bar bar-running" style={startWidth}></div>
330331
</div>
331332
}
333+
334+
/** Return a "DAG visualization" DOM element that expands into a visualization for a stage. */
335+
def showDagVizForStage(stageId: Int, graph: Option[VizGraph]): Seq[Node] = {
336+
showDagViz(graph.toSeq, forJob = false)
337+
}
338+
339+
/** Return a "DAG visualization" DOM element that expands into a visualization for a job. */
340+
def showDagVizForJob(jobId: Int, graphs: Seq[VizGraph]): Seq[Node] = {
341+
showDagViz(graphs, forJob = true)
342+
}
343+
344+
/**
345+
* Return a "DAG visualization" DOM element that expands into a visualization on the UI.
346+
*
347+
* This populates metadata necessary for generating the visualization on the front-end in
348+
* a format that is expected by spark-dag-viz.js. Any changes in the format here must be
349+
* reflected there.
350+
*/
351+
private def showDagViz(graphs: Seq[VizGraph], forJob: Boolean): Seq[Node] = {
352+
<div>
353+
<span class="expand-dag-viz" onclick={s"toggleDagViz($forJob);"}>
354+
<span class="expand-dag-viz-arrow arrow-closed"></span>
355+
<strong>DAG visualization</strong>
356+
</span>
357+
<div id="dag-viz-graph"></div>
358+
<div id="dag-viz-metadata">
359+
{
360+
graphs.map { g =>
361+
<div class="stage-metadata" stageId={g.rootScope.id} style="display:none">
362+
<div class="dot-file">{VizGraph.makeDotFile(g, forJob)}</div>
363+
{ g.incomingEdges.map { e => <div class="incoming-edge">{e.fromId},{e.toId}</div> } }
364+
{ g.outgoingEdges.map { e => <div class="outgoing-edge">{e.fromId},{e.toId}</div> } }
365+
</div>
366+
}
367+
}
368+
</div>
369+
</div>
370+
}
332371
}

core/src/main/scala/org/apache/spark/ui/jobs/JobPage.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ private[ui] class JobPage(parent: JobsTab) extends WebUIPage("job") {
309309
content ++= makeTimeline(activeStages ++ completedStages ++ failedStages,
310310
executorListener.executorIdToData, appStartTime)
311311

312-
content ++= vizListener.showVizElementForJob(jobId)
312+
content ++= UIUtils.showDagVizForJob(jobId, vizListener.getVizGraphsForJob(jobId))
313313

314314
if (shouldShowActiveStages) {
315315
content ++= <h4 id="active">Active Stages ({activeStages.size})</h4> ++

core/src/main/scala/org/apache/spark/ui/jobs/StagePage.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ private[ui] class StagePage(parent: StagesTab) extends WebUIPage("stage") {
171171
</div>
172172
</div>
173173

174+
val dagViz = UIUtils.showDagVizForStage(stageId, vizListener.getVizGraphForStage(stageId))
175+
174176
val accumulableHeaders: Seq[String] = Seq("Accumulable", "Value")
175177
def accumulableRow(acc: AccumulableInfo): Elem =
176178
<tr><td>{acc.name}</td><td>{acc.value}</td></tr>
@@ -436,7 +438,7 @@ private[ui] class StagePage(parent: StagesTab) extends WebUIPage("stage") {
436438
val content =
437439
summary ++
438440
showAdditionalMetrics ++
439-
vizListener.showVizElementForStage(stageId) ++
441+
dagViz ++
440442
<h4>Summary Metrics for {numCompleted} Completed Tasks</h4> ++
441443
<div>{summaryTable.getOrElse("No tasks have reported metrics yet.")}</div> ++
442444
<h4>Aggregated Metrics by Executor</h4> ++ executorTable.toNodeSeq ++

core/src/main/scala/org/apache/spark/ui/viz/VisualizationListener.scala

+2-34
Original file line numberDiff line numberDiff line change
@@ -36,47 +36,15 @@ private[ui] class VisualizationListener(conf: SparkConf) extends SparkListener {
3636
private val retainedStages =
3737
conf.getInt("spark.ui.retainedStages", SparkUI.DEFAULT_RETAINED_STAGES)
3838

39-
/** Construct a "DAG visualization" DOM element that expands into a visualization for a stage. */
40-
def showVizElementForStage(stageId: Int): Seq[Node] = {
41-
showVizElement(getVizGraphForStage(stageId).toSeq, forJob = false)
42-
}
43-
44-
/** Construct a "DAG visualization" DOM element that expands into a visualization for a job. */
45-
def showVizElementForJob(jobId: Int): Seq[Node] = {
46-
showVizElement(getVizGraphsForJob(jobId), forJob = true)
47-
}
48-
49-
/** Construct a "DAG visualization" DOM element that expands into a visualization on the UI. */
50-
private def showVizElement(graphs: Seq[VizGraph], forJob: Boolean): Seq[Node] = {
51-
<div>
52-
<span class="expand-dag-viz" onclick={s"toggleDagViz($forJob);"}>
53-
<span class="expand-dag-viz-arrow arrow-closed"></span>
54-
<strong>DAG visualization</strong>
55-
</span>
56-
<div id="dag-viz-graph"></div>
57-
<div id="dag-viz-metadata">
58-
{
59-
graphs.map { g =>
60-
<div class="stage-metadata" stageId={g.rootScope.id} style="display:none">
61-
<div class="dot-file">{VizGraph.makeDotFile(g, forJob)}</div>
62-
{ g.incomingEdges.map { e => <div class="incoming-edge">{e.fromId},{e.toId}</div> } }
63-
{ g.outgoingEdges.map { e => <div class="outgoing-edge">{e.fromId},{e.toId}</div> } }
64-
</div>
65-
}
66-
}
67-
</div>
68-
</div>
69-
}
70-
7139
/** Return the graph metadata for the given stage, or None if no such information exists. */
72-
private def getVizGraphsForJob(jobId: Int): Seq[VizGraph] = {
40+
def getVizGraphsForJob(jobId: Int): Seq[VizGraph] = {
7341
jobIdToStageIds.get(jobId)
7442
.map { sids => sids.flatMap { sid => stageIdToGraph.get(sid) } }
7543
.getOrElse { Seq.empty }
7644
}
7745

7846
/** Return the graph metadata for the given stage, or None if no such information exists. */
79-
private def getVizGraphForStage(stageId: Int): Option[VizGraph] = {
47+
def getVizGraphForStage(stageId: Int): Option[VizGraph] = {
8048
stageIdToGraph.get(stageId)
8149
}
8250

0 commit comments

Comments
 (0)