[LNT] r255974 - Better JavaScript and graph normalization
Chris Matthews via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 17 18:20:53 PST 2015
Author: cmatthews
Date: Thu Dec 17 20:20:52 2015
New Revision: 255974
URL: http://llvm.org/viewvc/llvm-project?rev=255974&view=rev
Log:
Better JavaScript and graph normalization
A JS liner made me see the error of my ways. Fixed a few bugs all caused by bad JS style, then fix style everywhere so we are lint clear.
Also normalize graphs based on regression location, not origin.
Also, deal with non-integer Orders.
Modified:
lnt/trunk/lnt/server/ui/api.py
lnt/trunk/lnt/server/ui/static/lnt_graph.js
lnt/trunk/lnt/server/ui/templates/v4_regression_detail.html
lnt/trunk/lnt/server/ui/templates/v4_regression_list.html
Modified: lnt/trunk/lnt/server/ui/api.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/api.py?rev=255974&r1=255973&r2=255974&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/api.py (original)
+++ lnt/trunk/lnt/server/ui/api.py Thu Dec 17 20:20:52 2015
@@ -185,7 +185,7 @@ class Graph(Resource):
if field.status_field:
q = q.filter((field.status_field.column == PASS) |
(field.status_field.column == None))
- samples = [[int(rev), val, {'label': rev, 'date': str(time)}] for val, rev, time in q.all()]
+ samples = [[rev, val, {'label': rev, 'date': str(time)}] for val, rev, time in q.all()]
return samples
Modified: lnt/trunk/lnt/server/ui/static/lnt_graph.js
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/static/lnt_graph.js?rev=255974&r1=255973&r2=255974&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/static/lnt_graph.js (original)
+++ lnt/trunk/lnt/server/ui/static/lnt_graph.js Thu Dec 17 20:20:52 2015
@@ -1,9 +1,12 @@
+/*jslint vars: true, browser: true, devel: true, plusplus: true, unparam: true*/
+/*global $, jQuery, alert, db_name, test_suite_name, init, changes */
+/*global update_graph*/
// Keep the graph data we download.
// Each element is a list of graph data points.
var data_cache = [];
var is_checked = []; // The current list of lines to plot.
var normalize = false;
-var MAX_TO_DRAW = 25;
+var MAX_TO_DRAW = 10;
var STATE_NAMES = {0: 'Detected',
1: 'Staged',
@@ -14,68 +17,164 @@ var STATE_NAMES = {0: 'Detected',
22: 'Fixed'};
var regression_cache = [];
+var lnt_graph = {};
+
+/* Bind events to the zoom bar buttons, so that
+ * the zoom buttons work, then position them
+ * over top of the main graph.
+ */
+function bind_zoom_bar(my_plot) {
+ "use strict";
+ $('#out').click(function (e) {
+ e.preventDefault();
+ my_plot.zoomOut();
+ });
+
+ $('#in').click(function (e) {
+ e.preventDefault();
+ my_plot.zoom();
+ });
+ // Now move the bottons onto the graph.
+ $('#zoombar').css('position', 'relative');
+ $('#zoombar').css('left', '40px');
+ $('#zoombar').css('top', '-235px');
+
+}
+
+
+// Show our overlay tooltip.
+lnt_graph.current_tip_point = null;
+
+function show_tooltip(x, y, item, pos, graph_data) {
+ "use strict";
+ // Given the event handler item, get the graph metadata.
+ function extract_metadata(item) {
+ var index = item.dataIndex;
+ // Graph data is formatted as [x, y, meta_data].
+ var meta_data = item.series.data[index][2];
+ return meta_data;
+ }
+ var data = item.datapoint;
+ var meta_data = extract_metadata(item);
+ var tip_body = '<div id="tooltip">';
+
+ if (meta_data.title) {
+ tip_body += "<b><a href=\"" + meta_data.link + "\">" + meta_data.title + "</a></b></br>";
+ }
+
+ if (meta_data.test_name) {
+ tip_body += "<b>Test:</b> " + meta_data.test_name + "<br>";
+ }
+
+ if (meta_data.label) {
+ tip_body += "<b>Revision:</b> " + meta_data.label + "<br>";
+ }
+ tip_body += "<b>Value:</b> " + data[1].toFixed(4) + "<br>";
+
+ if (meta_data.date) {
+ tip_body += "<b>Date:</b> " + meta_data.date;
+ }
+ if (meta_data.state) {
+ tip_body += "<b>State:</b> " + meta_data.state;
+ }
+
+ tip_body += "</div>";
+ var tooltip_div = $(tip_body).css({
+ position: 'absolute',
+ display: 'none',
+ top: y + 5,
+ left: x + 5,
+ border: '1px solid #fdd',
+ padding: '2px',
+ 'background-color': '#fee',
+ opacity: 0.80,
+ 'z-index': 100000
+ }).appendTo("body").fadeIn(200);
+
+ // Now make sure the tool tip is on the graph canvas.
+ var tt_position = tooltip_div.position();
+
+ var graph_div = $("#graph");
+ var graph_position = graph_div.position();
+
+ // The right edge of the graph.
+ var max_width = graph_position.left + graph_div.width();
+ // The right edge of the tool tip.
+ var tt_right = tt_position.left + tooltip_div.width();
+
+ if (tt_right > max_width) {
+ var diff = tt_right - max_width;
+ var GRAPH_BORDER = 10;
+ var VISUAL_APPEAL = 10;
+ tooltip_div.css({'left' : tt_position.left - diff
+ - GRAPH_BORDER - VISUAL_APPEAL});
+ }
+
+}
+
+// Event handler function to update the tooltop.
+function update_tooltip(event, pos, item, show_fn, graph_data) {
+ "use strict";
+ if (!item) {
+ $("#tooltip").fadeOut(200, function () {
+ $("#tooltip").remove();
+ });
+ lnt_graph.current_tip_point = null;
+ return;
+ }
+
+ if (!lnt_graph.current_tip_point || (lnt_graph.current_tip_point[0] !== item.datapoint[0] ||
+ lnt_graph.current_tip_point[1] !== item.datapoint[1])) {
+ $("#tooltip").remove();
+ lnt_graph.current_tip_point = item.datapoint;
+ show_fn(pos.pageX, pos.pageY, item, pos, graph_data);
+ }
+}
// Grab the graph API url for this line.
function get_api_url(kind, db, ts, mtf) {
- return ["/api", "db_"+ db, "v4", ts, kind, mtf].join('/');
+ "use strict";
+ return ["/api", "db_" + db, "v4", ts, kind, mtf].join('/');
}
// Grab the URL for a regression by id.
function get_regression_url(db, ts, regression) {
- return ["", "db_"+ db, "v4", ts, "regressions", regression].join('/');
+ "use strict";
+ return ["", "db_" + db, "v4", ts, "regressions", regression].join('/');
}
-
-
-function try_normal(data_array, end_rev) {
- $("#graph_range").prop("min", 0);
- var max = $("#graph_range").prop("max");
- if (max < data_array.length) {
- $("#graph_range").prop("max", data_array.length);
- }
- var center = -1;
- for (var i = 0; i < data_array.length; i++) {
- if (data_array[i][0] == end_rev) {
- center = i;
+// Normalize this data to the element in index
+function normalize_data(data_array, index) {
+ "use strict";
+ var new_data = new Array(data_array.length);
+ var i = 0;
+ var factor = 0;
+ for (i = 0; i < data_array.length; i++) {
+ if (data_array[i][0] == index) {
+ factor = data_array[i][1];
break;
}
}
- console.assert(center != -1, "Center was not found");
- var smaller = $("#graph_range").val();
- var total = data_array.length;
- var to_draw = total - smaller;
- var upper = data_array.length;
- var lower = 0;
- if (center - (to_draw/2) > 0) {
- lower = center - (to_draw/2);
- }
- if (center + (to_draw/2) < total) {
- upper = center + (to_draw/2);
- }
-
- data_array = data_array.slice(lower, upper);
-
- if (normalize) {
- console.log(data_array);
- return normalize_data(data_array);
- } else {
- return data_array;
+ console.assert(factor !== 0, "Did not find the element to normalize on.");
+ for (i = 0; i < data_array.length; i++) {
+ new_data[i] = jQuery.extend({}, data_array[i]);
+ new_data[i][1] = data_array[i][1] / factor;
}
+ return new_data;
}
-function normalize_data(data_array) {
- var new_data = []
-
- for (var i = 0; i < data_array.length; i++) {
- new_data[i] = jQuery.extend({}, data_array[i]);
- new_data[i][1] = data_array[i][1] / data_array[0][1];
+function try_normal(data_array, index) {
+ "use strict";
+ if (normalize) {
+ return normalize_data(data_array, index);
}
- return new_data;
-
+ return data_array;
}
+
function make_graph_point_entry(data, color, regression) {
+ "use strict";
var radius = 0.25;
var fill = true;
if (regression) {
@@ -92,7 +191,7 @@ function make_graph_point_entry(data, co
}
};
if (regression) {
- entry["points"]["symbol"] = "cross";
+ entry.points.symbol = "cross";
}
return entry;
}
@@ -115,96 +214,148 @@ var color_codes = ["#4D4D4D",
"#b2df8a",
"#fb9a99",
"#fdbf6f",
- "#cab2d6"]
+ "#cab2d6"];
function new_graph_data_callback(data, index) {
+ "use strict";
data_cache[index] = data;
update_graph();
}
+
function get_regression_id() {
+ "use strict";
var path = window.location.pathname.split("/");
- if (path[path.length - 2] == "regressions") {
- return parseInt(path[path.length - 1]);
- } else {
- return null;
+ if (path[path.length - 2] === "regressions") {
+ return parseInt(path[path.length - 1], 10);
}
}
-
function new_graph_regression_callback(data, index) {
+ "use strict";
$.each(data, function (i, d) {
- if (get_regression_id() != null) {
- if (get_regression_id() == d['id'] || d['state'] == 21) {
+ if (get_regression_id() !== null) {
+ if (get_regression_id() === d.id || d.state === 21) {
return;
}
}
- if ( ! (regression_cache[index])) {
+ if (!(regression_cache[index])) {
regression_cache[index] = [];
}
- metadata = {'label': d['end_point'][0],
- 'title': d['title'],
- 'link': get_regression_url(db_name, test_suite_name, d['id']),
- 'state': STATE_NAMES[d['state']]}
- regression_cache[index].push([parseInt(d['end_point'][0]), d['end_point'][1],metadata]);
+ var metadata = {'label': d.end_point[0],
+ 'title': d.title,
+ 'id': d.id,
+ 'link': get_regression_url(db_name, test_suite_name, d.id),
+ 'state': STATE_NAMES[d.state]};
+ regression_cache[index].push([parseInt(d.end_point[0], 10), d.end_point[1], metadata]);
});
update_graph();
}
-NOT_DRAWING = '<div class="alert alert-success" role="alert">' +
- 'Too many to graph.<a href="#" class="close" data-dismiss="alert" aria-label="close">Ã</a>' +
- '</div>';
+var NOT_DRAWING = '<div class="alert alert-success" role="alert">' +
+ 'Too many lines to plot. Limit is ' + MAX_TO_DRAW + "." +
+ '<a href="#" class="close" data-dismiss="alert" aria-label="close">Ã</a>' +
+ '</div>';
+
+
function update_graph() {
+ "use strict";
var to_draw = [];
var starts = [];
var ends = [];
+ var lines_to_draw = 0;
+ var i = 0;
+ var color = null;
+ var data = null;
+ var regressions = null;
// Data.
- for ( var i = 0; i < changes.length; i++) {
-
- if (is_checked[i] && data_cache[i]) {
- starts.push(changes[i].start);
- ends.push(changes[i].end);
- var color = color_codes[i % color_codes.length];
- var data = try_normal(data_cache[i], changes[i].end);
-
- to_draw.push(make_graph_point_entry(data, color, false));
- to_draw.push({"color": color, "data": data});
-
- }
+ for (i = 0; i < changes.length; i++) {
+ if (is_checked[i] && data_cache[i]) {
+ lines_to_draw++;
+ starts.push(changes[i].start);
+ ends.push(changes[i].end);
+ color = color_codes[i % color_codes.length];
+ data = try_normal(data_cache[i], changes[i].start);
+ to_draw.push(make_graph_point_entry(data, color, false));
+ to_draw.push({"color": color, "data": data});
+ }
}
// Regressions.
- for ( var i = 0; i < changes.length; i++) {
-
- if (is_checked[i] && data_cache[i]) {
- if (regression_cache[i]) {
- var regressions = try_normal(regression_cache[i], changes[i].end);
- to_draw.push(make_graph_point_entry(regressions, color, true));
- }
-
+ for (i = 0; i < changes.length; i++) {
+ if (is_checked[i] && data_cache[i]) {
+ if (regression_cache[i]) {
+ regressions = try_normal(regression_cache[i]);
+ to_draw.push(make_graph_point_entry(regressions, color, true));
}
+ }
+ }
+ // Limit the number of lines to plot: the graph gets cluttered and slow.
+ if (lines_to_draw > MAX_TO_DRAW) {
+ $('#errors').empty().prepend(NOT_DRAWING);
+ return;
}
var lowest_rev = Math.min.apply(Math, starts);
var highest_rev = Math.max.apply(Math, ends);
- console.log(to_draw);
- init(to_draw, lowest_rev, highest_rev);
+ init(to_draw, lowest_rev, highest_rev);
}
// To be called by main page. It will fetch data and make graph ready.
function add_data_to_graph(URL, index) {
- var current_to_draw = is_checked.filter(function(x){ return x; }).length
- if (current_to_draw > MAX_TO_DRAW) {
- $('#errors').empty().prepend(NOT_DRAWING);
- is_checked[index] = true;
- return;
- }
- $.getJSON(get_api_url("graph", db_name, test_suite_name, URL), function(data) {
+ "use strict";
+ $.getJSON(get_api_url("graph", db_name, test_suite_name, URL), function (data) {
new_graph_data_callback(data, index);
- });
- $.getJSON(get_api_url("regression", db_name, test_suite_name, URL), function(data) {
+ });
+ $.getJSON(get_api_url("regression", db_name, test_suite_name, URL), function (data) {
new_graph_regression_callback(data, index);
- });
+ });
is_checked[index] = true;
}
+
+function init_graph () {
+ $('#normalize').click(function (e) {
+ normalize = !normalize;
+ update_graph();
+ });
+
+}
+
+
+function init(data, start_highlight, end_highlight) {
+ "use strict";
+ // First, set up the primary graph.
+ var graph = $("#graph");
+ var graph_plots = data;
+ var line_width = 1;
+ if (data.length > 0 && data[0].data.length < 50) {
+ line_width = 2;
+ }
+ var graph_options = {
+ series : {
+ lines : {lineWidth : line_width},
+ shadowSize : 0
+ },
+ highlight : {
+ range: {"end": [end_highlight], "start": [start_highlight]},
+ alpha: "0.35",
+ stroke: true
+ },
+ zoom : { interactive : false },
+ pan : { interactive : true,
+ frameRate: 60 },
+ grid : {
+ hoverable : true,
+ clickable: true
+ }
+ };
+
+ var main_plot = $.plot("#graph", graph_plots, graph_options);
+
+ // Add tooltips.
+ graph.bind("plotclick", function (e, p, i) {
+ update_tooltip(e, p, i, show_tooltip, graph_plots);
+ });
+ bind_zoom_bar(main_plot);
+}
Modified: lnt/trunk/lnt/server/ui/templates/v4_regression_detail.html
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/templates/v4_regression_detail.html?rev=255974&r1=255973&r2=255974&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/templates/v4_regression_detail.html (original)
+++ lnt/trunk/lnt/server/ui/templates/v4_regression_detail.html Thu Dec 17 20:20:52 2015
@@ -34,7 +34,9 @@
{% block javascript %}
-var g = {}
+var g = {};
+var test_suite_name = "{{ testsuite_name }}";
+var db_name = "{{ request.view_args.db_name }}";
var changes = [
{% for form_change in form.field_changes%}
@@ -46,163 +48,6 @@ var changes = [
{% endfor %}
];
-var test_suite_name = "{{ testsuite_name }}";
-var db_name = "{{ request.view_args.db_name }}";
-
-/* Bind events to the zoom bar buttons, so that
- * the zoom buttons work, then position them
- * over top of the main graph.
- */
-function bind_zoom_bar(my_plot) {
-
- $('#out').click(function (e) {
- e.preventDefault();
- my_plot.zoomOut();
- });
-
- $('#in').click(function (e) {
- e.preventDefault();
- my_plot.zoom();
- });
-
-
- // Now move the bottons onto the graph.
- $('#zoombar').css('position', 'relative');
- $('#zoombar').css('left', '40px');
- $('#zoombar').css('top', '-235px');
-}
-$('#normalize').click(function (e) {
- normalize = !normalize;
- alert(normalize);
- update_graph();
-});
-function init(data, start_highlight, end_highlight) {
- // Set up the primary graph.
- var graph = $("#graph");
- var graph_plots = data;
- var line_width = 1;
- if (data.length > 0 && data[0]['data'].length < 50) {
- line_width = 2;
- }
- var graph_options = {
- series : {
- lines : {
- lineWidth : line_width },
- shadowSize : 0
- },
- highlight : {
-
- range: {"end": [end_highlight], "start": [start_highlight]},
- alpha: "0.35",
- stroke: true,
- },
- zoom : { interactive : false },
- pan : { interactive : true,
- frameRate: 60 },
- grid : {
- hoverable : true,
- clickable: true}
- };
-
- var main_plot = $.plot("#graph", graph_plots, graph_options);
-
- // Add tooltips.
- $("#graph").bind("plotclick", function(e,p,i) {
- update_tooltip(e, p, i, show_tooltip, graph_plots); });
- bind_zoom_bar(main_plot);
-
-
-}
-
-// Show our overlay tooltip.
-g.current_tip_point = null;
-function show_tooltip(x, y, item, pos, graph_data) {
-
- // Given the event handler item, get the graph metadata.
- function extract_metadata(item, graph_data) {
- var index = item.dataIndex;
- var series_index = item.seriesIndex;
- // Graph data is formatted as [x, y, meta_data].
- var meta_data = item.series.data[index][2];
- return meta_data;
-
- }
- var data = item.datapoint;
- var meta_data = extract_metadata(item, graph_data);
- var tip_body = '<div id="tooltip">';
-
- if ("title" in meta_data) {
- tip_body += "<b><a href=\"" + metadata.link + "\">" + meta_data.title + "</a></b></br>";
- }
-
- if ("test_name" in meta_data) {
- tip_body += "<b>Test:</b> " + meta_data.test_name + "<br>";
- }
-
- if ("label" in meta_data) {
- tip_body += "<b>Revision:</b> " + meta_data.label + "<br>";
- }
- tip_body += "<b>Value:</b> " + data[1].toFixed(4) + "<br>";
-
- if ("date" in meta_data) {
- tip_body += "<b>Date:</b> " + meta_data.date;
- }
- if ("state" in meta_data) {
- tip_body += "<b>State:</b> " + meta_data.state;
- }
-
- tip_body += "</div>";
- var tooltip_div = $(tip_body).css( {
- position: 'absolute',
- display: 'none',
- top: y + 5,
- left: x + 5,
- border: '1px solid #fdd',
- padding: '2px',
- 'background-color': '#fee',
- opacity: 0.80,
- 'z-index': 100000
- }).appendTo("body").fadeIn(200);
-
- // Now make sure the tool tip is on the graph canvas.
- var tt_position = tooltip_div.position();
- var tt_offset = tooltip_div.offset();
-
- var graph_div = $("#graph");
- var graph_position = graph_div.position();
-
- // The right edge of the graph.
- var max_width = graph_position.left + graph_div.width();
- // The right edge of the tool tip.
- var tt_right = tt_position.left + tooltip_div.width();
-
- if (tt_right > max_width) {
- var diff = tt_right - max_width
- var GRAPH_BORDER = 10;
- var VISUAL_APPEAL = 10;
- tooltip_div.css({'left' : tt_position.left - diff
- - GRAPH_BORDER - VISUAL_APPEAL});
- }
-
-}
-
-// Event handler function to update the tooltop.
-function update_tooltip(event, pos, item, show_fn, graph_data) {
- if (!item) {
- $("#tooltip").fadeOut(200, function () {
- $("#tooltip").remove();
- });
- g.current_tip_point = null;
- return;
- }
-
- if (!g.current_tip_point || (g.current_tip_point[0] != item.datapoint[0] ||
- g.current_tip_point[1] != item.datapoint[1])) {
- $("#tooltip").remove();
- g.current_tip_point = item.datapoint;
- show_fn(pos.pageX, pos.pageY, item, pos, graph_data);
- }
-}
{% endblock %}
{% block body %}
@@ -238,7 +83,7 @@ function update_tooltip(event, pos, item
<th>Old</th><th>New</th>
<th>%Δ</th>
<th>Now</th>
- <th>Curernt</th>
+ <th>Current</th>
<th>Age</th>
</tr>
@@ -274,8 +119,8 @@ function update_tooltip(event, pos, item
</tbody>
</table>
-<button id="all" type="button" class="btn btn-default" onclick="all_checks()">Check Visable</button>
-<button id="clear" type="button" class="btn btn-default" onclick="clear_checks()">Clear Visable</button>
+<button id="all" type="button" class="btn btn-default" onclick="all_checks()">Check Visible</button>
+<button id="clear" type="button" class="btn btn-default" onclick="clear_checks()">Clear Visible</button>
<!-- Button to trigger modal -->
@@ -434,26 +279,21 @@ var dt = null;
$(document).ready( function () {
dt = $('#changes_table').DataTable({
- "dom": '<"top"if>rt<"bottom"Flp>',
+ "dom": '<"top">rt<"bottom">',
"drawCallback": function( settings ) {
register_checkboxes();
},
- "aLengthMenu": [
- [25, 50, 100, 200, -1],
- [25, 50, 100, 200, "All"]],
-});
+ });
- for (var i = 0; i < changes.length; i++) {
- is_checked[i] = false;
- }
+ for (var i = 0; i < changes.length; i++) {
+ is_checked[i] = false;
+ }
register_checkboxes();
+ init_graph();
all_checks();
- $('#normalize').click(function (e) {
- normalize = !normalize;
- update_graph();
- });
+
update_graph();
update_order_summary();
Modified: lnt/trunk/lnt/server/ui/templates/v4_regression_list.html
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/server/ui/templates/v4_regression_list.html?rev=255974&r1=255973&r2=255974&view=diff
==============================================================================
--- lnt/trunk/lnt/server/ui/templates/v4_regression_list.html (original)
+++ lnt/trunk/lnt/server/ui/templates/v4_regression_list.html Thu Dec 17 20:20:52 2015
@@ -71,8 +71,12 @@
<script type="text/javascript">
$(document).ready( function () {
- dt = $('#regression_list').DataTable();
+ var settings = {"dom": '<"top"if>rt<"bottom"Flp>',
+ "aLengthMenu": [[50, -1],
+ [50, "All"]]};
+ dt = $('#regression_list').DataTable(settings);
});
+
</script>
{% endblock %}
More information about the llvm-commits
mailing list