OLD | NEW |
1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
2 <!-- | 2 <!-- |
3 Copyright 2016 The Chromium Authors. All rights reserved. | 3 Copyright 2016 The Chromium Authors. All rights reserved. |
4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
5 found in the LICENSE file. | 5 found in the LICENSE file. |
6 --> | 6 --> |
7 <link rel="import" href="/tracing/base/range.html"> | 7 <link rel="import" href="/tracing/base/range.html"> |
8 <link rel="import" href="/tracing/metrics/metric_registry.html"> | 8 <link rel="import" href="/tracing/metrics/metric_registry.html"> |
9 <link rel="import" href="/tracing/metrics/v8/utils.html"> | 9 <link rel="import" href="/tracing/metrics/v8/utils.html"> |
10 <link rel="import" href="/tracing/value/numeric.html"> | 10 <link rel="import" href="/tracing/value/numeric.html"> |
11 <link rel="import" href="/tracing/value/unit.html"> | 11 <link rel="import" href="/tracing/value/unit.html"> |
12 <link rel="import" href="/tracing/value/value.html"> | 12 <link rel="import" href="/tracing/value/value.html"> |
13 | 13 |
14 <script> | 14 <script> |
15 'use strict'; | 15 'use strict'; |
16 | 16 |
17 tr.exportTo('tr.metrics.v8', function() { | 17 tr.exportTo('tr.metrics.v8', function() { |
| 18 // The time window size for mutator utilization computation. |
| 19 // It is equal to the duration of one frame corresponding to 60 FPS rendering. |
| 20 var TARGET_FPS = 60; |
| 21 var MS_PER_SECOND = 1000; |
| 22 var WINDOW_SIZE_MS = MS_PER_SECOND / TARGET_FPS; |
| 23 |
18 function gcMetric(valueList, model) { | 24 function gcMetric(valueList, model) { |
19 addDurationOfTopEvents(valueList, model); | 25 addDurationOfTopEvents(valueList, model); |
20 addTotalDurationOfTopEvents(valueList, model); | 26 addTotalDurationOfTopEvents(valueList, model); |
21 addDurationOfSubEvents(valueList, model); | 27 addDurationOfSubEvents(valueList, model); |
22 addIdleTimesOfTopEvents(valueList, model); | 28 addIdleTimesOfTopEvents(valueList, model); |
23 addTotalIdleTimesOfTopEvents(valueList, model); | 29 addTotalIdleTimesOfTopEvents(valueList, model); |
| 30 addMutatorUtilization(valueList, model); |
24 } | 31 } |
25 | 32 |
26 gcMetric.prototype = { | 33 gcMetric.prototype = { |
27 __proto__: Function.prototype | 34 __proto__: Function.prototype |
28 }; | 35 }; |
29 | 36 |
30 tr.metrics.MetricRegistry.register(gcMetric); | 37 tr.metrics.MetricRegistry.register(gcMetric); |
31 | 38 |
32 var timeDurationInMs_smallerIsBetter = | 39 var timeDurationInMs_smallerIsBetter = |
33 tr.v.Unit.byName.timeDurationInMs_smallerIsBetter; | 40 tr.v.Unit.byName.timeDurationInMs_smallerIsBetter; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 var insideIdle = createNumeric(); | 159 var insideIdle = createNumeric(); |
153 var outsideIdle = createNumeric(); | 160 var outsideIdle = createNumeric(); |
154 var idleDeadlineOverrun = createNumeric(); | 161 var idleDeadlineOverrun = createNumeric(); |
155 events.forEach(function(event) { | 162 events.forEach(function(event) { |
156 var idleTask = tr.metrics.v8.utils.findParent( | 163 var idleTask = tr.metrics.v8.utils.findParent( |
157 event, tr.metrics.v8.utils.isIdleTask); | 164 event, tr.metrics.v8.utils.isIdleTask); |
158 var inside = 0; | 165 var inside = 0; |
159 var overrun = 0; | 166 var overrun = 0; |
160 if (idleTask) { | 167 if (idleTask) { |
161 var allottedTime = idleTask['args']['allotted_time_ms']; | 168 var allottedTime = idleTask['args']['allotted_time_ms']; |
162 console.log(allottedTime); | |
163 if (event.duration > allottedTime) { | 169 if (event.duration > allottedTime) { |
164 overrun = event.duration - allottedTime; | 170 overrun = event.duration - allottedTime; |
165 // Don't count time over the deadline as being inside idle time. | 171 // Don't count time over the deadline as being inside idle time. |
166 // Since the deadline should be relative to wall clock we | 172 // Since the deadline should be relative to wall clock we |
167 // compare allotted_time_ms with wall duration instead of thread | 173 // compare allotted_time_ms with wall duration instead of thread |
168 // duration, and then assume the thread duration was inside idle | 174 // duration, and then assume the thread duration was inside idle |
169 // for the same percentage of time. | 175 // for the same percentage of time. |
170 inside = event.cpuDuration * allottedTime / event.duration; | 176 inside = event.cpuDuration * allottedTime / event.duration; |
171 } else { | 177 } else { |
172 inside = event.cpuDuration; | 178 inside = event.cpuDuration; |
(...skipping 11 matching lines...) Expand all Loading... |
184 valueList.addValue( | 190 valueList.addValue( |
185 new tr.v.NumericValue(model.canonicalUrl, | 191 new tr.v.NumericValue(model.canonicalUrl, |
186 stageTitle + '-' + name + '_outside_idle', outsideIdle)); | 192 stageTitle + '-' + name + '_outside_idle', outsideIdle)); |
187 var percentage = createPercentage(insideIdle.runningSum, | 193 var percentage = createPercentage(insideIdle.runningSum, |
188 cpuDuration.runningSum); | 194 cpuDuration.runningSum); |
189 valueList.addValue( | 195 valueList.addValue( |
190 new tr.v.NumericValue(model.canonicalUrl, | 196 new tr.v.NumericValue(model.canonicalUrl, |
191 stageTitle + '-' + name + '_percentage_idle', percentage)); | 197 stageTitle + '-' + name + '_percentage_idle', percentage)); |
192 } | 198 } |
193 | 199 |
| 200 function addMutatorUtilization(valueList, model) { |
| 201 groupAndProcessEvents(model, |
| 202 tr.metrics.v8.utils.isTopV8ExecuteEvent, |
| 203 event => 'v8.execute', |
| 204 function(stageTitle, name, events) { |
| 205 events.sort((a, b) => a.start - b.start); |
| 206 var time = 0; |
| 207 var pauses = []; |
| 208 // Glue together the v8.execute events and adjust the GC pause |
| 209 // times accordingly. |
| 210 events.forEach(function(topEvent) { |
| 211 topEvent.findTopmostSlicesRelativeToThisSlice(function(e) { |
| 212 if (tr.metrics.v8.utils.isTopGarbageCollectionEvent(e)) { |
| 213 pauses.push({ start: e.start - topEvent.start + time, |
| 214 end: e.end - topEvent.start + time }); |
| 215 } |
| 216 }); |
| 217 time += topEvent.duration; |
| 218 }); |
| 219 // Now we have one big v8.execute interval from 0 to |time| and |
| 220 // a list of GC pauses. |
| 221 var mutatorUtilization = tr.metrics.v8.utils.mutatorUtilization( |
| 222 0, time, WINDOW_SIZE_MS, pauses); |
| 223 [0.95, 0.99].forEach(function(percent) { |
| 224 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, |
| 225 mutatorUtilization.percentile(1.0 - percent) * 100); |
| 226 valueList.addValue(new tr.v.NumericValue(model.canonicalUrl, |
| 227 stageTitle + '-mutator_utilization_pct_0' + percent * 100, |
| 228 value)); |
| 229 }); |
| 230 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, |
| 231 mutatorUtilization.min); |
| 232 valueList.addValue(new tr.v.NumericValue(model.canonicalUrl, |
| 233 stageTitle + '-mutator_utilization_min', value)); |
| 234 } |
| 235 ); |
| 236 } |
| 237 |
194 /** | 238 /** |
195 * Filters events using the |filterCallback|, then groups events by the user | 239 * Filters events using the |filterCallback|, then groups events by the user |
196 * expectation stage title and the name computed using the |nameCallback|, | 240 * expectation stage title and the name computed using the |nameCallback|, |
197 * and then invokes the |processCallback| with the grouped events. | 241 * and then invokes the |processCallback| with the grouped events. |
198 * @param {Function} filterCallback Takes an event and returns a boolean. | 242 * @param {Function} filterCallback Takes an event and returns a boolean. |
199 * @param {Function} nameCallback Takes event and returns a string. | 243 * @param {Function} nameCallback Takes event and returns a string. |
200 * @param {Function} processCallback Takes a stage title, a name, and | 244 * @param {Function} processCallback Takes a stage title, a name, and |
201 * an array of events. | 245 * an array of events. |
202 */ | 246 */ |
203 function groupAndProcessEvents(model, filterCallback, | 247 function groupAndProcessEvents(model, filterCallback, |
(...skipping 14 matching lines...) Expand all Loading... |
218 tr.b.iterItems(stageTitleToNameToEvents, | 262 tr.b.iterItems(stageTitleToNameToEvents, |
219 function(stageTitle, nameToEvents) { | 263 function(stageTitle, nameToEvents) { |
220 tr.b.iterItems(nameToEvents, function(name, events) { | 264 tr.b.iterItems(nameToEvents, function(name, events) { |
221 processCallback(stageTitle, name, events); | 265 processCallback(stageTitle, name, events); |
222 }); | 266 }); |
223 } | 267 } |
224 ); | 268 ); |
225 } | 269 } |
226 | 270 |
227 return { | 271 return { |
228 gcMetric: gcMetric | 272 gcMetric: gcMetric, |
| 273 WINDOW_SIZE_MS: WINDOW_SIZE_MS // For testing purposes only. |
229 }; | 274 }; |
230 }); | 275 }); |
231 </script> | 276 </script> |
OLD | NEW |