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/piecewise_linear_function.html"> | |
7 <link rel="import" href="/tracing/base/range.html"> | 8 <link rel="import" href="/tracing/base/range.html"> |
9 <link rel="import" href="/tracing/base/range_utils.html"> | |
8 <link rel="import" href="/tracing/metrics/metric_registry.html"> | 10 <link rel="import" href="/tracing/metrics/metric_registry.html"> |
9 <link rel="import" href="/tracing/value/numeric.html"> | 11 <link rel="import" href="/tracing/value/numeric.html"> |
10 <link rel="import" href="/tracing/value/unit.html"> | 12 <link rel="import" href="/tracing/value/unit.html"> |
11 <link rel="import" href="/tracing/value/value.html"> | 13 <link rel="import" href="/tracing/value/value.html"> |
12 | 14 |
13 <script> | 15 <script> |
14 'use strict'; | 16 'use strict'; |
15 | 17 |
16 tr.exportTo('tr.metrics.v8.utils', function() { | 18 tr.exportTo('tr.metrics.v8.utils', function() { |
17 // The title of the idle task event. | 19 // The title of the idle task event. |
18 var IDLE_TASK_EVENT = 'SingleThreadIdleTaskRunner::RunTask'; | 20 var IDLE_TASK_EVENT = 'SingleThreadIdleTaskRunner::RunTask'; |
19 | 21 |
22 // V8 execution event. | |
23 var V8_EXECUTE = 'V8.Execute'; | |
24 | |
20 // GC events start with this prefix. | 25 // GC events start with this prefix. |
21 var GC_EVENT_PREFIX = 'V8.GC'; | 26 var GC_EVENT_PREFIX = 'V8.GC'; |
22 | 27 |
23 // Special handling is required for full GCs inside low memory notification. | 28 // Special handling is required for full GCs inside low memory notification. |
24 var FULL_GC_EVENT = 'V8.GCCompactor'; | 29 var FULL_GC_EVENT = 'V8.GCCompactor'; |
25 | 30 |
26 var LOW_MEMORY_EVENT = 'V8.GCLowMemoryNotification'; | 31 var LOW_MEMORY_EVENT = 'V8.GCLowMemoryNotification'; |
27 | 32 |
28 // Maps the top-level GC events in timeline to telemetry friendly names. | 33 // Maps the top-level GC events in timeline to telemetry friendly names. |
29 var TOP_GC_EVENTS = { | 34 var TOP_GC_EVENTS = { |
30 'V8.GCCompactor': 'v8.gc.full_mark_compactor', | 35 'V8.GCCompactor': 'v8.gc.full_mark_compactor', |
31 'V8.GCFinalizeMC': 'v8.gc.latency_mark_compactor', | 36 'V8.GCFinalizeMC': 'v8.gc.latency_mark_compactor', |
32 'V8.GCFinalizeMCReduceMemory': 'v8.gc.memory_mark_compactor', | 37 'V8.GCFinalizeMCReduceMemory': 'v8.gc.memory_mark_compactor', |
33 'V8.GCIncrementalMarking': 'v8.gc.incremental_step', | 38 'V8.GCIncrementalMarking': 'v8.gc.incremental_step', |
34 'V8.GCIncrementalMarkingFinalize': 'v8.gc.incremental_finalize', | 39 'V8.GCIncrementalMarkingFinalize': 'v8.gc.incremental_finalize', |
35 'V8.GCIncrementalMarkingStart': 'v8.gc.incremental_start', | 40 'V8.GCIncrementalMarkingStart': 'v8.gc.incremental_start', |
36 'V8.GCLowMemoryNotification': 'v8.gc.low_memory_mark_compactor', | 41 'V8.GCLowMemoryNotification': 'v8.gc.low_memory_mark_compactor', |
37 'V8.GCScavenger': 'v8.gc.scavenger' | 42 'V8.GCScavenger': 'v8.gc.scavenger' |
38 }; | 43 }; |
39 | 44 |
40 /** | 45 /** |
41 * Finds the first parent of the |event| for which the |predicate| holds. | 46 * Finds the first parent of the |event| for which the |predicate| holds. |
42 */ | 47 */ |
43 function findParent(event, predicate) { | 48 function findParent(event, predicate) { |
44 var parent = event.parentSlice; | 49 var parent = event.parentSlice; |
45 while (parent) { | 50 while (parent) { |
46 if (predicate(parent)) { | 51 if (predicate(parent)) { |
47 return parent; | 52 return parent; |
48 } | 53 } |
49 parent = parent.parentSlice; | 54 parent = parent.parentSlice; |
50 } | 55 } |
51 return null; | 56 return null; |
52 } | 57 } |
53 | 58 |
54 function isIdleTask(event) { | 59 function isIdleTask(event) { |
55 return event.title === IDLE_TASK_EVENT; | 60 return event.title === IDLE_TASK_EVENT; |
56 } | 61 } |
57 | 62 |
58 function isLowMemoryEvent(event) { | 63 function isLowMemoryEvent(event) { |
59 return event.title === LOW_MEMORY_EVENT; | 64 return event.title === LOW_MEMORY_EVENT; |
60 } | 65 } |
61 | 66 |
67 function isV8ExecuteEvent(event) { | |
68 return event.title === V8_EXECUTE; | |
69 } | |
70 | |
71 function isTopV8ExecuteEvent(event) { | |
72 return isV8ExecuteEvent(event) && findParent(isV8ExecuteEvent) === null; | |
73 } | |
74 | |
62 function isGarbageCollectionEvent(event) { | 75 function isGarbageCollectionEvent(event) { |
63 // Low memory notification is handled specially because it contains | 76 // Low memory notification is handled specially because it contains |
64 // several full mark compact events. | 77 // several full mark compact events. |
65 return event.title && event.title.startsWith(GC_EVENT_PREFIX) && | 78 return event.title && event.title.startsWith(GC_EVENT_PREFIX) && |
66 event.title != LOW_MEMORY_EVENT; | 79 event.title != LOW_MEMORY_EVENT; |
67 } | 80 } |
68 | 81 |
69 function isTopGarbageCollectionEvent(event) { | 82 function isTopGarbageCollectionEvent(event) { |
70 return event.title in TOP_GC_EVENTS; | 83 return event.title in TOP_GC_EVENTS; |
71 } | 84 } |
(...skipping 17 matching lines...) Expand all Loading... | |
89 function subGarbageCollectionEventName(event) { | 102 function subGarbageCollectionEventName(event) { |
90 var topEvent = findParent(event, isTopGarbageCollectionEvent); | 103 var topEvent = findParent(event, isTopGarbageCollectionEvent); |
91 var prefix = topEvent ? topGarbageCollectionEventName(topEvent) : 'unknown'; | 104 var prefix = topEvent ? topGarbageCollectionEventName(topEvent) : 'unknown'; |
92 // Remove redundant prefixes and convert to lower case. | 105 // Remove redundant prefixes and convert to lower case. |
93 var name = event.title.replace('V8.GC_MC_', '') | 106 var name = event.title.replace('V8.GC_MC_', '') |
94 .replace('V8.GC_SCAVENGER_', '') | 107 .replace('V8.GC_SCAVENGER_', '') |
95 .replace('V8.GC_', '').toLowerCase(); | 108 .replace('V8.GC_', '').toLowerCase(); |
96 return prefix + '.' + name; | 109 return prefix + '.' + name; |
97 } | 110 } |
98 | 111 |
112 /** | |
113 * Given a list of intervals, returns a new list with all overalapping | |
114 * intervals merged into a single interval. | |
115 */ | |
116 function unionOfIntervals(intervals) { | |
117 if (intervals.length === 0) | |
118 return []; | |
119 return tr.b.mergeRanges( | |
120 intervals.map(x => ({min: x.start, max: x.end})), 1e-6, | |
121 function(ranges) { | |
122 return { | |
123 start: ranges.reduce((acc, x) => Math.min(acc, x.min), ranges[0].min), | |
124 end: ranges.reduce((acc, x) => Math.max(acc, x.max), ranges[0].max) | |
125 }; | |
126 } | |
127 ); | |
128 } | |
129 | |
130 /** | |
131 * An end-point of a window that is sliding from left to right | |
132 * over the |points| in the time interval defined by the |start| and |end|. | |
petrcermak
2016/04/22 11:40:02
nit: s/the |points|/|points|/ and s/the |start|/|s
ulan
2016/04/22 12:32:27
Done.
| |
133 * It is intended to be used only by the |mutatorUtilization| function. | |
134 * @constructor | |
135 */ | |
136 function WindowEndpoint(start, end, points) { | |
petrcermak
2016/04/22 11:40:01
Why do you pass in |end| when you don't use it???
ulan
2016/04/22 12:32:27
Leftover, removed.
| |
137 this.points = points; | |
138 // The index of the last passed point. | |
139 this.index = -1; | |
petrcermak
2016/04/22 11:40:01
lastIndex?
ulan
2016/04/22 12:32:27
Done.
| |
140 // The position of the limit. | |
petrcermak
2016/04/22 11:40:02
limit of what?
ulan
2016/04/22 12:32:27
Fixed the comment.
| |
141 this.position = start; | |
petrcermak
2016/04/22 11:40:02
limitPosition?
ulan
2016/04/22 12:32:27
I removed limit from the comment.
| |
142 // The distance until the next point. | |
143 this.remainder = points[0].position - start; | |
petrcermak
2016/04/22 11:40:02
distanceUntilNextPoint?
ulan
2016/04/22 12:32:27
Done.
| |
144 // The cumulative duration of GC pauses until this position. | |
145 this.pause = 0; | |
petrcermak
2016/04/22 11:40:02
cumulativePause?
ulan
2016/04/22 12:32:27
Done.
| |
146 // The number of entered GC intervals. | |
147 this.stack = 0; | |
petrcermak
2016/04/22 11:40:02
stackDepth?
ulan
2016/04/22 12:32:27
Done.
| |
148 }; | |
149 | |
150 WindowEndpoint.prototype = { | |
151 // Advance the end-point by the given |delta|. | |
152 advance: function(delta) { | |
153 var points = this.points; | |
154 if (delta < this.remainder) { | |
155 this.position += delta; | |
156 this.pause += this.stack > 0 ? delta : 0; | |
157 this.remainder = points[this.index + 1].position - this.position; | |
158 } else { | |
159 this.position += this.remainder; | |
160 this.pause += this.stack > 0 ? this.remainder : 0; | |
161 this.remainder = 0; | |
162 this.index += 1; | |
petrcermak
2016/04/22 11:40:02
this.index++
ulan
2016/04/22 12:32:27
Done.
| |
163 if (this.index < points.length) { | |
164 this.stack += points[this.index].delta; | |
165 if (this.index + 1 < points.length) | |
166 this.remainder = points[this.index + 1].position - this.position; | |
167 } | |
168 } | |
169 } | |
170 }; | |
171 | |
172 /** | |
173 * Returns mutator utilization as a piecewise linear function. | |
174 * Mutator utilization for a window size w is a function of time mu_w(t) | |
175 * that shows how much time in [t, t+w] is left for the mutator. | |
176 * More formally: | |
177 * mu_w(t) = (w - total_time_spent_in_gc_in(t, t + w)) / w. | |
178 * See "A Parallel, Real-Time Garbage Collector" by Cheng et. al. for | |
179 * more info [https://www.cs.cmu.edu/~guyb/papers/gc2001.pdf]. | |
180 * | |
181 * @param {number} start The start time of execution. | |
182 * @param {number} end The end time of execution. | |
183 * @param {number} timeWindow The size of the time window. | |
184 * @param {!Array<!{start: number, end: number}>} intervals The list of | |
185 * GC pauses. | |
186 */ | |
187 function mutatorUtilization(start, end, timeWindow, intervals) { | |
188 var mu = new tr.b.PiecewiseLinearFunction(); | |
189 // If the interval is smaller than the time windows, then the function is | |
petrcermak
2016/04/22 11:40:02
nit: s/windows/window/
ulan
2016/04/22 12:32:27
Done.
| |
190 // empty. | |
191 if (end - start <= timeWindow) | |
192 return mu; | |
193 // If there are GC pauses then the mutator utilization is 1.0. | |
194 if (intervals.length === 0) { | |
195 mu.push(start, 1.0, end - timeWindow, 1.0); | |
196 return mu; | |
197 } | |
198 intervals = unionOfIntervals(intervals); | |
199 // Create a point for the start and the end of each interval. | |
200 var points = []; | |
201 intervals.forEach(function(interval) { | |
202 points.push({position: interval.start, delta: 1}); | |
203 points.push({position: interval.end, delta: -1}); | |
204 }); | |
205 points.sort((a, b) => a.position - b.position); | |
206 points.push({position: end, delta: 0}); | |
207 // The left and the right limit of the sliding window. | |
208 var left = new WindowEndpoint(start, end, points); | |
209 var right = new WindowEndpoint(start, end, points); | |
210 // Advance the right end-point until we get the correct window size. | |
211 while (right.position - left.position < timeWindow) | |
212 right.advance(timeWindow - (right.position - left.position)); | |
213 while (right.index < points.length) { | |
214 // Advance the window end-points by the largest possible amount | |
215 // without jumping over a point. | |
216 var remainder = Math.min(left.remainder, right.remainder); | |
217 var position1 = left.position; | |
218 var value1 = right.pause - left.pause; | |
219 left.advance(remainder); | |
220 right.advance(remainder); | |
221 // Add a new mutator utilization segment only if it is non-trivial. | |
222 if (remainder > 0) { | |
223 var position2 = left.position; | |
224 var value2 = right.pause - left.pause; | |
225 mu.push(position1, 1.0 - value1 / timeWindow, | |
226 position2, 1.0 - value2 / timeWindow); | |
227 } | |
228 } | |
229 return mu; | |
230 } | |
231 | |
99 return { | 232 return { |
100 findParent: findParent, | 233 findParent: findParent, |
101 isIdleTask: isIdleTask, | 234 isIdleTask: isIdleTask, |
102 isLowMemoryEvent: isLowMemoryEvent, | 235 isLowMemoryEvent: isLowMemoryEvent, |
236 isV8ExecuteEvent: isV8ExecuteEvent, | |
237 isTopV8ExecuteEvent: isTopV8ExecuteEvent, | |
103 isGarbageCollectionEvent: isGarbageCollectionEvent, | 238 isGarbageCollectionEvent: isGarbageCollectionEvent, |
104 isTopGarbageCollectionEvent: isTopGarbageCollectionEvent, | 239 isTopGarbageCollectionEvent: isTopGarbageCollectionEvent, |
105 isSubGarbageCollectionEvent: isSubGarbageCollectionEvent, | 240 isSubGarbageCollectionEvent: isSubGarbageCollectionEvent, |
106 topGarbageCollectionEventName: topGarbageCollectionEventName, | 241 topGarbageCollectionEventName: topGarbageCollectionEventName, |
107 subGarbageCollectionEventName: subGarbageCollectionEventName | 242 subGarbageCollectionEventName: subGarbageCollectionEventName, |
243 unionOfIntervals: unionOfIntervals, | |
244 mutatorUtilization: mutatorUtilization | |
108 }; | 245 }; |
109 }); | 246 }); |
110 </script> | 247 </script> |
OLD | NEW |