Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(233)

Side by Side Diff: chrome/test/functional/perf/endure_graphs/endure_plotter.js

Issue 10832403: Add Chrome Endure graph plotting code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 /*
2 Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 Use of this source code is governed by a BSD-style license that can be
4 found in the LICENSE file.
5 */
6
7 /**
8 * @fileoverview Handles drawing a general Chrome Endure graph.
9 */
10
11 document.title = Config.title + ' - ' + Config.buildslave;
12
13 var unitsX = 'unitsX';
14 var unitsY = 'unitsY';
15 var unitsYOther = null;
16 var graphList = [];
17 var revisionNumbers = [];
18 var graphDataOtherRows = null;
19
20 var eventRows = null;
21 var eventTypes = [];
22 var eventInfo = null;
23
24 var params = ParseParams();
25
26 /**
27 * Encapsulates a *-summary.dat file.
28 * @constructor
29 *
30 * @param {string} data Raw data from a *-summary.dat file.
31 */
32 function Rows(data) {
33 this.rows = data.split('\n');
34 this.length = this.rows.length;
35 }
36
37 /**
38 * Returns the row at the given index.
39 *
40 * @param {number} i The index of a row of data from the *-summary.dat file.
41 * @return {Object} An object representing a row of data from the input file.
42 */
43 Rows.prototype.get = function(i) {
44 if (!this.rows[i].length) return null;
45 var row = jsonToJs(this.rows[i]);
46 row.revision = isNaN(row['rev']) ? row['rev'] : parseInt(row['rev']);
47 return row;
48 };
49
50 /**
51 * Gets the current URL, but without the 'lookout' parameter.
52 *
53 * @return {string} The current URL, but without the 'lookout' parameter.
54 */
55 function get_url() {
56 new_url = window.location.href;
57 new_url = new_url.replace(/\&lookout=1/, '');
58 return new_url;
59 }
60
61 /**
62 * Reports an error message on the webpage.
63 *
64 * @param {string} error An error message to display on the page.
65 */
66 function reportError(error) {
67 document.getElementById('output').innerHTML = '<p>' + error + '</p>';
68 }
69
70 /**
71 * Converts a JSON string into a Javascript object.
72 *
73 * @param {string} data A string in JSON format.
74 * @return {Object} A Javascript object computed from the JSON string.
75 */
76 function jsonToJs(data) {
77 return eval('(' + data + ')')
78 }
79
80 /**
81 * Causes the page to navigate to another graph.
82 *
83 * @param {string} graph The name of the graph to which to navigate.
84 */
85 function goTo(graph) {
86 params.graph = graph;
87 window.location.href = MakeURL(params);
88 }
89
90 /**
91 * Returns a function that will navigate the page to another graph.
92 *
93 * @param {string} graph The name of the graph to which to navigate.
94 * @return {Function} A function that will navigate the page to another graph.
95 */
96 function goToClosure(graph) {
97 return function(){goTo(graph)};
98 }
99
100 /**
101 * Changes the event being overlayed on the graph.
102 *
103 * @param {string} eventName The name of the event to overlay on the graph.
104 */
105 function changeEventCompare(eventName) {
106 delete params.revisionOther;
107 delete params.graphOther;
108 if (eventName == 'None') {
109 delete params.event;
110 window.location.href = MakeURL(params);
111 } else {
112 params.event = eventName;
113 window.location.href = MakeURL(params);
114 }
115 }
116
117 /**
118 * Changes the other measurement being overlayed on top of an original line on
119 * the graph.
120 *
121 * @param {string} graphName The name of the other graph to overlay on top of
122 * the existing graph.
123 */
124 function changeMeasurementCompare(graphName) {
125 delete params.revisionOther;
126 delete params.event;
127 if (graphName == 'None') {
128 delete params.graphOther;
129 window.location.href = MakeURL(params);
130 } else {
131 params.graphOther = graphName;
132 window.location.href = MakeURL(params);
133 }
134 }
135
136 /**
137 * Changes the number of the other revision to compare against on the graph.
138 *
139 * @param {string} revision The revision number of the other line to plot on
140 * the graph.
141 */
142 function changeRevisionCompare(revision) {
143 delete params.graphOther;
144 delete params.event;
145 if (revision == 'None') {
146 delete params.revisionOther;
147 window.location.href = MakeURL(params);
148 } else {
149 params.revisionOther = revision;
150 window.location.href = MakeURL(params);
151 }
152 }
153
154 /**
155 * Changes the displayed revision number of the graph line.
156 *
157 * @param {string} revision The revision number of the graph to display.
158 */
159 function changeRevision(revision) {
160 delete params.revisionOther;
161 delete params.graphOther;
162 delete params.event;
163 params.revision = revision;
164 window.location.href = MakeURL(params);
165 }
166
167 /**
168 * Initializes the UI for changing the revision number of the displayed graph.
169 */
170 function initRevisionOptions() {
171 var html = '<table cellpadding=5><tr><td>';
172 html += '<b>Chrome revision:</b>&nbsp;';
173 html += '<select onchange=\"changeRevision(this.value)\">';
174 for (var i = 0; i < revisionNumbers.length; ++i) {
175 html += '<option id=\"r' + revisionNumbers[i] + '\"';
176 if (revisionNumbers[i] == params.revision)
177 html += 'selected=\"true\"';
178 html += '>' + revisionNumbers[i] + '</option>';
179 }
180 html += '</select></td></tr></table>';
181
182 document.getElementById('revisions').innerHTML = html;
183 }
184
185 /**
186 * Initializes the UI for changing what is compared against the current line
187 * on the displayed graph.
188 */
189 function initComparisonOptions() {
190 var html = '<table cellpadding=5>';
191 html += '<tr><td><b>Compare with (select one):</b></td></tr>';
192
193 html += '<tr><td>&nbsp;&nbsp;&nbsp;Another run:&nbsp;';
194 html += '<select onchange=\"changeRevisionCompare(this.value)\">';
195 html += '<option selected=\"true\">None</option>';
196 for (var i = 0; i < revisionNumbers.length; ++i) {
197 html += '<option id=\"r' + revisionNumbers[i] + '\"';
198 if (revisionNumbers[i] == params.revisionOther)
199 html += 'selected=\"true\"';
200 html += '>' + revisionNumbers[i] + '</option>';
201 }
202 html += '</select></td></tr>'
203
204 html += '<tr><td>&nbsp;&nbsp;&nbsp;Another measurement of same run:&nbsp;';
205 html += '<select onchange=\"changeMeasurementCompare(this.value)\">';
206 html += '<option selected=\"true\">None</option>';
207 for (var i = 0; i < graphList.length; ++i) {
208 var graph = graphList[i];
209 html += '<option id=\"r' + graph.name + '\"';
210 if (graph.name == params.graphOther)
211 html += 'selected=\"true\"';
212 html += '>' + graph.name + '</option>';
213 }
214 html += '</select></td></tr>';
215
216 html += '<tr><td>&nbsp;&nbsp;&nbsp;Event overlay:&nbsp;';
217 if (eventTypes.length >= 1) {
218 html += '<select onchange=\"changeEventCompare(this.value)\">';
219 html += '<option selected=\"true\">None</option>';
220 for (var i = 0; i < eventTypes.length; ++i) {
221 var eventType = eventTypes[i];
222 html += '<option id=\"' + eventType + '\"';
223 if (eventType == params.event)
224 html += 'selected=\"true\"';
225 html += '>' + eventType + '</option>';
226 }
227 html += '</select>';
228 } else {
229 html += '&nbsp;<i><font size=-1>No events for this revision</font></i>';
230 }
231 html += '</td></tr></table>';
232
cmp 2012/08/27 02:42:01 remove blank line
dennis_jeffrey 2012/08/27 23:37:41 Done.
233
234 document.getElementById('comparisons').innerHTML = html;
235 }
236
237 /**
238 * Initializes the UI for the tabs at the top of a graph to change the displayed
239 * line.
240 */
241 function initPlotSwitcher(tabs) {
242 var switcher = document.getElementById('switcher');
243 for (var i = 0; i < tabs.length; ++i) {
244 var is_selected = tabs[i] == params.graph;
245 var tab = document.createElement(is_selected ? 'span' : 'a');
246 tab.appendChild(document.createTextNode(tabs[i] + ' '));
247 if (!is_selected)
248 tab.addEventListener('click', goToClosure(tabs[i]), false);
249 switcher.appendChild(tab);
250 }
251 }
252
253 /**
254 * Adds data to existing arrays indicating what data should be plotted.
255 *
256 * @param {number} revisionNum The revision number of the data to plot.
257 * @param {Object} dataRows The |Rows| object containing the plot data.
258 * @param {Array} plotData A list of data lines to plot, to which new data will
259 * be appended.
260 * @param {Array} dataDescriptions A list of string descriptions corresponding
261 * to data lines in |plotData|, to which new data will be appended.
262 * @return {boolean} Whether or not new plot data was actually appended to the
263 * given arrays.
264 */
265 function addToPlotData(revisionNum, dataRows, plotData, dataDescriptions) {
266 // Get data for the revision number(s) to plot.
267 var revData = null;
268 for (var i = 0; i < dataRows.length; ++i) {
269 var row = dataRows.get(i);
270 if (!row)
271 continue;
272
273 var revision = row.revision;
274 var traces = row.traces;
275
276 if (revisionNum == revision) {
277 revData = traces;
278 break;
279 }
280 }
281
282 if (!revData)
283 return false;
284
285 // Identify the (single) trace name associated with this revision.
286 var traceName = '';
287 for (var t in revData) {
288 if (traceName) {
289 reportError('Only one trace per revision is supported.');
290 return false;
291 }
292 traceName = t
cmp 2012/08/27 02:42:01 append a semicolon
dennis_jeffrey 2012/08/27 23:37:41 Done.
293 }
294
295 var traceData = [];
296 for (var pointIndex = 0; pointIndex < revData[traceName].length;
297 ++pointIndex) {
298 traceData.push([parseFloat(revData[traceName][pointIndex][0]),
299 parseFloat(revData[traceName][pointIndex][1])]);
300 }
301
302 plotData.push(traceData);
303 dataDescriptions.push(traceName + ' [r' + revisionNum + ']');
304 return true
cmp 2012/08/27 02:42:01 append a semicolon
dennis_jeffrey 2012/08/27 23:37:41 Done.
305 }
306
307 /**
308 * Callback for when a *-summary.dat data file has been read.
309 *
310 * @param {string} data The string data from the inputted text file.
311 * @param {string} error A string error message, in case an error occurred
312 * during the file read.
313 */
314 function receivedSummary(data, error) {
315 if (error) {
316 reportError(error);
317 return;
318 }
319
320 var errorMessages = '';
321 var rows = new Rows(data);
322
323 // Build and order a list of revision numbers.
324 revisionNumbers = [];
325 for (var i = 0; i < rows.length; ++i) {
326 var row = rows.get(i);
327 if (!row)
328 continue;
329 revisionNumbers.push(row.revision);
330 }
331 revisionNumbers.sort(
332 function(a, b) { return parseInt(a, 10) - parseInt(b, 10) });
333
334 // Get the revision number to plot.
335 if (!('revision' in params) || params.revision == '') {
336 if (revisionNumbers.length >= 2 && 'lookout' in params) {
337 // Since the last graph (test run) might still be in progress, get the
338 // second-to-last graph to display on the summary page. That one
339 // is assumed to have finished running to completion.
340 params.revision = revisionNumbers[revisionNumbers.length-2];
341 } else {
342 if (revisionNumbers.length >= 1) {
343 params.revision = revisionNumbers[revisionNumbers.length-1];
344 } else {
345 reportError('No revision information to plot.');
346 return;
347 }
348 }
349 }
350
351 var plotData = []; // plotData is a list of graph lines; each graph line is
352 // a list of points; each point is a list of 2 values,
353 // representing the (x, y) pair.
354 var dataDescriptions = [];
355
356 if (!addToPlotData(params.revision, rows, plotData, dataDescriptions))
357 errorMessages += 'No data for the specified revision.<br>';
358
359 if ('revisionOther' in params) {
360 if (!addToPlotData(params.revisionOther, rows, plotData, dataDescriptions))
361 errorMessages += 'No data for the revision to compare against.<br>';
362 }
363
364 if ('graphOther' in params) {
365 if (addToPlotData(params.revision, graphDataOtherRows, plotData,
366 dataDescriptions)) {
367 for (var i = 0; i < graphList.length; ++i) {
368 if (graphList[i].name == params.graphOther) {
369 unitsYOther = graphList[i].units;
370 break;
371 }
372 }
373 } else {
374 errorMessages += 'No data for the measurement to compare against.<br>'
cmp 2012/08/27 02:42:01 append a semicolon
dennis_jeffrey 2012/08/27 23:37:41 Done.
375 }
376 }
377
378 // Identify the events for the current revision.
379 if (eventRows) {
380 for (var index = 0; index < eventRows.length; ++index) {
381 var info = eventRows.get(index);
382 if (params.revision == info['rev']) {
383 eventInfo = info;
384 break;
385 }
386 }
387 if (eventInfo != null) {
388 for (var key in eventInfo['events']) {
389 eventTypes.push(key);
390 }
391 }
392 }
393
394 // Get data for the events to display, if one was requested in the params.
395 var eventNameToPlot = null;
396 var eventInfoToPlot = null;
397 if ('event' in params && eventInfo != null) {
398 for (var key in eventInfo['events']) {
399 if (key == params['event']) {
400 eventInfoToPlot = eventInfo['events'][key];
401 eventNameToPlot = key;
402 }
403 }
404 }
405
406 // Draw everything.
407 if (errorMessages == '') {
408 var plotter = new Plotter(
409 plotData,
410 dataDescriptions,
411 eventNameToPlot, eventInfoToPlot,
412 unitsX, unitsY, unitsYOther,
413 document.getElementById('output'),
414 'lookout' in params);
415
416 plotter.plot();
417 } else {
418 errorMessages = '<br><br><br><table border=2 cellpadding=5><tr><td>' +
419 errorMessages + '</td></tr></table><br><br>';
420 document.getElementById('output').innerHTML = errorMessages;
421 }
422
423 if (!('lookout' in params)) {
424 initRevisionOptions();
425 initComparisonOptions();
426 }
427 }
428
429 /**
430 * Callback for when a second *-summary.dat data file has been read, in the
431 * event that a second graph line is being overlayed on top of an existing
432 * graph line.
433 *
434 * @param {string} data The string data from the inputted text file.
435 * @param {string} error A string error message, in case an error occurred
436 * during the file read.
437 */
438 function receivedSummaryGraphOther(data, error) {
439 if (error) {
440 reportError(error);
441 return;
442 }
443
444 graphDataOtherRows = new Rows(data);
445 Fetch(escape(params.graph) + '-summary.dat', receivedSummary);
446 }
447
448 /**
449 * Callback for when an event info file has been read.
450 *
451 * @param {string} data The string data from the inputted text file.
452 * @param {string} error A string error message, in case an error occurred
453 * during the file read.
454 */
455 function receivedEvents(data, error) {
456 if (!error)
457 eventRows = new Rows(data);
458 fetchSummary();
459 }
460
461 /**
462 * Callback for when a graphs.dat data file has been read.
463 *
464 * @param {string} data The string data from the inputted text file.
465 * @param {string} error A string error message, in case an error occurred
466 * during the file read.
467 */
468 function receivedGraphList(data, error) {
469 if (error) {
470 reportError(error);
471 return;
472 }
473 graphList = jsonToJs(data);
474
475 if (!('graph' in params) || params.graph == '')
476 if (graphList.length > 0)
477 params.graph = graphList[0].name
478
479 // Add a selection tab for each graph, and find the units for the selected
480 // one while we're at it.
481 tabs = [];
482 for (var index = 0; index < graphList.length; ++index) {
483 var graph = graphList[index];
484 tabs.push(graph.name);
485 if (graph.name == params.graph) {
486 unitsX = graph.units_x;
487 unitsY = graph.units;
488 }
489 }
490 initPlotSwitcher(tabs);
491
492 fetchEvents();
493 }
494
495 /**
496 * Starts fetching a *-summary.dat file.
497 */
498 function fetchSummary() {
499 if ('graphOther' in params) {
500 // We need to overlay a second graph over the first one, so we need to
501 // fetch that summary data too. Do it first.
502 Fetch(escape(params.graphOther) + '-summary.dat',
503 receivedSummaryGraphOther);
504 } else {
505 Fetch(escape(params.graph) + '-summary.dat',
506 receivedSummary);
507 }
508 }
509
510 /**
511 * Starts fetching an event info file.
512 */
513 function fetchEvents() {
514 Fetch('_EVENT_-summary.dat', receivedEvents);
515 }
516
517 /**
518 * Starts fetching a graphs.dat file.
519 */
520 function fetchGraphList() {
521 Fetch('graphs.dat', receivedGraphList);
522 }
523
524 window.addEventListener('load', fetchGraphList, false);
OLDNEW
« no previous file with comments | « chrome/test/functional/perf/endure_graphs/endure_plotter.html ('k') | chrome/test/functional/perf/endure_graphs/js/common.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698