summaryrefslogtreecommitdiffstats
path: root/web/topchanges/main.js
diff options
context:
space:
mode:
authorjasplin <qt-info@nokia.com>2011-05-26 15:07:14 +0200
committerjasplin <qt-info@nokia.com>2011-05-26 15:07:14 +0200
commitcac600fc0a2069e34036c5112ba4cfb8483bb559 (patch)
tree8fba1a4e47113b902582cc6c5f03af909b6e9e73 /web/topchanges/main.js
parenteae8ff839296559a637ff100d7585562d68b5cb1 (diff)
Added Top Changes page to replace ranking feature.
This commit introduces the Top Changes page. This page retrieves 'top 10' changes for all host/platform/branch combinations from a new 'change' database table. The script that updates this table for a given host/platform/branch combination is run automatically after uploading a new set of results (since this is when new changes may potentially arise). This commit also removes the ranking feature as this is obsoleted (more or less) by the new feature.
Diffstat (limited to 'web/topchanges/main.js')
-rw-r--r--web/topchanges/main.js422
1 files changed, 422 insertions, 0 deletions
diff --git a/web/topchanges/main.js b/web/topchanges/main.js
new file mode 100644
index 0000000..cb9a208
--- /dev/null
+++ b/web/topchanges/main.js
@@ -0,0 +1,422 @@
+// --- BEGIN Global variables -----------------------------------
+
+var limit = null; // Size of top score list (a "Top 10" list has limit=10 etc.)
+
+// Id-to-name mappings:
+var hosts = null;
+var platforms = null;
+var branches = null;
+var sha1s = null;
+var benchmarks = null;
+var metrics = null;
+
+// Test cases with changes:
+var testCases = null;
+
+// --- END Global variables -------------------------------------
+
+function toggleTestCaseFilter() {
+ var divObj_hidden = $("#div_testCaseFilter_hidden");
+ var divObj_shown = $("#div_testCaseFilter_shown");
+ if (divObj_shown.css("display") == "none") {
+ divObj_shown.css("display", "block");
+ divObj_hidden.css("display", "none");
+ } else {
+ divObj_shown.css("display", "none");
+ divObj_hidden.css("display", "block");
+ }
+}
+
+
+function updateTestCaseTable() {
+
+ // Clear table:
+ $("#test_cases tr").remove();
+
+ // Populate table:
+
+ var nc = 8; // # of columns
+ var nr = Math.ceil(testCases.length / nc); // # of rows
+ var c1 = testCases.length % nc; // lowest column index for empty bottom cell
+
+ var html = "";
+ for (r = 0; r < nr; ++r) {
+ if ((r < (nr - 1)) || (nc > 1))
+ html += "<tr>";
+ for (c = 0; c < nc; ++c) {
+ if ((r == (nr - 1)) && (c >= c1) && (!(nc == 1))) {
+ html += "<td></td>"; // Fill in empty bottom cell
+ } else {
+ var index = -1;
+ if (c <= c1)
+ index = r + c * nr;
+ else
+ index = r + c1 * nr + (c - c1) * (nr - 1);
+
+ var name = testCases[index];
+ html += "<td style=\"white-space: nowrap\">";
+ html += "<input type=\"checkbox\" id=\"tc" + index + "\" " +
+ "name=\"" + name + "\"/>";
+ html += "<label for=\"tc" + index + "\">" + name +
+ "</label>";
+ html += "</td>";
+ }
+ }
+ if ((r < (nr - 1)) || (nc > 1))
+ html += "</tr>";
+ }
+
+ $("#test_cases").append(html);
+}
+
+
+// ### 2 B DOCUMENTED!
+function timeSeriesURL(
+ database, hostId, platformId, branchId, sha1Id, benchmarkId, metricId,
+ difftol, durtolmin, durtolmax) {
+
+ query = "?db=" + database;
+ query += "&host=" + encodeURIComponent(hosts[hostId]);
+ query += "&platform=" + encodeURIComponent(platforms[platformId]);
+ query += "&branch=" + encodeURIComponent(branches[branchId]);
+ query += "&sha11=earliest"; // invalid SHA-1 specifies infinite startpoint
+ query += "&sha12=latest"; // invalid SHA-1 specifies infinite endpoint
+ query += "&sha1_sel=" + sha1s[sha1Id];
+ query += "&benchmark=" + encodeURIComponent(benchmarks[benchmarkId]);
+ query += "&metric=" + encodeURIComponent(metrics[metricId]);
+ query += "&difftol=" + difftol;
+ query += "&durtolmin=" + durtolmin;
+ query += "&durtolmax=" + durtolmax;
+
+ url = "http://" + location.host + "/bm2/analysis/tsbm.shtml" + query;
+ return url;
+}
+
+
+// Loads a main table from the database.
+function loadMainTable(tableName, regressions, last, timescope, premature) {
+
+ var tableSel = "#" + tableName;
+
+ updateStatus("fetching top changes ...", true);
+
+ //var database = $('#database').val();
+ var database = "bm"; // ### Hardcoded for now!
+ // ### The following tolerances are hardcoded for now. They are assumed
+ // to match the tolerances used for computing the 'change' table
+ // (see updatechanges.py script)!
+ var difftol = 1.1;
+ var durtolmin = 3;
+ var durtolmax = 10;
+
+ query = "?db=" + database;
+ query += "&cmd=topchanges";
+ query += "&regressions=" + (regressions ? 1 : 0);
+ query += "&last=" + (last ? 1 : 0);
+ query += "&timescope=" + timescope;
+ query += "&premature=" + (premature ? 1 : 0);
+ query += "&limit=" + limit;
+
+ // Add test case filter:
+ testCaseFilter = "";
+ $("#test_cases input").each(function() {
+ if (this.checked) {
+ testCaseFilter += " " + this.name;
+ }
+ });
+ query += "&testcasefilter=" + testCaseFilter;
+
+ url = "http://" + location.host + "/cgi-bin/getstatswrapper" + query;
+ //alert("url: >" + url + "<");
+
+ $.ajax({
+ url: url,
+ type: "GET",
+ dataType: "json",
+
+ success: function(data, textStatus, request) {
+ if (request.readyState == 4) {
+ if (request.status == 200) {
+
+ if (data.error != null) {
+ updateStatus(
+ "fetching top changes ... failed: " +
+ data.error, false);
+ return
+ }
+
+ updateStatus("fetching top changes ... done", false);
+ updateStatus("", false);
+
+ // Remove all rows below the header ...
+ $(tableSel + " tr:gt(0)").remove();
+
+ // Insert new rows ...
+ contexts = data.contexts;
+ html = "";
+ for (i = 0; i < contexts.length; ++i) {
+ context = contexts[i];
+
+ var hostId = context.hostId;
+ var platformId = context.platformId;
+ var branchId = context.branchId;
+
+ html += "<tr>";
+
+ html += "<td style=\"white-space: nowrap\">" +
+ hosts[hostId] + "</td>";
+ html += "<td style=\"white-space: nowrap\">" +
+ platforms[platformId] + "</td>";
+ html += "<td style=\"white-space: nowrap\">" +
+ branches[branchId] + "</td>";
+
+ // Fill in scores:
+ for (j = 0; j < context.topchanges.length; ++j) {
+ var tc = context.topchanges[j];
+ var benchmarkId = tc[0];
+ var metricId = tc[1];
+ var sha1Id = tc[2];
+ var timestamp = tc[3];
+ var score = tc[4];
+ var bgColor = scoreColor(score, data.regressions);
+ html += "<td style=\"background-color:" +
+ bgColor + "\">";
+ html += "<a href=\"" +
+ timeSeriesURL(
+ database, hostId, platformId, branchId,
+ sha1Id, benchmarkId, metricId, difftol,
+ durtolmin, durtolmax) +
+ "\"" +
+ " target=\"_blank\" style=\"" +
+ "text-decoration:none; color:black; " +
+ "display:block\">";
+ html += score;
+ html += "</a>";
+
+ html += "</td>";
+ }
+
+ // Fill in missing scores:
+ for (j = context.topchanges.length; j < limit; ++j) {
+ html +=
+ "<td style=\"background-color:#bbb\"></td>";
+ }
+
+ html += "</tr>";
+ }
+
+ $(tableSel + " > tbody:last").append(html);
+ $(tableSel).trigger("update");
+ if (html != "") // hm ... why is this test necessary?
+ $(tableSel).trigger("appendCache");
+ }
+ }
+ },
+
+ error: function(request, textStatus, errorThrown) {
+ descr = errorThrown;
+ if (errorThrown == null) {
+ descr = "undefined error - is the server down?";
+ }
+ updateStatus(
+ "fetching top changes ... error: " + descr, false);
+ }
+
+ // complete: function(request, textStatus) {
+ // alert("complete; request.status: " + request.status)
+ // }
+
+ });
+
+ return false;
+}
+
+
+// Updates the main table based on the current change type.
+function updateMainTable() {
+ var pctTag = $("#primary_change_type option:selected").attr("tag");
+ var sctTag = $("#secondary_change_type option:selected").attr("tag");
+ var pmtTag =
+ ($("#incl_premature_changes:checked").length == 1) ? "_pmt" : "";
+ var tableName = "mt_" + pctTag + "_" + sctTag + pmtTag;
+ var divName = "div_" + tableName;
+ // ### NOTE: tableName and divName unused for now. Later they may be used
+ // for caching based on multiple main tables (of which only one is shown
+ // at a time).
+
+ // Hide all tables but the current one:
+ // ### NOTE: Unused for now (see above)
+ // $('div[id^="div_mt_"]').css("display", "none");
+ // $("#" + divName).css("display", "block");
+
+ var regressions = (pctTag == "regr");
+ var last = (sctTag == "last");
+ var sctTag_int = parseInt(sctTag);
+ var timescope =
+ ((sctTag == "all") || (isNaN(sctTag_int))) ? -1 : sctTag_int;
+ var premature = (pmtTag == "_pmt");
+
+ // Load the table from the database if necessary:
+ // if ($("#" + tableName + " tr").length == 1) {
+ // // The table for this change type is empty
+ // // (except for header row), so populate it from the database:
+ // loadMainTable(tableName, regressions, last, timescope, premature)
+ // }
+
+ // ### Just reload the only main table for now (later a caching scheme
+ // should be implemented):
+ loadMainTable("main_table", regressions, last, timescope, premature)
+}
+
+
+function fetchNameMappings() {
+ updateStatus("fetching name mappings ...", true);
+
+ //database = $('#database').val();
+ database = "bm"; // ### Hardcoded for now!
+
+ query = "?db=" + database;
+ query += "&cmd=namemappings";
+
+ url = "http://" + location.host + "/cgi-bin/getstatswrapper" + query;
+ //alert("url: >" + url + "<");
+
+ $.ajax({
+ url: url,
+ type: "GET",
+ dataType: "json",
+
+ success: function(data, textStatus, request) {
+ if (request.readyState == 4) {
+ if (request.status == 200) {
+
+ if (data.error != null) {
+ updateStatus(
+ "fetching name mappings ... failed: " +
+ data.error, false);
+ return
+ }
+
+ updateStatus("fetching name mappings ... done", false);
+ updateStatus("", false);
+
+ hosts = data.hosts;
+ platforms = data.platforms;
+ branches = data.branches;
+ sha1s = data.sha1s;
+ benchmarks = data.benchmarks;
+ metrics = data.metrics;
+
+ updateTestCaseTable();
+ updateMainTable();
+ }
+ }
+ },
+
+ error: function(request, textStatus, errorThrown) {
+ descr = errorThrown;
+ if (errorThrown == null) {
+ descr = "undefined error - is the server down?";
+ }
+ updateStatus(
+ "fetching name mappings ... error: " + descr, false);
+ }
+
+ // complete: function(request, textStatus) {
+ // alert("complete; request.status: " + request.status)
+ // }
+
+ });
+
+ return false;
+}
+
+
+function fetchTestCases() {
+ updateStatus("fetching test cases ...", true);
+
+ //database = $('#database').val();
+ database = "bm"; // ### Hardcoded for now!
+
+ query = "?db=" + database;
+ query += "&cmd=testcaseswithchanges";
+
+ url = "http://" + location.host + "/cgi-bin/getstatswrapper" + query;
+ //alert("url: >" + url + "<");
+
+ $.ajax({
+ url: url,
+ type: "GET",
+ dataType: "json",
+
+ success: function(data, textStatus, request) {
+ if (request.readyState == 4) {
+ if (request.status == 200) {
+
+ if (data.error != null) {
+ updateStatus(
+ "fetching test cases ... failed: " +
+ data.error, false);
+ return
+ }
+
+ updateStatus("fetching test cases ... done", false);
+ updateStatus("", false);
+
+ testCases = data.testCases;
+
+ fetchNameMappings();
+ }
+ }
+ },
+
+ error: function(request, textStatus, errorThrown) {
+ descr = errorThrown;
+ if (errorThrown == null) {
+ descr = "undefined error - is the server down?";
+ }
+ updateStatus(
+ "fetching test cases ... error: " + descr, false);
+ }
+
+ // complete: function(request, textStatus) {
+ // alert("complete; request.status: " + request.status)
+ // }
+
+ });
+
+ return false;
+}
+
+
+$(document).ready(function() {
+
+ initTablesorter();
+
+ // Initialize main table:
+ $("#main_table").tablesorter({
+ headers: {
+ 3: { sorter: "mixed_numeric_desc_before_missing" }, // rank pos 0
+ 4: { sorter: false }, // 1
+ 5: { sorter: false }, // 2
+ 6: { sorter: false }, // 3
+ 7: { sorter: false }, // 4
+ 8: { sorter: false }, // 5
+ 9: { sorter: false }, // 6
+ 10: { sorter: false }, // 7
+ 11: { sorter: false }, // 8
+ 12: { sorter: false } // 9
+ }
+ });
+
+ // Initialize change type:
+ $("#primary_change_type option[singular_name='regression']").attr(
+ "selected", true);
+ $("#incl_premature_changes").attr("checked", false)
+
+ // Deduce the limit directly from the static HTML of the main table:
+ // (subtract 3 for the Host, Platform, and Branch columns)
+ limit = $("#main_table th").length - 3;
+
+ fetchTestCases();
+});