/** * 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. */ module.exports = { durationFormatter:function(d) { if (d==0) { return "0" } var seconds = Math.floor(parseInt(d) / 1000); if ( seconds < 60 ) return seconds + "s"; var minutes = Math.floor(seconds / 60); if ( minutes < 60 ) { var x = seconds - 60*minutes; return minutes + "m" + (x==0 ? "" : " " + x + "s"); } var hours = Math.floor(minutes / 60); if ( hours < 24 ) { var x = minutes - 60*hours; return hours + "h" + (x==0 ? "" : " " + x + "m"); } var days = Math.floor(hours / 24); if ( days < 7 ) { var x = hours - 24*days; return days + "d " + (x==0 ? "" : " " + x + "h"); } var weeks = Math.floor(days / 7); var x = days - 7*weeks; return weeks + "w " + (x==0 ? "" : " " + x + "d"); }, bytesFormatter:function(y) { if (y >= 1125899906842624) { return Math.floor(10 * y / 1125899906842624)/10 + " PB" } else if (y >= 1099511627776){ return Math.floor(10 * y / 1099511627776)/10 + " TB" } else if (y >= 1073741824) { return Math.floor(10 * y / 1073741824)/10 + " GB" } else if (y >= 1048576) { return Math.floor(10 * y / 1048576)/10 + " MB" } else if (y >= 1024) { return Math.floor(10 * y / 1024)/10 + " KB" } else { return y + " B"} }, addSeries:function(svgg,series,color,xscale,yscale,margin,startTime,dotInfo) { if (series.length==0) return; var self = this; var g = svgg.append("svg:g").selectAll("g") .data(series) .enter().append("svg:g") .attr("transform", "translate(0,"+margin+")"); g.append("svg:circle") .attr("r",function(d) {return d.r;}) .attr("cx",function(d) {return xscale(d.x);}) .attr("cy",function(d) {return yscale(d.y);}) .style("fill",color) .style("fill-opacity",0.8) .style("stroke",d3.interpolateRgb(color, 'black')(0.125)) .append("title") .text(function(d) { return dotInfo[Math.round(xscale(d.x))][Math.round(yscale(d.y))]; }); g.append("svg:line") .attr("x1", function(d) { return xscale(d.x)+d.r; } ) .attr("x2", function(d) { return xscale(d.x+d.y); } ) .attr("y1", function(d) { return yscale(d.y); } ) .attr("y2", function(d) { return yscale(d.y); } ) .style("stroke",d3.interpolateRgb(color, 'black')(0.125)) .style("stroke-width",2) .append("title") .text(function(d) { return dotInfo[Math.round(xscale(d.x))][Math.round(yscale(d.y))]; }); }, /** * * @param mapNodeLocal * @param mapRackLocal * @param mapOffSwitch * @param reduceOffSwitch * @param startTime * @param endTime * @param svgw * @param svgh * @param element */ drawJobTasks:function (mapNodeLocal, mapRackLocal, mapOffSwitch, reduceOffSwitch, startTime, endTime, svgw, svgh, element) { var rmax = 24; // default value var axisHeight = 24; var margin = {"vertical":10, "horizontal":50}; var w = svgw - 2*margin.horizontal; var h = svgh - 2*margin.vertical; var x = d3.time.scale.utc() .domain([startTime, endTime]) .range([0, w]); var xrel = d3.time.scale() .domain([0, endTime-startTime]) .range([0, w]); // create axes var topAxis = d3.svg.axis() .scale(x) .orient("bottom"); var self = this; var bottomAxis = d3.svg.axis() .scale(xrel) .orient("bottom") .tickFormat(function(d) {return self.durationFormatter(d.getTime())}); var svg = d3.select("div#" + element).append("svg:svg") .attr("width", svgw+"px") .attr("height", svgh+"px"); var svgg = svg.append("g") .attr("transform", "translate("+margin.horizontal+","+margin.vertical+")"); svgg.append("g") .attr("class", "x axis top") .call(topAxis); svgg.append("g") .attr("class", "x axis bottom") .call(bottomAxis) .attr("transform", "translate(0,"+(h-axisHeight)+")"); var ymax = 0; if (mapNodeLocal.length > 0) ymax = Math.max(ymax, d3.max(mapNodeLocal, function(d) { return d.y; } )); if (mapRackLocal.length > 0) ymax = Math.max(ymax, d3.max(mapRackLocal, function(d) { return d.y; } )); if (mapOffSwitch.length > 0) ymax = Math.max(ymax, d3.max(mapOffSwitch, function(d) { return d.y; } )); if (reduceOffSwitch.length > 0) ymax = Math.max(ymax, d3.max(reduceOffSwitch, function(d) { return d.y; } )); var y = d3.scale.linear() .domain([0, ymax]) .range([h-2*axisHeight-rmax, 0]); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickFormat(self.durationFormatter); svgg.append("svg:g") .attr("class", "y axis") .call(yAxis) .attr("transform", "translate(0,"+(axisHeight+rmax)+")") .append("text") .attr("transform", "rotate(-90)") .attr("x", -(h-2*axisHeight-rmax)/2) .attr("y", -margin.horizontal + 11) .attr("class", "axislabel") .text("Task Attempt Duration"); var dotInfo = []; var mapDotInfo = function(d) { var thisx = Math.round(x(d.x)); var thisy = Math.round(y(d.y)); if (!(thisx in dotInfo)) dotInfo[thisx] = []; var existing = dotInfo[thisx][thisy]; var newInfo = d.label + " \n" + 'Run-time: ' + self.durationFormatter(d.y) + ' \nWait-time: ' + self.durationFormatter(d.x-startTime) + ' \nI/O: ' + self.bytesFormatter(d.io) + ' \nStatus: ' + d.status; if (existing) dotInfo[thisx][thisy] = existing + " \n" + newInfo; else dotInfo[thisx][thisy] = newInfo; }; mapNodeLocal.forEach(mapDotInfo); mapRackLocal.forEach(mapDotInfo); mapOffSwitch.forEach(mapDotInfo); reduceOffSwitch.forEach(mapDotInfo); this.addSeries(svgg, mapNodeLocal, "green", x, y, axisHeight+rmax, startTime, dotInfo); this.addSeries(svgg, mapRackLocal,'#66B366', x, y, axisHeight+rmax, startTime, dotInfo); this.addSeries(svgg, mapOffSwitch, 'brown', x, y, axisHeight+rmax, startTime, dotInfo); this.addSeries(svgg, reduceOffSwitch, 'steelblue', x, y, axisHeight+rmax, startTime, dotInfo); } };