OLD | NEW |
| (Empty) |
1 // Copyright 2014 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef V8_GC_TRACER_H_ | |
6 #define V8_GC_TRACER_H_ | |
7 | |
8 namespace v8 { | |
9 namespace internal { | |
10 | |
11 // A simple ring buffer class with maximum size known at compile time. | |
12 // The class only implements the functionality required in GCTracer. | |
13 template <typename T, size_t MAX_SIZE> | |
14 class RingBuffer { | |
15 public: | |
16 class const_iterator { | |
17 public: | |
18 const_iterator() : index_(0), elements_(NULL) {} | |
19 | |
20 const_iterator(size_t index, const T* elements) | |
21 : index_(index), elements_(elements) {} | |
22 | |
23 bool operator==(const const_iterator& rhs) const { | |
24 return elements_ == rhs.elements_ && index_ == rhs.index_; | |
25 } | |
26 | |
27 bool operator!=(const const_iterator& rhs) const { | |
28 return elements_ != rhs.elements_ || index_ != rhs.index_; | |
29 } | |
30 | |
31 operator const T*() const { return elements_ + index_; } | |
32 | |
33 const T* operator->() const { return elements_ + index_; } | |
34 | |
35 const T& operator*() const { return elements_[index_]; } | |
36 | |
37 const_iterator& operator++() { | |
38 index_ = (index_ + 1) % (MAX_SIZE + 1); | |
39 return *this; | |
40 } | |
41 | |
42 const_iterator& operator--() { | |
43 index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1); | |
44 return *this; | |
45 } | |
46 | |
47 private: | |
48 size_t index_; | |
49 const T* elements_; | |
50 }; | |
51 | |
52 RingBuffer() : begin_(0), end_(0) {} | |
53 | |
54 bool empty() const { return begin_ == end_; } | |
55 size_t size() const { | |
56 return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1); | |
57 } | |
58 const_iterator begin() const { return const_iterator(begin_, elements_); } | |
59 const_iterator end() const { return const_iterator(end_, elements_); } | |
60 const_iterator back() const { return --end(); } | |
61 void push_back(const T& element) { | |
62 elements_[end_] = element; | |
63 end_ = (end_ + 1) % (MAX_SIZE + 1); | |
64 if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1); | |
65 } | |
66 void push_front(const T& element) { | |
67 begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1); | |
68 if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1); | |
69 elements_[begin_] = element; | |
70 } | |
71 | |
72 private: | |
73 T elements_[MAX_SIZE + 1]; | |
74 size_t begin_; | |
75 size_t end_; | |
76 | |
77 DISALLOW_COPY_AND_ASSIGN(RingBuffer); | |
78 }; | |
79 | |
80 | |
81 // GCTracer collects and prints ONE line after each garbage collector | |
82 // invocation IFF --trace_gc is used. | |
83 // TODO(ernstm): Unit tests. | |
84 class GCTracer BASE_EMBEDDED { | |
85 public: | |
86 class Scope BASE_EMBEDDED { | |
87 public: | |
88 enum ScopeId { | |
89 EXTERNAL, | |
90 MC_MARK, | |
91 MC_SWEEP, | |
92 MC_SWEEP_NEWSPACE, | |
93 MC_SWEEP_OLDSPACE, | |
94 MC_SWEEP_CODE, | |
95 MC_SWEEP_CELL, | |
96 MC_SWEEP_MAP, | |
97 MC_EVACUATE_PAGES, | |
98 MC_UPDATE_NEW_TO_NEW_POINTERS, | |
99 MC_UPDATE_ROOT_TO_NEW_POINTERS, | |
100 MC_UPDATE_OLD_TO_NEW_POINTERS, | |
101 MC_UPDATE_POINTERS_TO_EVACUATED, | |
102 MC_UPDATE_POINTERS_BETWEEN_EVACUATED, | |
103 MC_UPDATE_MISC_POINTERS, | |
104 MC_WEAKCOLLECTION_PROCESS, | |
105 MC_WEAKCOLLECTION_CLEAR, | |
106 MC_FLUSH_CODE, | |
107 NUMBER_OF_SCOPES | |
108 }; | |
109 | |
110 Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) { | |
111 start_time_ = base::OS::TimeCurrentMillis(); | |
112 } | |
113 | |
114 ~Scope() { | |
115 DCHECK(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned. | |
116 tracer_->current_.scopes[scope_] += | |
117 base::OS::TimeCurrentMillis() - start_time_; | |
118 } | |
119 | |
120 private: | |
121 GCTracer* tracer_; | |
122 ScopeId scope_; | |
123 double start_time_; | |
124 | |
125 DISALLOW_COPY_AND_ASSIGN(Scope); | |
126 }; | |
127 | |
128 | |
129 class Event { | |
130 public: | |
131 enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 }; | |
132 | |
133 // Default constructor leaves the event uninitialized. | |
134 Event() {} | |
135 | |
136 Event(Type type, const char* gc_reason, const char* collector_reason); | |
137 | |
138 // Returns a string describing the event type. | |
139 const char* TypeName(bool short_name) const; | |
140 | |
141 // Type of event | |
142 Type type; | |
143 | |
144 const char* gc_reason; | |
145 const char* collector_reason; | |
146 | |
147 // Timestamp set in the constructor. | |
148 double start_time; | |
149 | |
150 // Timestamp set in the destructor. | |
151 double end_time; | |
152 | |
153 // Size of objects in heap set in constructor. | |
154 intptr_t start_object_size; | |
155 | |
156 // Size of objects in heap set in destructor. | |
157 intptr_t end_object_size; | |
158 | |
159 // Size of memory allocated from OS set in constructor. | |
160 intptr_t start_memory_size; | |
161 | |
162 // Size of memory allocated from OS set in destructor. | |
163 intptr_t end_memory_size; | |
164 | |
165 // Total amount of space either wasted or contained in one of free lists | |
166 // before the current GC. | |
167 intptr_t start_holes_size; | |
168 | |
169 // Total amount of space either wasted or contained in one of free lists | |
170 // after the current GC. | |
171 intptr_t end_holes_size; | |
172 | |
173 // Number of incremental marking steps since creation of tracer. | |
174 // (value at start of event) | |
175 int cumulative_incremental_marking_steps; | |
176 | |
177 // Incremental marking steps since | |
178 // - last event for SCAVENGER events | |
179 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
180 int incremental_marking_steps; | |
181 | |
182 // Bytes marked since creation of tracer (value at start of event). | |
183 intptr_t cumulative_incremental_marking_bytes; | |
184 | |
185 // Bytes marked since | |
186 // - last event for SCAVENGER events | |
187 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
188 intptr_t incremental_marking_bytes; | |
189 | |
190 // Cumulative duration of incremental marking steps since creation of | |
191 // tracer. (value at start of event) | |
192 double cumulative_incremental_marking_duration; | |
193 | |
194 // Duration of incremental marking steps since | |
195 // - last event for SCAVENGER events | |
196 // - last MARK_COMPACTOR event for MARK_COMPACTOR events | |
197 double incremental_marking_duration; | |
198 | |
199 // Longest incremental marking step since start of marking. | |
200 // (value at start of event) | |
201 double longest_incremental_marking_step; | |
202 | |
203 // Amounts of time spent in different scopes during GC. | |
204 double scopes[Scope::NUMBER_OF_SCOPES]; | |
205 }; | |
206 | |
207 static const int kRingBufferMaxSize = 10; | |
208 | |
209 typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer; | |
210 | |
211 explicit GCTracer(Heap* heap); | |
212 | |
213 // Start collecting data. | |
214 void Start(GarbageCollector collector, const char* gc_reason, | |
215 const char* collector_reason); | |
216 | |
217 // Stop collecting data and print results. | |
218 void Stop(); | |
219 | |
220 // Log an incremental marking step. | |
221 void AddIncrementalMarkingStep(double duration, intptr_t bytes); | |
222 | |
223 // Log time spent in marking. | |
224 void AddMarkingTime(double duration) { | |
225 cumulative_marking_duration_ += duration; | |
226 } | |
227 | |
228 // Time spent in marking. | |
229 double cumulative_marking_duration() const { | |
230 return cumulative_marking_duration_; | |
231 } | |
232 | |
233 // Log time spent in sweeping on main thread. | |
234 void AddSweepingTime(double duration) { | |
235 cumulative_sweeping_duration_ += duration; | |
236 } | |
237 | |
238 // Time spent in sweeping on main thread. | |
239 double cumulative_sweeping_duration() const { | |
240 return cumulative_sweeping_duration_; | |
241 } | |
242 | |
243 // Compute the mean duration of the last scavenger events. Returns 0 if no | |
244 // events have been recorded. | |
245 double MeanScavengerDuration() const { | |
246 return MeanDuration(scavenger_events_); | |
247 } | |
248 | |
249 // Compute the max duration of the last scavenger events. Returns 0 if no | |
250 // events have been recorded. | |
251 double MaxScavengerDuration() const { return MaxDuration(scavenger_events_); } | |
252 | |
253 // Compute the mean duration of the last mark compactor events. Returns 0 if | |
254 // no events have been recorded. | |
255 double MeanMarkCompactorDuration() const { | |
256 return MeanDuration(mark_compactor_events_); | |
257 } | |
258 | |
259 // Compute the max duration of the last mark compactor events. Return 0 if no | |
260 // events have been recorded. | |
261 double MaxMarkCompactorDuration() const { | |
262 return MaxDuration(mark_compactor_events_); | |
263 } | |
264 | |
265 // Compute the mean step duration of the last incremental marking round. | |
266 // Returns 0 if no incremental marking round has been completed. | |
267 double MeanIncrementalMarkingDuration() const; | |
268 | |
269 // Compute the max step duration of the last incremental marking round. | |
270 // Returns 0 if no incremental marking round has been completed. | |
271 double MaxIncrementalMarkingDuration() const; | |
272 | |
273 // Compute the average incremental marking speed in bytes/second. Returns 0 if | |
274 // no events have been recorded. | |
275 intptr_t IncrementalMarkingSpeedInBytesPerMillisecond() const; | |
276 | |
277 private: | |
278 // Print one detailed trace line in name=value format. | |
279 // TODO(ernstm): Move to Heap. | |
280 void PrintNVP() const; | |
281 | |
282 // Print one trace line. | |
283 // TODO(ernstm): Move to Heap. | |
284 void Print() const; | |
285 | |
286 // Compute the mean duration of the events in the given ring buffer. | |
287 double MeanDuration(const EventBuffer& events) const; | |
288 | |
289 // Compute the max duration of the events in the given ring buffer. | |
290 double MaxDuration(const EventBuffer& events) const; | |
291 | |
292 // Pointer to the heap that owns this tracer. | |
293 Heap* heap_; | |
294 | |
295 // Current tracer event. Populated during Start/Stop cycle. Valid after Stop() | |
296 // has returned. | |
297 Event current_; | |
298 | |
299 // Previous tracer event. | |
300 Event previous_; | |
301 | |
302 // Previous MARK_COMPACTOR event. | |
303 Event previous_mark_compactor_event_; | |
304 | |
305 // RingBuffers for SCAVENGER events. | |
306 EventBuffer scavenger_events_; | |
307 | |
308 // RingBuffers for MARK_COMPACTOR events. | |
309 EventBuffer mark_compactor_events_; | |
310 | |
311 // Cumulative number of incremental marking steps since creation of tracer. | |
312 int cumulative_incremental_marking_steps_; | |
313 | |
314 // Cumulative size of incremental marking steps (in bytes) since creation of | |
315 // tracer. | |
316 intptr_t cumulative_incremental_marking_bytes_; | |
317 | |
318 // Cumulative duration of incremental marking steps since creation of tracer. | |
319 double cumulative_incremental_marking_duration_; | |
320 | |
321 // Longest incremental marking step since start of marking. | |
322 double longest_incremental_marking_step_; | |
323 | |
324 // Total marking time. | |
325 // This timer is precise when run with --print-cumulative-gc-stat | |
326 double cumulative_marking_duration_; | |
327 | |
328 // Total sweeping time on the main thread. | |
329 // This timer is precise when run with --print-cumulative-gc-stat | |
330 // TODO(hpayer): Account for sweeping time on sweeper threads. Add a | |
331 // different field for that. | |
332 // TODO(hpayer): This timer right now just holds the sweeping time | |
333 // of the initial atomic sweeping pause. Make sure that it accumulates | |
334 // all sweeping operations performed on the main thread. | |
335 double cumulative_sweeping_duration_; | |
336 | |
337 DISALLOW_COPY_AND_ASSIGN(GCTracer); | |
338 }; | |
339 } | |
340 } // namespace v8::internal | |
341 | |
342 #endif // V8_GC_TRACER_H_ | |
OLD | NEW |