[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