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 |