Index: perf/dashboard/ui/generic_plotter.html |
=================================================================== |
--- perf/dashboard/ui/generic_plotter.html (revision 298504) |
+++ perf/dashboard/ui/generic_plotter.html (working copy) |
@@ -1,533 +0,0 @@ |
-<html> |
- |
-<!-- |
- Copyright (c) 2012 The Chromium Authors. All rights reserved. |
- Use of this source code is governed by a BSD-style license that can be |
- found in the LICENSE file. |
---> |
- |
-<!-- |
- For testing this file locally, start a localhost server at the root of the |
- perf directory (e.g. with "python -m SimpleHTTPServer") and pass in a |
- baseUrl as a query parameter, e.g. |
- http://localhost:8000/dashboard/ui/generic_plotter.html?history=150&rev=-1&graph=dom&baseUrl=http://localhost:8000/data/linux-release-webkit-latest/dromaeo_domcore/. |
- |
- You need a localhost server to get around Chromium's restrictions on loading |
- file urls in XMLHttpRequests. |
- |
- A brief note on terminology as used here: a "graph" is a plotted screenful |
- of data, showing the results of one type of test: for example, the |
- page-load-time graph. A "trace" is a single line on a graph, showing one |
- one for the test: for example, the reference build trace on the |
- page-load-time graph. |
- |
- This page plots arbitrary numerical data loaded from files in a specific |
- format. It uses two or more data files, all JSON-encoded: |
- |
- graphs.dat: a list of objects, each with these properties: name (the name |
- of a graph) and units (the units for the data to be read by humans). |
- Schematically: |
- [{"name": <graph_name>, "units": <units>}, ...] |
- |
- <graphname>-summary.dat: for each of the graphs listed in graphs.dat, the |
- corresponding summary file holds rows of data. Each row of data is an |
- object with several properties: |
- "rev": the revision number for this row of data |
- "traces": an object with several properties of its own. The name of |
- the property corresponds to a trace name, used only as an |
- internal identifier, and the property's value is an array of |
- its measurement and that measurement's standard deviation (or |
- other measurement error). |
- Schematically: |
- {"rev": <rev>, |
- "traces": {<trace_name1>: [<value1>, <stddev1>], |
- <trace_name2>: [<value2>, <stddev2>], ...} |
- } |
---> |
-<head> |
-<style> |
-body { |
- font-family: sans-serif; |
-} |
-div#output { |
- cursor: pointer; |
-} |
-div#switcher * { |
- border: 1px solid black; |
- border-radius: 4px 4px 0 0; |
- padding-left: 0.5em; |
- padding-right: 0.5em; |
-} |
-div#switcher a { |
- background: #ddd; |
- cursor: pointer; |
-} |
-canvas.plot { |
- border: 1px solid black; |
-} |
-div.plot-coordinates { |
- font-family: monospace; |
-} |
-iframe { |
- display: none; |
- width: 100%; |
- height: 100%; |
- border: none; |
-} |
-.selector { |
- border: solid 1px black; |
- cursor: pointer; |
- padding-left: 0.3em; |
- background-color: white; |
- width: 80px; |
- display: inline-block; |
-} |
-.selector:hover { |
- background-color: rgb(200,200,250); |
-} |
-div#selectors { |
- display: none; |
- right: 6px; |
- position: absolute; |
-} |
-#explain { |
- font-size: 0.75em; |
- font-style: italic; |
- color: rgb(100,100,100); |
-} |
-#views { |
- border: 1px solid black; |
- width: 100%; |
- display: none; |
-} |
-#webkit-tab { |
- border-left: none; |
- display: none; |
-} |
-</style> |
- |
-<script src="js/common.js"></script> |
-<script src="js/plotter.js"></script> |
-<script src="js/coordinates.js"></script> |
-<script src="config.js"></script> |
-<script> |
-document.title = Config.title + ' - ' + Config.buildslave; |
- |
-var did_position_details = false; |
-var units = 'thing-a-ma-bobs'; |
-var graph_list = []; |
-var first_trace = ''; |
- |
-var refresh_params = false; |
-var params = ParseParams(); |
-if (!('history' in params)) { |
- params.history = 150; |
- refresh_params = true; |
-} |
-if (!('rev' in params)) { |
- params.rev = -1; // -1 specifies the latest revision. |
- refresh_params = true; |
-} |
-if (refresh_params) |
- window.location.href = MakeURL(params); |
- |
-if (!Config.detailTabs) |
- Config.detailTabs = {'view-change': 'CL'}; |
- |
-/** |
- * Encapsulates a *-summary.dat file. |
- * @constructor |
- */ |
-function Rows(data) { |
- this.rows = data.split('\n'); |
- this.length = this.rows.length; |
-} |
- |
-/** |
- * Returns the row at the given index. |
- */ |
-Rows.prototype.get = function(i) { |
- if (!i in this.rows || this.rows[i] === undefined) return null; |
- if (!this.rows[i].length) return null; |
- var row = JSON.parse(this.rows[i]); |
- row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']); |
- row.webkitRevision = isNaN(row['webkit_rev']) ? |
- row['webkit_rev'] : parseInt(row['webkit_rev']); |
- return row; |
-}; |
- |
-function report_error(error) { |
- document.getElementById("output").innerHTML = "<p>" + error + "</p>"; |
-} |
- |
-function received_graph_list(data, error) { |
- if (error) { |
- report_error(error); |
- return; |
- } |
- graph_list = JSON.parse(data); |
- |
- if (!('graph' in params) || params.graph == '') { |
- if (graph_list.length > 0) |
- params.graph = graph_list[0].name |
- } |
- |
- // Add a selection tab for each graph, and find the units for the selected |
- // one while we're at it. |
- tabs = []; |
- for (var index = 0; index < graph_list.length; ++index) { |
- var graph = graph_list[index]; |
- tabs.push(graph.name); |
- if (graph.name == params.graph) |
- units = graph.units; |
- } |
- initPlotSwitcher(tabs); |
- |
- // Fetch the data for the selected graph. |
- fetch_summary(); |
- |
-} |
- |
-function go_to(graph) { |
- params.graph = graph; |
- if (params.graph == '') |
- delete params.graph; |
- window.location.href = MakeURL(params); |
-} |
- |
-function get_url() { |
- var new_url = encodeURI(window.location.href); |
- new_url = new_url.replace(/'/g, '%27'); |
- new_url = new_url.replace(/\&lookout=1/, ''); |
- if (new_url.indexOf('http://') == 0 || new_url.indexOf('https://') == 0) |
- return new_url; |
- return ''; |
-} |
- |
-function on_clicked_plot(prev_entry, current_entry) { |
- if ('lookout' in params) { |
- window.open(get_url()); |
- return; |
- } |
- |
- // Define sources for detail tabs |
- if ('view-change' in Config.detailTabs) { |
- // If the changeLinkPrefix has {PREV_CL}/{CL} markers, replace them. |
- // Otherwise, append to the URL. |
- var url = Config.changeLinkPrefix; |
- if (url.indexOf('{PREV_CL}') >= 0 || url.indexOf('{CL}') >= 0) { |
- url = url.replace('{PREV_CL}', prev_entry.chromium); |
- url = url.replace('{CL}', current_entry.chromium); |
- } else { |
- url += prev_entry.chromium + ':' + current_entry.chromium; |
- } |
- document.getElementById('view-change').setAttribute('src', url); |
- } |
- if ('view-pages' in Config.detailTabs) { |
- document.getElementById('view-pages').src = 'details.html?cl=' + |
- current_entry.chromium + '&graph=' + params.graph + '&trace=' + |
- first_trace; |
- } |
- if ('view-coverage' in Config.detailTabs) { |
- document.getElementById('view-coverage').src = |
- Config.coverageLinkPrefix + current_entry.chromium; |
- } |
- if (!isNaN(prev_entry.webkit) && !isNaN(current_entry.webkit) && |
- prev_entry.webkit <= current_entry.webkit) { |
- Config.detailTabs['view-webkit-change'] = 'Webkit'; |
- document.getElementById('webkit-tab').style.display = 'inline-block'; |
- var url = 'http://trac.webkit.org/log/?verbose=on&rev=' + |
- current_entry.webkit + '&stop_rev=' + prev_entry.webkit; |
- document.getElementById('view-webkit-change').src = url; |
- } else { |
- var webkitView = document.getElementById('view-webkit-change'); |
- if (webkitView.style.display == 'block') |
- show_first_view(); |
- delete Config.detailTabs['view-webkit-change']; |
- document.getElementById('webkit-tab').style.display = 'none'; |
- } |
- |
- if (!did_position_details) { |
- show_first_view(); |
- position_details(); |
- did_position_details = true; |
- } |
-} |
- |
-function show_first_view() { |
- for (var tab in Config.detailTabs) { |
- change_view(tab); |
- break; |
- } |
-} |
- |
-function received_summary(data, error) { |
- if (error) { |
- report_error(error); |
- return; |
- } |
- // Parse the summary data file. |
- var rows = new Rows(data); |
- var max_rows = rows.length; |
- if (max_rows > params.history) |
- max_rows = params.history; |
- |
- var allTraces = {}; |
- |
- // Find the start and end of the data slice we will focus on. |
- var start_row = 0; |
- if (params.rev > 0) { |
- var i = 0; |
- while (i < rows.length) { |
- var row = rows.get(i); |
- |
- // If the current row's revision is higher than the desired revision, |
- // continue searching. |
- if (row.revision > params.rev) { |
- i++; |
- continue; |
- } |
- |
- // We're either just under or at the desired revision. |
- start_row = i; |
- |
- // If the desired revision does not exist, use the row before it. |
- if (row.revision < params.rev && start_row > 0) |
- start_row -= 1; |
- |
- break; |
- } |
- } |
- |
- // Some summary files contain data not listed in rev-descending order. For |
- // those cases, it is possible we will find a start row in the middle of the |
- // data whose neighboring data is not nearby. See xp-release-dual-core |
- // moz rev 265 => no graph. |
- var end_row = start_row + max_rows; |
- |
- // Build and order a list of revision numbers. |
- var revisionNumbers = []; |
- var hasNumericRevisions = true; |
- // graphData[rev] = {trace1:[value, stddev], trace2:[value, stddev], ...} |
- var graphData = {}; |
- for (var i = start_row; i < end_row; ++i) { |
- var row = rows.get(i); |
- if (!row) |
- continue; |
- var traces = row['traces']; |
- for (var j = 0; j < traces.length; ++j) |
- traces[j] = parseFloat(traces[j]); |
- |
- if (!(row.revision in graphData)) { |
- graphData[row.revision] = {}; |
- } |
- graphData[row.revision][row.webkitRevision] = traces; |
- if (isNaN(row.revision) || isNaN(row.webkitRevision)) { |
- hasNumericRevisions = false; |
- } |
- revisionNumbers.push( |
- { chromium: row.revision, webkit: row.webkitRevision }); |
- |
- // Collect unique trace names. If traces are explicitly specified in |
- // params, delete unspecified trace data. |
- for (var traceName in traces) { |
- if (typeof(params['trace']) != 'undefined' && |
- params['trace'][traceName] != 1) { |
- delete(traces[traceName]); |
- } |
- allTraces[traceName] = 1; |
- } |
- } |
- |
- // Build a list of all the trace names we've seen, in the order in which |
- // they appear in the data file. Although JS objects are not required by |
- // the spec to iterate their properties in order, in practice they do, |
- // because it causes compatibility problems otherwise. |
- var traceNames = []; |
- for (var traceName in allTraces) |
- traceNames.push(traceName); |
- |
- first_trace = traceNames[0]; |
- |
- // If the revisions are numeric (svn), sort them numerically to ensure they |
- // are in ascending order. Otherwise, if the revisions aren't numeric (git), |
- // reverse them under the assumption the rows were prepended to the file. |
- if (hasNumericRevisions) { |
- revisionNumbers.sort(function(a, b) { |
- var revdiff = parseInt(a.chromium, 10) - parseInt(b.chromium, 10); |
- if (revdiff != 0) { |
- return revdiff; |
- } |
- return parseInt(a.webkit, 10) - parseInt(b.webkit, 10); |
- }); |
- } else { |
- revisionNumbers.reverse(); |
- } |
- |
- // Build separate ordered lists of trace data. |
- var traceData = {}; |
- for (var revIndex = 0; revIndex < revisionNumbers.length; ++revIndex) { |
- var rev = revisionNumbers[revIndex].chromium; |
- var webkitrev = revisionNumbers[revIndex].webkit; |
- var revisionData = graphData[rev][webkitrev]; |
- for (var nameIndex = 0; nameIndex < traceNames.length; ++nameIndex) { |
- var traceName = traceNames[nameIndex]; |
- if (!traceData[traceName]) |
- traceData[traceName] = []; |
- if (!revisionData[traceName]) |
- traceData[traceName].push([NaN, NaN]); |
- else |
- traceData[traceName].push([parseFloat(revisionData[traceName][0]), |
- parseFloat(revisionData[traceName][1])]); |
- } |
- } |
- var plotData = []; |
- for (var traceName in traceData) |
- plotData.push(traceData[traceName]); |
- var plotter = new Plotter(revisionNumbers, plotData, traceNames, units, |
- document.getElementById("output")); |
- plotter.onclick = on_clicked_plot; |
- plotter.plot(); |
-} |
- |
-function fetch_summary() { |
- if ('graph' in params) |
- file = escape(params.graph) + "-summary.dat" |
- else |
- file = "summary.dat" |
- var baseUrl = params.baseUrl || ''; |
- Fetch(baseUrl + file, received_summary); |
-} |
- |
-function fetch_graph_list() { |
- var baseUrl = params.baseUrl || ''; |
- Fetch(baseUrl + "graphs.dat", received_graph_list); |
-} |
- |
-function initPlotSwitcher(tabs) { |
- var switcher = document.getElementById("switcher"); |
- for (var i = 0; i < tabs.length; i++) { |
- var is_selected = tabs[i] == params.graph; |
- var tab = document.createElement(is_selected ? "span" : "a"); |
- tab.appendChild(document.createTextNode(tabs[i] + " ")); |
- if (!is_selected) |
- tab.addEventListener("click", goToClosure(tabs[i]), false); |
- switcher.appendChild(tab); |
- } |
-} |
- |
-function goToClosure(graph) { |
- return function(){go_to(graph)}; |
-} |
- |
-function position_details() { |
- var views = document.getElementById("views"); |
- views.style.display = "block"; |
- var selectors = document.getElementById("selectors"); |
- selectors.style.display = "block"; |
- |
- var output = document.getElementById("output"); |
- var views_width = output.offsetWidth - selectors.offsetWidth; |
- |
- views.style.height = (window.innerHeight - output.offsetHeight - |
- output.offsetTop - 16) + "px"; |
- selectors.style.top = (views.offsetTop - selectors.offsetHeight + 1) + "px"; |
-} |
- |
-function change_view(target) { |
- for (var tab in Config.detailTabs) { |
- document.getElementById(tab).style.display = |
- (tab == target ? "block" : "none"); |
- } |
-} |
- |
-function init() { |
- // We need to fill the graph list before parsing the params or fetching the |
- // data, so we have a default graph in case none was specified. |
- fetch_graph_list(); |
-} |
- |
-window.addEventListener("resize", position_details, false); |
-window.addEventListener("load", init, false); |
-</script> |
-</head> |
- |
- |
-<body> |
-<div id="header_lookout" align="center"> |
- <font style='color: #0066FF; font-family: Arial, serif; |
- font-size: 20pt; font-weight: bold;'> |
- <script> |
- document.write("<a target=\"_blank\" href=\""); |
- document.write(get_url()); |
- document.write("\">"); |
- if ('header' in params && params.header != '') { |
- document.write(escape(params.header)); |
- } else { |
- document.write(Config.title); |
- } |
- document.write("</a>"); |
- </script> |
- </font> |
-</div> |
- |
-<div id="header_text"> |
-Builds generated by the <a href="http://build.chromium.org/">Chromium Buildbot</a> |
-are run through <b> |
-<script> |
-document.write(Config.title); |
-</script> |
-</b>and the results of that test are charted here. |
-</div> |
- |
-<div id="explain"> |
-The vertical axis is measured values, and the horizontal |
-axis is the revision number for the build being tested. |
-</div> |
-<p></p> |
-<div id="switcher"> |
- |
-</div> |
-<div id="output"></div> |
-<div id="details"> |
- <div id="views"> |
- <script> |
- for (var tab in Config.detailTabs) { |
- document.write("<iframe id=\"" + tab + "\"></iframe>"); |
- } |
- </script> |
- <iframe id='view-webkit-change'></iframe> |
- </div> |
- <div id="selectors"> |
- <script> |
- var firstTab = true; |
- for (var tab in Config.detailTabs) { |
- document.write("<div "); |
- if (firstTab) { |
- firstTab = false; |
- } else { |
- document.write("style=\"border-left: none\" "); |
- } |
- document.write("class=\"selector\" onclick=\"change_view('" |
- + tab + "')\">" + Config.detailTabs[tab] + "</div>"); |
- } |
- </script><div id="webkit-tab" class="selector" |
- onclick="change_view('view-webkit-change')">Webkit</div> |
- </div> |
-</div> |
-<pre id="log"></pre> |
-<script> |
-if ('lookout' in params) { |
- document.getElementById("switcher").style.display = "none"; |
- document.getElementById("details").style.display = "none"; |
- document.getElementById("header_text").style.display = "none"; |
- document.getElementById("explain").style.display = "none"; |
- if ('thumbnail' in params) { |
- document.getElementById("header_lookout").style.display = "none"; |
- } |
-} else { |
- document.getElementById("header_lookout").style.display = "none"; |
-} |
-</script> |
-</body> |
-</html> |