| 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"> |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 percentile: [] | 83 percentile: [] |
| 84 }); | 84 }); |
| 85 return n; | 85 return n; |
| 86 } | 86 } |
| 87 | 87 |
| 88 function createPercentage(numerator, denominator) { | 88 function createPercentage(numerator, denominator) { |
| 89 var percentage = denominator === 0 ? 0 : numerator / denominator * 100; | 89 var percentage = denominator === 0 ? 0 : numerator / denominator * 100; |
| 90 return new tr.v.ScalarNumeric(percentage_biggerIsBetter, percentage); | 90 return new tr.v.ScalarNumeric(percentage_biggerIsBetter, percentage); |
| 91 } | 91 } |
| 92 | 92 |
| 93 function isNotForcedTopGarbageCollectionEvent(event) { |
| 94 // We exclude garbage collection events forced by benchmark runner, |
| 95 // because they cannot happen in real world. |
| 96 return tr.metrics.v8.utils.isTopGarbageCollectionEvent(event) && |
| 97 !tr.metrics.v8.utils.isForcedGarbageCollectionEvent(event); |
| 98 } |
| 99 |
| 100 function isNotForcedSubGarbageCollectionEvent(event) { |
| 101 // We exclude garbage collection events forced by benchmark runner, |
| 102 // because they cannot happen in real world. |
| 103 return tr.metrics.v8.utils.isSubGarbageCollectionEvent(event) && |
| 104 !tr.metrics.v8.utils.isForcedGarbageCollectionEvent(event); |
| 105 } |
| 106 |
| 93 /** | 107 /** |
| 94 * Example output: | 108 * Example output: |
| 95 * - Animation-v8_gc_full_mark_compactor. | 109 * - v8-gc-full-mark-compactor. |
| 96 */ | 110 */ |
| 97 function addDurationOfTopEvents(values, model) { | 111 function addDurationOfTopEvents(values, model) { |
| 98 groupAndProcessEvents(model, | 112 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 99 tr.metrics.v8.utils.isTopGarbageCollectionEvent, | 113 isNotForcedTopGarbageCollectionEvent, |
| 100 tr.metrics.v8.utils.topGarbageCollectionEventName, | 114 tr.metrics.v8.utils.topGarbageCollectionEventName, |
| 101 function(stageTitle, name, events) { | 115 function(name, events) { |
| 102 var cpuDuration = createNumericForTopEventTime(); | 116 var cpuDuration = createNumericForTopEventTime(); |
| 103 events.forEach(function(event) { | 117 events.forEach(function(event) { |
| 104 cpuDuration.add(event.cpuDuration); | 118 cpuDuration.add(event.cpuDuration); |
| 105 }); | 119 }); |
| 106 values.addValue(new tr.v.NumericValue( | 120 values.addValue(new tr.v.NumericValue(name, cpuDuration)); |
| 107 stageTitle + '-' + name, cpuDuration)); | |
| 108 } | 121 } |
| 109 ); | 122 ); |
| 110 } | 123 } |
| 111 | 124 |
| 112 /** | 125 /** |
| 113 * Example output: | 126 * Example output: |
| 114 * - Animation:v8_gc_total | 127 * - v8-gc-total |
| 115 */ | 128 */ |
| 116 function addTotalDurationOfTopEvents(values, model) { | 129 function addTotalDurationOfTopEvents(values, model) { |
| 117 groupAndProcessEvents(model, | 130 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 118 tr.metrics.v8.utils.isTopGarbageCollectionEvent, | 131 isNotForcedTopGarbageCollectionEvent, |
| 119 event => 'v8-gc-total', | 132 event => 'v8-gc-total', |
| 120 function(stageTitle, name, events) { | 133 function(name, events) { |
| 121 var cpuDuration = createNumericForTopEventTime(); | 134 var cpuDuration = createNumericForTopEventTime(); |
| 122 events.forEach(function(event) { | 135 events.forEach(function(event) { |
| 123 cpuDuration.add(event.cpuDuration); | 136 cpuDuration.add(event.cpuDuration); |
| 124 }); | 137 }); |
| 125 values.addValue(new tr.v.NumericValue( | 138 values.addValue(new tr.v.NumericValue(name, cpuDuration)); |
| 126 stageTitle + '-' + name, cpuDuration)); | |
| 127 } | 139 } |
| 128 ); | 140 ); |
| 129 } | 141 } |
| 130 | 142 |
| 131 /** | 143 /** |
| 132 * Example output: | 144 * Example output: |
| 133 * - Animation-v8-gc-full-mark-compactor-evacuate. | 145 * - v8-gc-full-mark-compactor-evacuate. |
| 134 */ | 146 */ |
| 135 function addDurationOfSubEvents(values, model) { | 147 function addDurationOfSubEvents(values, model) { |
| 136 groupAndProcessEvents(model, | 148 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 137 tr.metrics.v8.utils.isSubGarbageCollectionEvent, | 149 isNotForcedSubGarbageCollectionEvent, |
| 138 tr.metrics.v8.utils.subGarbageCollectionEventName, | 150 tr.metrics.v8.utils.subGarbageCollectionEventName, |
| 139 function(stageTitle, name, events) { | 151 function(name, events) { |
| 140 var cpuDuration = createNumericForSubEventTime(); | 152 var cpuDuration = createNumericForSubEventTime(); |
| 141 events.forEach(function(event) { | 153 events.forEach(function(event) { |
| 142 cpuDuration.add(event.cpuDuration); | 154 cpuDuration.add(event.cpuDuration); |
| 143 }); | 155 }); |
| 144 values.addValue(new tr.v.NumericValue( | 156 values.addValue(new tr.v.NumericValue(name, cpuDuration)); |
| 145 stageTitle + '-' + name, cpuDuration)); | |
| 146 } | 157 } |
| 147 ); | 158 ); |
| 148 } | 159 } |
| 149 | 160 |
| 150 /** | 161 /** |
| 151 * Example output: | 162 * Example output: |
| 152 * - Animation-v8-gc-full-mark-compactor_idle_deadline_overrun, | 163 * - v8-gc-full-mark-compactor_idle_deadline_overrun, |
| 153 * - Animation-v8-gc-full-mark-compactor_outside_idle, | 164 * - v8-gc-full-mark-compactor_outside_idle, |
| 154 * - Animation-v8-gc-full-mark-compactor_percentage_idle. | 165 * - v8-gc-full-mark-compactor_percentage_idle. |
| 155 */ | 166 */ |
| 156 function addIdleTimesOfTopEvents(values, model) { | 167 function addIdleTimesOfTopEvents(values, model) { |
| 157 groupAndProcessEvents(model, | 168 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 158 tr.metrics.v8.utils.isTopGarbageCollectionEvent, | 169 isNotForcedTopGarbageCollectionEvent, |
| 159 tr.metrics.v8.utils.topGarbageCollectionEventName, | 170 tr.metrics.v8.utils.topGarbageCollectionEventName, |
| 160 function(stageTitle, name, events) { | 171 function(name, events) { |
| 161 addIdleTimes(values, model, stageTitle, name, events); | 172 addIdleTimes(values, model, name, events); |
| 162 } | 173 } |
| 163 ); | 174 ); |
| 164 } | 175 } |
| 165 | 176 |
| 166 /** | 177 /** |
| 167 * Example output: | 178 * Example output: |
| 168 * - Animation-v8-gc-total_idle_deadline_overrun, | 179 * - v8-gc-total_idle_deadline_overrun, |
| 169 * - Animation-v8-gc-total_outside_idle, | 180 * - v8-gc-total_outside_idle, |
| 170 * - Animation-v8-gc-total_percentage_idle. | 181 * - v8-gc-total_percentage_idle. |
| 171 */ | 182 */ |
| 172 function addTotalIdleTimesOfTopEvents(values, model) { | 183 function addTotalIdleTimesOfTopEvents(values, model) { |
| 173 groupAndProcessEvents(model, | 184 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 174 tr.metrics.v8.utils.isTopGarbageCollectionEvent, | 185 isNotForcedTopGarbageCollectionEvent, |
| 175 event => 'v8-gc-total', | 186 event => 'v8-gc-total', |
| 176 function(stageTitle, name, events) { | 187 function(name, events) { |
| 177 addIdleTimes(values, model, stageTitle, name, events); | 188 addIdleTimes(values, model, name, events); |
| 178 } | 189 } |
| 179 ); | 190 ); |
| 180 } | 191 } |
| 181 | 192 |
| 182 function addIdleTimes(values, model, stageTitle, name, events) { | 193 function addIdleTimes(values, model, name, events) { |
| 183 var cpuDuration = createNumericForIdleTime(); | 194 var cpuDuration = createNumericForIdleTime(); |
| 184 var insideIdle = createNumericForIdleTime(); | 195 var insideIdle = createNumericForIdleTime(); |
| 185 var outsideIdle = createNumericForIdleTime(); | 196 var outsideIdle = createNumericForIdleTime(); |
| 186 var idleDeadlineOverrun = createNumericForIdleTime(); | 197 var idleDeadlineOverrun = createNumericForIdleTime(); |
| 187 events.forEach(function(event) { | 198 events.forEach(function(event) { |
| 188 var idleTask = tr.metrics.v8.utils.findParent( | 199 var idleTask = tr.metrics.v8.utils.findParent( |
| 189 event, tr.metrics.v8.utils.isIdleTask); | 200 event, tr.metrics.v8.utils.isIdleTask); |
| 190 var inside = 0; | 201 var inside = 0; |
| 191 var overrun = 0; | 202 var overrun = 0; |
| 192 if (idleTask) { | 203 if (idleTask) { |
| 193 var allottedTime = idleTask['args']['allotted_time_ms']; | 204 var allottedTime = idleTask['args']['allotted_time_ms']; |
| 194 if (event.duration > allottedTime) { | 205 if (event.duration > allottedTime) { |
| 195 overrun = event.duration - allottedTime; | 206 overrun = event.duration - allottedTime; |
| 196 // Don't count time over the deadline as being inside idle time. | 207 // Don't count time over the deadline as being inside idle time. |
| 197 // Since the deadline should be relative to wall clock we | 208 // Since the deadline should be relative to wall clock we |
| 198 // compare allotted_time_ms with wall duration instead of thread | 209 // compare allotted_time_ms with wall duration instead of thread |
| 199 // duration, and then assume the thread duration was inside idle | 210 // duration, and then assume the thread duration was inside idle |
| 200 // for the same percentage of time. | 211 // for the same percentage of time. |
| 201 inside = event.cpuDuration * allottedTime / event.duration; | 212 inside = event.cpuDuration * allottedTime / event.duration; |
| 202 } else { | 213 } else { |
| 203 inside = event.cpuDuration; | 214 inside = event.cpuDuration; |
| 204 } | 215 } |
| 205 } | 216 } |
| 206 cpuDuration.add(event.cpuDuration); | 217 cpuDuration.add(event.cpuDuration); |
| 207 insideIdle.add(inside); | 218 insideIdle.add(inside); |
| 208 outsideIdle.add(event.cpuDuration - inside); | 219 outsideIdle.add(event.cpuDuration - inside); |
| 209 idleDeadlineOverrun.add(overrun); | 220 idleDeadlineOverrun.add(overrun); |
| 210 }); | 221 }); |
| 211 values.addValue(new tr.v.NumericValue( | 222 values.addValue(new tr.v.NumericValue( |
| 212 stageTitle + '-' + name + '_idle_deadline_overrun', | 223 name + '_idle_deadline_overrun', |
| 213 idleDeadlineOverrun)); | 224 idleDeadlineOverrun)); |
| 214 values.addValue(new tr.v.NumericValue( | 225 values.addValue(new tr.v.NumericValue( |
| 215 stageTitle + '-' + name + '_outside_idle', outsideIdle)); | 226 name + '_outside_idle', outsideIdle)); |
| 216 var percentage = createPercentage(insideIdle.sum, | 227 var percentage = createPercentage(insideIdle.sum, |
| 217 cpuDuration.sum); | 228 cpuDuration.sum); |
| 218 values.addValue(new tr.v.NumericValue( | 229 values.addValue(new tr.v.NumericValue( |
| 219 stageTitle + '-' + name + '_percentage_idle', percentage)); | 230 name + '_percentage_idle', percentage)); |
| 220 } | 231 } |
| 221 | 232 |
| 222 function addV8ExecuteMutatorUtilization(values, model) { | 233 function addV8ExecuteMutatorUtilization(values, model) { |
| 223 groupAndProcessEvents(model, | 234 tr.metrics.v8.utils.groupAndProcessEvents(model, |
| 224 tr.metrics.v8.utils.isTopV8ExecuteEvent, | 235 tr.metrics.v8.utils.isTopV8ExecuteEvent, |
| 225 event => 'v8-execute', | 236 event => 'v8-execute', |
| 226 function(stageTitle, name, events) { | 237 function(name, events) { |
| 227 events.sort((a, b) => a.start - b.start); | 238 events.sort((a, b) => a.start - b.start); |
| 228 var time = 0; | 239 var time = 0; |
| 229 var pauses = []; | 240 var pauses = []; |
| 230 // Glue together the v8.execute events and adjust the GC pause | 241 // Glue together the v8.execute events and adjust the GC pause |
| 231 // times accordingly. | 242 // times accordingly. |
| 232 events.forEach(function(topEvent) { | 243 for (var topEvent of events) { |
| 233 topEvent.iterateAllDescendents(function(e) { | 244 for (var e of topEvent.enumerateAllDescendents()) { |
| 234 if (tr.metrics.v8.utils.isTopGarbageCollectionEvent(e)) { | 245 if (isNotForcedTopGarbageCollectionEvent(e)) { |
| 235 pauses.push({ start: e.start - topEvent.start + time, | 246 pauses.push({ start: e.start - topEvent.start + time, |
| 236 end: e.end - topEvent.start + time }); | 247 end: e.end - topEvent.start + time }); |
| 237 } | 248 } |
| 238 }); | 249 } |
| 239 time += topEvent.duration; | 250 time += topEvent.duration; |
| 240 }); | 251 } |
| 241 // Now we have one big v8.execute interval from 0 to |time| and | 252 // Now we have one big v8.execute interval from 0 to |time| and |
| 242 // a list of GC pauses. | 253 // a list of GC pauses. |
| 243 var mutatorUtilization = tr.metrics.v8.utils.mutatorUtilization( | 254 var mutatorUtilization = tr.metrics.v8.utils.mutatorUtilization( |
| 244 0, time, WINDOW_SIZE_MS, pauses); | 255 0, time, WINDOW_SIZE_MS, pauses); |
| 245 [0.90, 0.95, 0.99].forEach(function(percent) { | 256 [0.90, 0.95, 0.99].forEach(function(percent) { |
| 246 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, | 257 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, |
| 247 mutatorUtilization.percentile(1.0 - percent) * 100); | 258 mutatorUtilization.percentile(1.0 - percent) * 100); |
| 248 values.addValue(new tr.v.NumericValue( | 259 values.addValue(new tr.v.NumericValue( |
| 249 stageTitle + '-v8-execute-mutator-utilization_pct_0' + | 260 'v8-execute-mutator-utilization_pct_0' + |
| 250 percent * 100, | 261 percent * 100, |
| 251 value)); | 262 value)); |
| 252 }); | 263 }); |
| 253 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, | 264 var value = new tr.v.ScalarNumeric(percentage_biggerIsBetter, |
| 254 mutatorUtilization.min); | 265 mutatorUtilization.min); |
| 255 values.addValue(new tr.v.NumericValue( | 266 values.addValue(new tr.v.NumericValue( |
| 256 stageTitle + '-v8-execute-mutator-utilization_min', value)); | 267 'v8-execute-mutator-utilization_min', value)); |
| 257 } | 268 } |
| 258 ); | 269 ); |
| 259 } | 270 } |
| 260 | 271 |
| 261 /** | |
| 262 * Filters events using the |filterCallback|, then groups events by the user | |
| 263 * expectation stage title and the name computed using the |nameCallback|, | |
| 264 * and then invokes the |processCallback| with the grouped events. | |
| 265 * @param {Function} filterCallback Takes an event and returns a boolean. | |
| 266 * @param {Function} nameCallback Takes event and returns a string. | |
| 267 * @param {Function} processCallback Takes a stage title, a name, and | |
| 268 * an array of events. | |
| 269 */ | |
| 270 function groupAndProcessEvents(model, filterCallback, | |
| 271 nameCallback, processCallback) { | |
| 272 // Two level map: stageTitle -> name -> [events]. | |
| 273 var stageTitleToNameToEvents = {}; | |
| 274 model.userModel.expectations.forEach(function(ue) { | |
| 275 stageTitleToNameToEvents[ue.stageTitle] = | |
| 276 stageTitleToNameToEvents[ue.stageTitle] || {}; | |
| 277 var nameToEvents = stageTitleToNameToEvents[ue.stageTitle]; | |
| 278 ue.associatedEvents.forEach(function(event) { | |
| 279 if (!filterCallback(event)) return; | |
| 280 var name = nameCallback(event); | |
| 281 nameToEvents[name] = nameToEvents[name] || []; | |
| 282 nameToEvents[name].push(event); | |
| 283 }); | |
| 284 }); | |
| 285 tr.b.iterItems(stageTitleToNameToEvents, | |
| 286 function(stageTitle, nameToEvents) { | |
| 287 tr.b.iterItems(nameToEvents, function(name, events) { | |
| 288 processCallback(stageTitle, name, events); | |
| 289 }); | |
| 290 } | |
| 291 ); | |
| 292 } | |
| 293 | |
| 294 return { | 272 return { |
| 295 gcMetric: gcMetric, | 273 gcMetric: gcMetric, |
| 296 WINDOW_SIZE_MS: WINDOW_SIZE_MS // For testing purposes only. | 274 WINDOW_SIZE_MS: WINDOW_SIZE_MS // For testing purposes only. |
| 297 }; | 275 }; |
| 298 }); | 276 }); |
| 299 </script> | 277 </script> |
| OLD | NEW |