| <!-- |
| Licensed 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. See accompanying LICENSE file. |
| --> |
| <!doctype> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <link rel="stylesheet" href="css/bootstrap.min.css" media="screen"> |
| <link rel="stylesheet" href="css/bootstrap-responsive.min.css"> |
| <style type="text/css"> |
| body { |
| font: 20px sans-serif; |
| } |
| |
| .axis path, |
| .axis line { |
| fill: none; |
| stroke: #000; |
| shape-rendering: crispEdges; |
| } |
| .axis text { |
| font-family: sans-serif; |
| font-size: 20px; |
| } |
| |
| .line { |
| fill: none; |
| stroke: steelblue; |
| stroke-width: 3px; |
| } |
| |
| .legend { |
| padding: 1px; |
| font: 18px sans-serif; |
| background: yellow; |
| box-shadow: 2px 2px 1px #888; |
| } |
| |
| .title { |
| font: 24px sans-serif; |
| } |
| .divborder { |
| border-width: 1px; |
| border-style: solid; |
| border-color: black; |
| margin-top:10px |
| } |
| </style> |
| <script src="js/thirdparty/d3.v3.js"></script> |
| <script src="js/thirdparty/jquery.js"></script> |
| <script src="js/thirdparty/bootstrap.min.js"></script> |
| |
| </head> |
| |
| <body> |
| <div class="row"> |
| <div class="offset5" style="margin-top:20px; margin-bottom:20px"> |
| Select the generated metrics log file (realtimetrack.json): <input type='file' id='jsonfile' /> <input type='button' value='Generate !' onClick='draw()' /><br> |
| </div> |
| </div> |
| |
| <div class="row"> |
| <div class="divborder span8" style="margin-left:50px" id="area1"></div> |
| <div class="divborder span8" id="area2"></div> |
| </div> |
| |
| <div class="row"> |
| <div class="divborder span8" style="margin-left:50px" id="area3"></div> |
| <div class="divborder span8" id="area4"></div> |
| </div> |
| |
| <div class="row"> |
| <div class="divborder span8" style="margin-left:50px" id="area5"></div> |
| <div class="divborder span8" id="area6"></div> |
| </div> |
| |
| <div class="row"> |
| <div class="divborder span8" style="margin-left:50px" id="area7"></div> |
| <div class="span7" id="area8"></div> |
| </div> |
| <p> </p> |
| <script> |
| // select file and draw |
| function draw() { |
| var filepath = document.getElementById('jsonfile').value; |
| if (filepath) { |
| for (var i = 1; i < 9; i ++) { |
| $('#area' + i).empty(); |
| } |
| filepath = filepath.replace("C:\\fakepath\\", ""); |
| drawCharts(filepath); |
| } else { |
| alert('choose file firstly.'); |
| } |
| } |
| |
| function drawCharts(filepath) { |
| $.getJSON(filepath, function(data) { |
| var numQueues = 0; |
| var queueNames = new Array(); |
| for (var j in data[0]) { |
| if (j.substring(0, 'queue'.length) === 'queue') { |
| queueNames[numQueues] = j; |
| numQueues ++; |
| } |
| } |
| numQueues /= 2; |
| |
| // create graph |
| $.getJSON(filepath, function(data) { |
| var basetime = data[0].time; |
| data.forEach(function(d) { |
| d.time = (d.time - basetime) / 1000; |
| }); |
| |
| var legends = ["running.applications", "running.containers"]; |
| drawEachChart("#area1", data, legends, "Cluster running applications & containers", "Number", 0, 0); |
| legends = ["jvm.free.memory", "jvm.max.memory", "jvm.total.memory"]; |
| drawEachChart("#area2", data, legends, "JVM memory", "Memory (GB)", 0, 0); |
| legends = ["cluster.allocated.memory", "cluster.available.memory"]; |
| drawEachChart("#area3", data, legends, "Cluster allocated & available memory", "Memory (GB)", 0, 0); |
| legends = ["cluster.allocated.vcores", "cluster.available.vcores"]; |
| drawEachChart("#area4", data, legends, "Cluster allocated & available vcores", "Number", 0, 0); |
| |
| for (var i = 0; i < numQueues; i ++) { |
| legends[i] = queueNames[i * 2]; |
| } |
| drawEachChart("#area5", data, legends, "Queue allocated memory", "Memory (GB)", 1, 100); |
| for (var i = 0; i < numQueues; i ++) { |
| legends[i] = queueNames[i * 2 + 1]; |
| } |
| drawEachChart("#area6", data, legends, "Queue allocated vcores", "VCores", 1, 90); |
| |
| legends = [ |
| "scheduler.allocate.timecost", |
| "scheduler.handle-NODE_ADDED.timecost", "scheduler.handle-NODE_REMOVED.timecost", |
| "scheduler.handle-NODE_UPDATE.timecost", "scheduler.handle-APP_ADDED.timecost", |
| "scheduler.handle-APP_REMOVED.timecost", "scheduler.handle-CONTAINER_EXPIRED.timecost" |
| ]; |
| drawEachChart("#area7", data, legends, "Scheduler allocate & handle operations timecost", "Timecost (ms)", 0, 210); |
| }); |
| }); |
| } |
| |
| // draw different chart |
| function drawEachChart(chartArea, data, legends, title, yLabelTitle, isArea, pl) { |
| // drawchart |
| var margin = {top: 50, right: 250, bottom: 50, left: 70}; |
| var width = 800 - margin.left - margin.right; |
| var height = 420 - margin.top - margin.bottom; |
| |
| var x = d3.scale.linear().range([0, width]); |
| var y = d3.scale.linear().range([height, 0]); |
| var xAxis = d3.svg.axis().scale(x).orient("bottom"); |
| var yAxis = d3.svg.axis().scale(y).orient("left"); |
| |
| var color = d3.scale.category10(); |
| |
| if (isArea == 1){ |
| var area = d3.svg.area() |
| .x(function(d) { return x(d.time); }) |
| .y0(function(d) { return y(d.y0); }) |
| .y1(function(d) { return y(d.y0 + d.y); }); |
| |
| var stack = d3.layout.stack() |
| .values(function(d) { return d.values; }); |
| |
| // create chart |
| var svg = d3.select(chartArea).append("svg") |
| .attr("width", width + margin.left + margin.right) |
| .attr("height", height + margin.top + margin.bottom) |
| .append("g") |
| .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
| |
| color.domain(d3.keys(data[0]) |
| .filter(function(key) {return $.inArray(key, legends) !== -1; })); |
| |
| var points = stack(color.domain().map(function(name) { |
| return { |
| name: name, |
| values: data.map(function(d) { |
| return {time: d.time, y: d[name]}; |
| }) |
| }; |
| })); |
| |
| // x & y |
| x.domain(d3.extent(data, function(d) { return d.time; })); |
| y.domain([ |
| d3.min(points, function(c) { |
| return 0.9 * d3.min(c.values, function(v) { return v.y; }); }), |
| d3.max(points, function(c) { |
| return 1.1 * d3.max(c.values, function(v) { return v.y + v.y0; }); }) |
| ]); |
| |
| svg.append("g").attr("class", "x axis") |
| .attr("transform", "translate(0," + height + ")") |
| .call(xAxis) |
| .append("text") |
| .attr("transform", "translate(" + (width / 2) + ", 45)") |
| .style("text-anchor", "middle") |
| .text("Time (s)"); |
| |
| svg.append("g") |
| .attr("class", "y axis") |
| .call(yAxis) |
| .append("text") |
| .attr("transform", "rotate(-90)") |
| .attr("y", 0 - margin.left) |
| .attr("x",0 - (height / 2)) |
| .attr("dy", "1em") |
| .style("text-anchor", "middle") |
| .text(yLabelTitle); |
| |
| var point = svg.selectAll(".point") |
| .data(points) |
| .enter().append("g"); |
| |
| point.append("path") |
| .attr("class", "area") |
| .attr("d", function(d) { return area(d.values); }) |
| .style("fill", function(d) { return color(d.name); }); |
| } else { |
| // lines |
| var line = d3.svg.line() |
| .interpolate("basis") |
| .x(function(d) { return x(d.time); }) |
| .y(function(d) { return y(d.value); }); |
| |
| // create chart |
| var svg = d3.select(chartArea).append("svg") |
| .attr("id", title) |
| .attr("width", width + margin.left + margin.right) |
| .attr("height", height + margin.top + margin.bottom) |
| .append("g") |
| .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
| |
| color.domain(d3.keys(data[0]) |
| .filter(function(key) {return $.inArray(key, legends) !== -1; })); |
| |
| var values = color.domain().map(function(name) { |
| return { |
| name: name, |
| values: data.map(function(d) { |
| return {time: d.time, value: +d[name]}; |
| }) |
| }; |
| }); |
| |
| // x & y |
| x.domain(d3.extent(data, function(d) { return d.time; })); |
| y.domain([ |
| d3.min(values, function(c) { return 0.9 * d3.min(c.values, function(v) { return v.value; }); }), |
| d3.max(values, function(c) { return 1.1 * d3.max(c.values, function(v) { return v.value; }); }) |
| ]); |
| |
| svg.append("g").attr("class", "x axis") |
| .attr("transform", "translate(0," + height + ")") |
| .call(xAxis) |
| .append("text") |
| .attr("transform", "translate(" + (width / 2) + ", 45)") |
| .style("text-anchor", "middle") |
| .text("Time (s)"); |
| |
| svg.append("g") |
| .attr("class", "y axis") |
| .call(yAxis) |
| .append("text") |
| .attr("transform", "rotate(-90)") |
| .attr("y", 0 - margin.left) |
| .attr("x",0 - (height / 2)) |
| .attr("dy", "1em") |
| .style("text-anchor", "middle") |
| .text(yLabelTitle); |
| |
| var value = svg.selectAll(".city") |
| .data(values) |
| .enter().append("g") |
| .attr("class", "city"); |
| |
| value.append("path") |
| .attr("class", "line") |
| .attr("d", function(d) { return line(d.values); }) |
| .style("stroke", function(d) { return color(d.name); }); |
| } |
| // title |
| svg.append("text") |
| .attr("x", (width / 2)) |
| .attr("y", 10 - (margin.top / 2)) |
| .attr("text-anchor", "middle") |
| .text(title); |
| |
| // legend |
| var legend = svg.append("g") |
| .attr("class", "legend") |
| .attr("x", width - 50) |
| .attr("y", 25) |
| .attr("height", 120) |
| .attr("width", 140); |
| |
| legend.selectAll('g').data(legends) |
| .enter() |
| .append('g') |
| .each(function(d, i) { |
| var g = d3.select(this); |
| g.append("rect") |
| .attr("x", width - 5 - pl) |
| .attr("y", i*20 + 0) |
| .attr("width", 10) |
| .attr("height", 10) |
| .style("fill", color(d)); |
| |
| g.append("text") |
| .attr("x", width + 15 - pl) |
| .attr("y", i * 20 + 8) |
| .attr("height",30) |
| .attr("width",250) |
| .style("fill", color(d)) |
| .text(d); |
| }); |
| } |
| </script> |
| </body> |
| </html> |