1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 
19 package org.apache.hadoop.mapreduce.v2.hs.webapp;
20 
21 import static org.apache.hadoop.mapreduce.v2.app.webapp.AMParams.TASK_TYPE;
22 
23 import org.apache.hadoop.mapreduce.v2.api.records.TaskType;
24 import org.apache.hadoop.mapreduce.v2.app.job.Task;
25 import org.apache.hadoop.mapreduce.v2.app.job.TaskAttempt;
26 import org.apache.hadoop.mapreduce.v2.app.webapp.App;
27 import org.apache.hadoop.mapreduce.v2.app.webapp.dao.ReduceTaskAttemptInfo;
28 import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskAttemptInfo;
29 import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskInfo;
30 import org.apache.hadoop.mapreduce.v2.util.MRApps;
31 import org.apache.hadoop.util.StringUtils;
32 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet;
33 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TABLE;
34 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TBODY;
35 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TFOOT;
36 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.THEAD;
37 import org.apache.hadoop.yarn.webapp.hamlet.Hamlet.TR;
38 import org.apache.hadoop.yarn.webapp.hamlet.HamletSpec.InputType;
39 import org.apache.hadoop.yarn.webapp.view.HtmlBlock;
40 
41 import com.google.inject.Inject;
42 
43 /**
44  * Render the a table of tasks for a given type.
45  */
46 public class HsTasksBlock extends HtmlBlock {
47   final App app;
48 
HsTasksBlock(App app)49   @Inject HsTasksBlock(App app) {
50     this.app = app;
51   }
52 
53   /*
54    * (non-Javadoc)
55    * @see org.apache.hadoop.yarn.webapp.view.HtmlBlock#render(org.apache.hadoop.yarn.webapp.view.HtmlBlock.Block)
56    */
render(Block html)57   @Override protected void render(Block html) {
58     if (app.getJob() == null) {
59       html.
60         h2($(TITLE));
61       return;
62     }
63     TaskType type = null;
64     String symbol = $(TASK_TYPE);
65     if (!symbol.isEmpty()) {
66       type = MRApps.taskType(symbol);
67     }
68     THEAD<TABLE<Hamlet>> thead;
69     if(type != null)
70       thead = html.table("#"+app.getJob().getID()
71         + type).$class("dt-tasks").thead();
72     else
73       thead = html.table("#tasks").thead();
74     //Create the spanning row
75     int attemptColSpan = type == TaskType.REDUCE ? 8 : 3;
76     thead.tr().
77       th().$colspan(5).$class("ui-state-default")._("Task")._().
78       th().$colspan(attemptColSpan).$class("ui-state-default").
79         _("Successful Attempt")._().
80     _();
81 
82     TR<THEAD<TABLE<Hamlet>>> theadRow = thead.
83           tr().
84             th("Name").
85             th("State").
86             th("Start Time").
87             th("Finish Time").
88             th("Elapsed Time").
89             th("Start Time"); //Attempt
90 
91     if(type == TaskType.REDUCE) {
92       theadRow.th("Shuffle Finish Time"); //Attempt
93       theadRow.th("Merge Finish Time"); //Attempt
94     }
95 
96     theadRow.th("Finish Time"); //Attempt
97 
98     if(type == TaskType.REDUCE) {
99       theadRow.th("Elapsed Time Shuffle"); //Attempt
100       theadRow.th("Elapsed Time Merge"); //Attempt
101       theadRow.th("Elapsed Time Reduce"); //Attempt
102     }
103     theadRow.th("Elapsed Time"); //Attempt
104 
105     TBODY<TABLE<Hamlet>> tbody = theadRow._()._().tbody();
106 
107     // Write all the data into a JavaScript array of arrays for JQuery
108     // DataTables to display
109     StringBuilder tasksTableData = new StringBuilder("[\n");
110     for (Task task : app.getJob().getTasks().values()) {
111       if (type != null && task.getType() != type) {
112         continue;
113       }
114       TaskInfo info = new TaskInfo(task);
115       String tid = info.getId();
116 
117       long startTime = info.getStartTime();
118       long finishTime = info.getFinishTime();
119       long elapsed = info.getElapsedTime();
120 
121       long attemptStartTime = -1;
122       long shuffleFinishTime = -1;
123       long sortFinishTime = -1;
124       long attemptFinishTime = -1;
125       long elapsedShuffleTime = -1;
126       long elapsedSortTime = -1;;
127       long elapsedReduceTime = -1;
128       long attemptElapsed = -1;
129       TaskAttempt successful = info.getSuccessful();
130       if(successful != null) {
131         TaskAttemptInfo ta;
132         if(type == TaskType.REDUCE) {
133           ReduceTaskAttemptInfo rta = new ReduceTaskAttemptInfo(successful, type);
134           shuffleFinishTime = rta.getShuffleFinishTime();
135           sortFinishTime = rta.getMergeFinishTime();
136           elapsedShuffleTime = rta.getElapsedShuffleTime();
137           elapsedSortTime = rta.getElapsedMergeTime();
138           elapsedReduceTime = rta.getElapsedReduceTime();
139           ta = rta;
140         } else {
141           ta = new TaskAttemptInfo(successful, type, false);
142         }
143         attemptStartTime = ta.getStartTime();
144         attemptFinishTime = ta.getFinishTime();
145         attemptElapsed = ta.getElapsedTime();
146       }
147 
148       tasksTableData.append("[\"")
149       .append("<a href='" + url("task", tid)).append("'>")
150       .append(tid).append("</a>\",\"")
151       .append(info.getState()).append("\",\"")
152       .append(startTime).append("\",\"")
153       .append(finishTime).append("\",\"")
154       .append(elapsed).append("\",\"")
155       .append(attemptStartTime).append("\",\"");
156 
157       if(type == TaskType.REDUCE) {
158         tasksTableData.append(shuffleFinishTime).append("\",\"")
159         .append(sortFinishTime).append("\",\"");
160       }
161       tasksTableData.append(attemptFinishTime).append("\",\"");
162       if(type == TaskType.REDUCE) {
163         tasksTableData.append(elapsedShuffleTime).append("\",\"")
164         .append(elapsedSortTime).append("\",\"")
165         .append(elapsedReduceTime).append("\",\"");
166       }
167       tasksTableData.append(attemptElapsed).append("\"],\n");
168     }
169     //Remove the last comma and close off the array of arrays
170     if(tasksTableData.charAt(tasksTableData.length() - 2) == ',') {
171       tasksTableData.delete(
172         tasksTableData.length()-2, tasksTableData.length()-1);
173     }
174     tasksTableData.append("]");
175     html.script().$type("text/javascript").
176     _("var tasksTableData=" + tasksTableData)._();
177 
178     TR<TFOOT<TABLE<Hamlet>>> footRow = tbody._().tfoot().tr();
179     footRow.th().input("search_init").$type(InputType.text).$name("task")
180         .$value("ID")._()._().th().input("search_init").$type(InputType.text)
181         .$name("state").$value("State")._()._().th().input("search_init")
182         .$type(InputType.text).$name("start_time").$value("Start Time")._()._()
183         .th().input("search_init").$type(InputType.text).$name("finish_time")
184         .$value("Finish Time")._()._().th().input("search_init")
185         .$type(InputType.text).$name("elapsed_time").$value("Elapsed Time")._()
186         ._().th().input("search_init").$type(InputType.text)
187         .$name("attempt_start_time").$value("Start Time")._()._();
188 
189     if(type == TaskType.REDUCE) {
190       footRow.th().input("search_init").$type(InputType.text)
191           .$name("shuffle_time").$value("Shuffle Time")._()._();
192       footRow.th().input("search_init").$type(InputType.text)
193           .$name("merge_time").$value("Merge Time")._()._();
194     }
195 
196     footRow.th().input("search_init").$type(InputType.text)
197         .$name("attempt_finish").$value("Finish Time")._()._();
198 
199     if(type == TaskType.REDUCE) {
200       footRow.th().input("search_init").$type(InputType.text)
201           .$name("elapsed_shuffle_time").$value("Elapsed Shuffle Time")._()._();
202       footRow.th().input("search_init").$type(InputType.text)
203           .$name("elapsed_merge_time").$value("Elapsed Merge Time")._()._();
204       footRow.th().input("search_init").$type(InputType.text)
205           .$name("elapsed_reduce_time").$value("Elapsed Reduce Time")._()._();
206     }
207 
208     footRow.th().input("search_init").$type(InputType.text)
209         .$name("attempt_elapsed").$value("Elapsed Time")._()._();
210 
211     footRow._()._()._();
212   }
213 }
214