Changeset 194130 in webkit
- Timestamp:
- Dec 15, 2015 9:19:08 PM (8 years ago)
- Location:
- trunk/Websites/perf.webkit.org
- Files:
-
- 48 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Websites/perf.webkit.org/ChangeLog
r194121 r194130 1 2015-12-15 Ryosuke Niwa <rniwa@webkit.org> 2 3 Add v3 UI to perf dashboard 4 https://bugs.webkit.org/show_bug.cgi?id=152311 5 6 Reviewed by Chris Dumez. 7 8 Add the third iteration of the perf dashboard UI. UI for viewing and modifying analysis tasks is coming soon. 9 The v3 UI is focused on speed, and removes all third-party script dependencies including jQuery, d3, and Ember. 10 Both the DOM-based UI and graphing are implemented manually. 11 12 13 The entire app is structured using new component library implemented in components/base.js. Each component is 14 an instance of a subclass of ComponentBase which owns a single DOM element. Each subclass may supply static 15 methods named htmlTemplate and cssTemplate as the template for a component instance. ComponentBase automatically 16 clones the templates inside the associated element (or its shadow root on the supported browsers). Each subclass 17 must supply a method called "render()" which constructs and updates the DOM as needed. 18 19 There is a special component called Page, which represents an entire page. Each Page is opened by PageRouter's 20 "route()" function. Each subclass of Page supplies "open()" for initialization and "updateFromSerializedState()" 21 for a hash URL transition. 22 23 24 The key feature of the v3 UI is the split of time series into chunks called clusters (see r194120). On an internal 25 instance of the dashboard, the v2 UI downloads 27MB of data whereas the same page loads only 3MB of data in the v3. 26 The key logic for fetching time series in chunks is implemented by MeasurementSet in /v3/models/measurement-set.js. 27 We first fetch the cached primary cluster (the cluster that contains the newest data) at: 28 /data/measurement-set-<platform-id>-<metric-id>.json 29 30 If that's outdated according to lastModified in manifest.json, then we immediately re-fetch the primary cluster at: 31 /api/measurement-set/?platform=<platform-id>&metric=<metric-id> 32 33 Once the up-to-date primary cluster is fetched, we fetch all "secondary" clusters. For each cluster being fetched, 34 including the primary, we invoke registered callbacks. 35 36 37 In addition, the v3 UI reduces the initial page load time by loading a single bundled JS file generated by 38 tools/bundle-v3-scripts.py. index.html has a fallback to load all 44 JS files individually during development. 39 40 * public/api/analysis-tasks.php: 41 (fetch_and_push_bugs_to_tasks): Added the code to fetch start and end run times. This is necessary in V3 UI 42 because no longer fetch the entire time series. See r194120 for the new measurement set JSON API. 43 (format_task): Compute the category of an analysis task based on "result" value. This will be re-vamped once 44 I add the UI for the analysis task page in v3. 45 46 * public/include/json-header.php: 47 (require_format): CamelCase the name. 48 (require_match_one_of_values): Ditto. 49 (validate_arguments): Renamed from require_existence_of and used in measurement-set.php landed in r194120. 50 51 * public/v3: Added. 52 * public/v3/components: Added. 53 54 * public/v3/components/base.js: Added. 55 (ComponentBase): The base component class. 56 (ComponentBase.prototype.element): Returns the DOM element associated with the DOM element. 57 (ComponentBase.prototype.content): Returns the shadow root if one exists and the associated element otherwise. 58 (ComponentBase.prototype.render): To be implemented by a subclass. 59 (ComponentBase.prototype.renderReplace): A helper function to "render" DOM contents. 60 (ComponentBase.prototype._constructShadowTree): Called inside the constructor to instantiate the templates. 61 (ComponentBase.prototype._recursivelyReplaceUnknownElementsByComponents): Instantiates components referred by 62 its element name inside the instantiated content. 63 (ComponentBase.isElementInViewport): A helper function. Returns true if the element is in the viewport and it has 64 non-zero width and height. 65 (ComponentBase.defineElement): Defines a custom element that can be automatically instantiated from htmlTemplate. 66 (ComponentBase.createElement): A helper function to create DOM tree to be used in "render()" method. 67 (ComponentBase._addContentToElement): A helper for "createElement". 68 (ComponentBase.createLink): A helper function to create a hyperlink or another clickable element (via callback). 69 (ComponentBase.createActionHandler): A helper function to create an event listener that prevents the default action 70 and stops the event propagation. 71 72 * public/v3/components/button-base.js: Added. 73 74 * public/v3/components/chart-status-view.js: Added. 75 (ChartStatusView): A component that reports the current status of time-series-chart. It's subclasses by 76 ChartPaneStatusView to provide additional information in the charts page's panes. 77 78 * public/v3/components/close-button.js: Added. 79 (CloseButton): 80 * public/v3/components/commit-log-viewer.js: Added. 81 (CommitLogViewer): A component that lists commit revisions along with commit messages for a range of data points. 82 83 * public/v3/components/interactive-time-series-chart.js: Added. 84 (InteractiveTimeSeriesChart): A subclass of InteractiveTimeSeriesChart with interactivity (selection & indicator). 85 Selection and indicator are mutually exclusive. 86 87 * public/v3/components/pane-selector.js: Added. 88 (PaneSelector): A component for selecting (platform, metric) pair to add in the charts page. 89 90 * public/v3/components/spinner-icon.js: Added. 91 92 * public/v3/components/time-series-chart.js: Added. 93 (TimeSeriesChart): A canvas-based chart component without interactivity. It takes a source list and options as 94 the constructor arguments. A source list is a list of measurement sets (measurement-set.js) with drawing options. 95 This component fetches data via MeasurementSet.fetchBetween inside TimeSeriesChart.prototype.setDomain and 96 progressively updates the charts as more data arrives. The canvas is updated on animation frame via rAF and all 97 layout and rendering metrics are lazily computed in _layout. In addition, this component samples data before 98 rendering the chart when there are more data points per pixel in _ensureSampledTimeSeries. 99 100 * public/v3/index.html: Added. Loads bundled-scripts.js if it exists, or individual script files otherwise. 101 102 * public/v3/instrumentation.js: Added. This class is used to gather runtime statistics of v3 UI. (It measures 103 the performance of the perf dashboard UI). 104 105 * public/v3/main.js: Added. Bootstraps the app. 106 (main): 107 (fetchManifest): 108 109 * public/v3/models: Added. 110 * public/v3/models/analysis-task.js: Added. 111 * public/v3/models/bug-tracker.js: Added. 112 * public/v3/models/bug.js: Added. 113 * public/v3/models/builder.js: Added. 114 * public/v3/models/commit-log.js: Added. 115 * public/v3/models/data-model.js: Added. 116 (DataModelObject): The base class for various data objects that correspond to database tables. It supplies static 117 hash map to find entries by id as well as other keys. 118 (LabeledObject): A subclass of DataModelObject with the capability to find an object via its name. 119 120 * public/v3/models/measurement-cluster.js: Added. 121 (MeasurementCluster): Represents a single cluster or a chunk of data in a measurement set. 122 123 * public/v3/models/measurement-set.js: Added. 124 (MeasurementSet): Represents a measurement set. 125 (MeasurementSet.findSet): Returns the singleton set given (metric, platform). We use singleton to avoid issuing 126 multiple HTTP requests for the same JSON when there are multiple TimeSeriesChart that show the same graph (e.g. on 127 charts page with overview and main charts). 128 (MeasurementSet.prototype.findClusters): Finds the list of clusters to fetch in a given time range. 129 (MeasurementSet.prototype.fetchBetween): Fetch clusters for a given time range and calls callback whenever new data 130 arrives. The number of callbacks depends on the how many clusters need to be newly fetched. 131 (MeasurementSet.prototype._fetchSecondaryClusters): Fetches non-primary (non-latest) clusters. 132 (MeasurementSet.prototype._fetch): Issues a HTTP request to fetch a cluster. 133 (MeasurementSet.prototype._didFetchJSON): Called when a cluster is fetched. 134 (MeasurementSet.prototype._failedToFetchJSON): Called when the fetching of a cluster has failed. 135 (MeasurementSet.prototype._invokeCallbacks): Invokes callbacks upon an approval of a new cluster. 136 (MeasurementSet.prototype._addFetchedCluster): Adds the newly fetched cluster in the order. 137 (MeasurementSet.prototype.fetchedTimeSeries): Returns a time series that contains data from all clusters that have 138 been fetched. 139 (TimeSeries.prototype.findById): Additions to TimeSeries defined in /v2/data.js. 140 (TimeSeries.prototype.dataBetweenPoints): Ditto. 141 (TimeSeries.prototype.firstPoint): Ditto. 142 143 * public/v3/models/metric.js: Added. 144 * public/v3/models/platform.js: Added. 145 * public/v3/models/repository.js: Added. 146 * public/v3/models/test.js: Added. 147 148 * public/v3/pages: Added. 149 * public/v3/pages/analysis-category-page.js: Added. The "Analysis" page that lists the analysis tasks. 150 * public/v3/pages/analysis-category-toolbar.js: Added. The toolbar to filter analysis tasks based on its category 151 (unconfirmed, bisecting, identified, closed) and a keyword. 152 153 * public/v3/pages/analysis-task-page.js: Added. Not implemented yet. It just has the hyperlink to the v2 UI. 154 155 * public/v3/pages/chart-pane-status-view.js: Added. 156 (ChartPaneStatusView): A subclass of ChartStatusView used in the charts page. In addition to the current value, 157 comparison to baseline/target, it shows the list of repository revisions (e.g. WebKit revision, OS version). 158 159 * public/v3/pages/chart-pane.js: Added. 160 (ChartPane): A component a pane in the charts page. Each pane has the overview chart and the main chart. The zooming 161 is synced across all panes in the charts page. 162 163 * public/v3/pages/charts-page.js: Added. Charts page. 164 * public/v3/pages/charts-toolbar.js: Added. The toolbar to set the number of days to show. This affects the overview 165 chart's domain in each pane. 166 167 * public/v3/pages/create-analysis-task-page.js: Added. 168 (CreateAnalysisTaskPage): A page that gets shown momentarily while creating a new analysis task. 169 170 * public/v3/pages/dashboard-page.js: Added. A dashboard page. 171 * public/v3/pages/dashboard-toolbar.js: Added. Its toolbar with buttons to select the number of days to show. 172 * public/v3/pages/domain-control-toolbar.js: Added. An abstract superclass of charts and dashboard toolbars. 173 174 * public/v3/pages/heading.js: Added. A component for displaying the header and toolbar, if exists, on each page. 175 * public/v3/pages/page-router.js: Added. This class is responsible for updating the URL hashes as well as opening 176 and updating each page when the hash changes (via back/forward navigation). 177 * public/v3/pages/page-with-charts.js: Added. An abstract subclass of page used by dashboards and charts page. 178 Supplies helper functions for creating TimeSeriesChart options. 179 * public/v3/pages/page-with-heading.js: Added. An abstract subclass of page that uses the heading component. 180 * public/v3/pages/page.js: Added. The Page component. 181 * public/v3/pages/toolbar.js: Added. An abstract toolbar component. 182 183 * public/v3/remote.js: Added. 184 (getJSON): Fetches JSON from the remote server. 185 (getJSONWithStatus): Ditto. Rejects the response if the status is not "OK". 186 (PrivilegedAPI.sendRequest): Posts a HTTP request to a privileged API in /privileged-api/. 187 (PrivilegedAPI.requestCSRFToken): Creates a new CSRF token to request a privileged API post. 188 189 * tools/bundle-v3-scripts.py: Added. 190 (main): Bundles js files together and minifies them by jsmin.py for the v3 UI. Without this script, we're forced to 191 download 44 JS files or making each JS file contain multiple classes. 192 193 * tools/jsmin.py: Copied from WebInspector / JavaScriptCore code. 194 1 195 2015-12-15 Ryosuke Niwa <rniwa@webkit.org> 2 196 -
trunk/Websites/perf.webkit.org/public/api/analysis-tasks.php
r183232 r194130 11 11 exit_with_error('InvalidRequest'); 12 12 13 if (count($path) > 0 && $path[0]) { 14 $task_id = intval($path[0]); 13 $task_id = count($path) > 0 && $path[0] ? $path[0] : array_get($_GET, 'id'); 14 15 if ($task_id) { 16 $task_id = intval($task_id); 15 17 $task = $db->select_first_row('analysis_tasks', 'task', array('id' => $task_id)); 16 18 if (!$task) … … 74 76 } 75 77 78 $run_ids = array(); 79 $task_by_run = array(); 80 foreach ($tasks as &$task) { 81 if ($task['startRun']) { 82 array_push($run_ids, $task['startRun']); 83 $task_by_run[$task['startRun']] = &$task; 84 } 85 if ($task['endRun']) { 86 array_push($run_ids, $task['endRun']); 87 $task_by_run[$task['endRun']] = &$task; 88 } 89 } 90 91 // FIXME: This query is quite expensive. We may need to store this directly in analysis_tasks table instead. 92 $build_revision_times = $db->query_and_fetch_all('SELECT run_id, build_time, max(commit_time) AS revision_time 93 FROM builds 94 LEFT OUTER JOIN build_commits ON commit_build = build_id 95 LEFT OUTER JOIN commits ON build_commit = commit_id, test_runs 96 WHERE run_build = build_id AND run_id = ANY($1) GROUP BY build_id, run_id', 97 array('{' . implode(', ', $run_ids) . '}')); 98 foreach ($build_revision_times as &$row) { 99 $time = $row['revision_time'] or $row['build_time']; 100 $id = $row['run_id']; 101 if ($task_by_run[$id]['startRun'] == $id) 102 $task_by_run[$id]['startRunTime'] = Database::to_js_time($time); 103 if ($task_by_run[$id]['endRun'] == $id) 104 $task_by_run[$id]['endRunTime'] = Database::to_js_time($time); 105 } 106 76 107 return $bugs; 77 108 } … … 89 120 'startRun' => $task_row['task_start_run'], 90 121 'endRun' => $task_row['task_end_run'], 122 'category' => $task_row['task_result'] ? 'bisecting' : 'unconfirmed', 91 123 'result' => $task_row['task_result'], 92 124 'needed' => $task_row['task_needed'] ? Database::is_true($task_row['task_needed']) : null, -
trunk/Websites/perf.webkit.org/public/include/json-header.php
r183237 r194130 54 54 function require_format($name, $value, $pattern) { 55 55 if (!preg_match($pattern, $value)) 56 exit_with_error('Invalid' . $name, array('value' => $value));56 exit_with_error('Invalid' . camel_case_words_separated_by_underscore($name), array('value' => $value)); 57 57 } 58 58 59 59 function require_match_one_of_values($name, $value, $valid_values) { 60 60 if (!in_array($value, $valid_values)) 61 exit_with_error('Invalid' . $name, array('value' => $value)); 61 exit_with_error('Invalid' . camel_case_words_separated_by_underscore($name), array('value' => $value)); 62 } 63 64 function validate_arguments($array, $list_of_arguments) { 65 $result = array(); 66 foreach ($list_of_arguments as $name => $pattern) { 67 $value = array_get($array, $name, ''); 68 if ($pattern == 'int') { 69 require_format($name, $value, '/^\d+$/'); 70 $value = intval($value); 71 } else if ($pattern == 'int?') { 72 require_format($name, $value, '/^\d*$/'); 73 $value = $value ? intval($value) : null; 74 } else 75 require_format($name, $value, $pattern); 76 $result[$name] = $value; 77 } 78 return $result; 62 79 } 63 80
Note: See TracChangeset
for help on using the changeset viewer.