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 #include "src/v8.h" | |
6 | |
7 #include "src/gc-tracer.h" | |
8 | |
9 namespace v8 { | |
10 namespace internal { | |
11 | |
12 static intptr_t CountTotalHolesSize(Heap* heap) { | |
13 intptr_t holes_size = 0; | |
14 OldSpaces spaces(heap); | |
15 for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) { | |
16 holes_size += space->Waste() + space->Available(); | |
17 } | |
18 return holes_size; | |
19 } | |
20 | |
21 | |
22 GCTracer::Event::Event(Type type, const char* gc_reason, | |
23 const char* collector_reason) | |
24 : type(type), | |
25 gc_reason(gc_reason), | |
26 collector_reason(collector_reason), | |
27 start_time(0.0), | |
28 end_time(0.0), | |
29 start_object_size(0), | |
30 end_object_size(0), | |
31 start_memory_size(0), | |
32 end_memory_size(0), | |
33 start_holes_size(0), | |
34 end_holes_size(0), | |
35 cumulative_incremental_marking_steps(0), | |
36 incremental_marking_steps(0), | |
37 cumulative_incremental_marking_bytes(0), | |
38 incremental_marking_bytes(0), | |
39 cumulative_incremental_marking_duration(0.0), | |
40 incremental_marking_duration(0.0), | |
41 longest_incremental_marking_step(0.0) { | |
42 for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) { | |
43 scopes[i] = 0; | |
44 } | |
45 } | |
46 | |
47 | |
48 const char* GCTracer::Event::TypeName(bool short_name) const { | |
49 switch (type) { | |
50 case SCAVENGER: | |
51 if (short_name) { | |
52 return "s"; | |
53 } else { | |
54 return "Scavenge"; | |
55 } | |
56 case MARK_COMPACTOR: | |
57 if (short_name) { | |
58 return "ms"; | |
59 } else { | |
60 return "Mark-sweep"; | |
61 } | |
62 case START: | |
63 if (short_name) { | |
64 return "st"; | |
65 } else { | |
66 return "Start"; | |
67 } | |
68 } | |
69 return "Unknown Event Type"; | |
70 } | |
71 | |
72 | |
73 GCTracer::GCTracer(Heap* heap) | |
74 : heap_(heap), | |
75 cumulative_incremental_marking_steps_(0), | |
76 cumulative_incremental_marking_bytes_(0), | |
77 cumulative_incremental_marking_duration_(0.0), | |
78 longest_incremental_marking_step_(0.0), | |
79 cumulative_marking_duration_(0.0), | |
80 cumulative_sweeping_duration_(0.0) { | |
81 current_ = Event(Event::START, NULL, NULL); | |
82 current_.end_time = base::OS::TimeCurrentMillis(); | |
83 previous_ = previous_mark_compactor_event_ = current_; | |
84 } | |
85 | |
86 | |
87 void GCTracer::Start(GarbageCollector collector, const char* gc_reason, | |
88 const char* collector_reason) { | |
89 previous_ = current_; | |
90 if (current_.type == Event::MARK_COMPACTOR) | |
91 previous_mark_compactor_event_ = current_; | |
92 | |
93 if (collector == SCAVENGER) { | |
94 current_ = Event(Event::SCAVENGER, gc_reason, collector_reason); | |
95 } else { | |
96 current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason); | |
97 } | |
98 | |
99 current_.start_time = base::OS::TimeCurrentMillis(); | |
100 current_.start_object_size = heap_->SizeOfObjects(); | |
101 current_.start_memory_size = heap_->isolate()->memory_allocator()->Size(); | |
102 current_.start_holes_size = CountTotalHolesSize(heap_); | |
103 | |
104 current_.cumulative_incremental_marking_steps = | |
105 cumulative_incremental_marking_steps_; | |
106 current_.cumulative_incremental_marking_bytes = | |
107 cumulative_incremental_marking_bytes_; | |
108 current_.cumulative_incremental_marking_duration = | |
109 cumulative_incremental_marking_duration_; | |
110 current_.longest_incremental_marking_step = longest_incremental_marking_step_; | |
111 | |
112 for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) { | |
113 current_.scopes[i] = 0; | |
114 } | |
115 } | |
116 | |
117 | |
118 void GCTracer::Stop() { | |
119 current_.end_time = base::OS::TimeCurrentMillis(); | |
120 current_.end_object_size = heap_->SizeOfObjects(); | |
121 current_.end_memory_size = heap_->isolate()->memory_allocator()->Size(); | |
122 current_.end_holes_size = CountTotalHolesSize(heap_); | |
123 | |
124 if (current_.type == Event::SCAVENGER) { | |
125 current_.incremental_marking_steps = | |
126 current_.cumulative_incremental_marking_steps - | |
127 previous_.cumulative_incremental_marking_steps; | |
128 current_.incremental_marking_bytes = | |
129 current_.cumulative_incremental_marking_bytes - | |
130 previous_.cumulative_incremental_marking_bytes; | |
131 current_.incremental_marking_duration = | |
132 current_.cumulative_incremental_marking_duration - | |
133 previous_.cumulative_incremental_marking_duration; | |
134 scavenger_events_.push_front(current_); | |
135 } else { | |
136 current_.incremental_marking_steps = | |
137 current_.cumulative_incremental_marking_steps - | |
138 previous_mark_compactor_event_.cumulative_incremental_marking_steps; | |
139 current_.incremental_marking_bytes = | |
140 current_.cumulative_incremental_marking_bytes - | |
141 previous_mark_compactor_event_.cumulative_incremental_marking_bytes; | |
142 current_.incremental_marking_duration = | |
143 current_.cumulative_incremental_marking_duration - | |
144 previous_mark_compactor_event_.cumulative_incremental_marking_duration; | |
145 longest_incremental_marking_step_ = 0.0; | |
146 mark_compactor_events_.push_front(current_); | |
147 } | |
148 | |
149 // TODO(ernstm): move the code below out of GCTracer. | |
150 | |
151 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; | |
152 | |
153 double duration = current_.end_time - current_.start_time; | |
154 double spent_in_mutator = Max(current_.start_time - previous_.end_time, 0.0); | |
155 | |
156 heap_->UpdateCumulativeGCStatistics(duration, spent_in_mutator, | |
157 current_.scopes[Scope::MC_MARK]); | |
158 | |
159 if (current_.type == Event::SCAVENGER && FLAG_trace_gc_ignore_scavenger) | |
160 return; | |
161 | |
162 if (FLAG_trace_gc) { | |
163 if (FLAG_trace_gc_nvp) | |
164 PrintNVP(); | |
165 else | |
166 Print(); | |
167 | |
168 heap_->PrintShortHeapStatistics(); | |
169 } | |
170 } | |
171 | |
172 | |
173 void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) { | |
174 cumulative_incremental_marking_steps_++; | |
175 cumulative_incremental_marking_bytes_ += bytes; | |
176 cumulative_incremental_marking_duration_ += duration; | |
177 longest_incremental_marking_step_ = | |
178 Max(longest_incremental_marking_step_, duration); | |
179 cumulative_marking_duration_ += duration; | |
180 } | |
181 | |
182 | |
183 void GCTracer::Print() const { | |
184 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init()); | |
185 | |
186 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", current_.TypeName(false), | |
187 static_cast<double>(current_.start_object_size) / MB, | |
188 static_cast<double>(current_.start_memory_size) / MB, | |
189 static_cast<double>(current_.end_object_size) / MB, | |
190 static_cast<double>(current_.end_memory_size) / MB); | |
191 | |
192 int external_time = static_cast<int>(current_.scopes[Scope::EXTERNAL]); | |
193 if (external_time > 0) PrintF("%d / ", external_time); | |
194 | |
195 double duration = current_.end_time - current_.start_time; | |
196 PrintF("%.1f ms", duration); | |
197 if (current_.type == Event::SCAVENGER) { | |
198 if (current_.incremental_marking_steps > 0) { | |
199 PrintF(" (+ %.1f ms in %d steps since last GC)", | |
200 current_.incremental_marking_duration, | |
201 current_.incremental_marking_steps); | |
202 } | |
203 } else { | |
204 if (current_.incremental_marking_steps > 0) { | |
205 PrintF( | |
206 " (+ %.1f ms in %d steps since start of marking, " | |
207 "biggest step %.1f ms)", | |
208 current_.incremental_marking_duration, | |
209 current_.incremental_marking_steps, | |
210 current_.longest_incremental_marking_step); | |
211 } | |
212 } | |
213 | |
214 if (current_.gc_reason != NULL) { | |
215 PrintF(" [%s]", current_.gc_reason); | |
216 } | |
217 | |
218 if (current_.collector_reason != NULL) { | |
219 PrintF(" [%s]", current_.collector_reason); | |
220 } | |
221 | |
222 PrintF(".\n"); | |
223 } | |
224 | |
225 | |
226 void GCTracer::PrintNVP() const { | |
227 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init()); | |
228 | |
229 double duration = current_.end_time - current_.start_time; | |
230 double spent_in_mutator = current_.start_time - previous_.end_time; | |
231 | |
232 PrintF("pause=%.1f ", duration); | |
233 PrintF("mutator=%.1f ", spent_in_mutator); | |
234 PrintF("gc=%s ", current_.TypeName(true)); | |
235 | |
236 PrintF("external=%.1f ", current_.scopes[Scope::EXTERNAL]); | |
237 PrintF("mark=%.1f ", current_.scopes[Scope::MC_MARK]); | |
238 PrintF("sweep=%.2f ", current_.scopes[Scope::MC_SWEEP]); | |
239 PrintF("sweepns=%.2f ", current_.scopes[Scope::MC_SWEEP_NEWSPACE]); | |
240 PrintF("sweepos=%.2f ", current_.scopes[Scope::MC_SWEEP_OLDSPACE]); | |
241 PrintF("sweepcode=%.2f ", current_.scopes[Scope::MC_SWEEP_CODE]); | |
242 PrintF("sweepcell=%.2f ", current_.scopes[Scope::MC_SWEEP_CELL]); | |
243 PrintF("sweepmap=%.2f ", current_.scopes[Scope::MC_SWEEP_MAP]); | |
244 PrintF("evacuate=%.1f ", current_.scopes[Scope::MC_EVACUATE_PAGES]); | |
245 PrintF("new_new=%.1f ", | |
246 current_.scopes[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]); | |
247 PrintF("root_new=%.1f ", | |
248 current_.scopes[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]); | |
249 PrintF("old_new=%.1f ", | |
250 current_.scopes[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]); | |
251 PrintF("compaction_ptrs=%.1f ", | |
252 current_.scopes[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]); | |
253 PrintF("intracompaction_ptrs=%.1f ", | |
254 current_.scopes[Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]); | |
255 PrintF("misc_compaction=%.1f ", | |
256 current_.scopes[Scope::MC_UPDATE_MISC_POINTERS]); | |
257 PrintF("weakcollection_process=%.1f ", | |
258 current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]); | |
259 PrintF("weakcollection_clear=%.1f ", | |
260 current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]); | |
261 | |
262 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", current_.start_object_size); | |
263 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", current_.end_object_size); | |
264 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", current_.start_holes_size); | |
265 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", current_.end_holes_size); | |
266 | |
267 intptr_t allocated_since_last_gc = | |
268 current_.start_object_size - previous_.end_object_size; | |
269 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc); | |
270 PrintF("promoted=%" V8_PTR_PREFIX "d ", heap_->promoted_objects_size_); | |
271 PrintF("semi_space_copied=%" V8_PTR_PREFIX "d ", | |
272 heap_->semi_space_copied_object_size_); | |
273 PrintF("nodes_died_in_new=%d ", heap_->nodes_died_in_new_space_); | |
274 PrintF("nodes_copied_in_new=%d ", heap_->nodes_copied_in_new_space_); | |
275 PrintF("nodes_promoted=%d ", heap_->nodes_promoted_); | |
276 PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_); | |
277 PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_); | |
278 | |
279 if (current_.type == Event::SCAVENGER) { | |
280 PrintF("steps_count=%d ", current_.incremental_marking_steps); | |
281 PrintF("steps_took=%.1f ", current_.incremental_marking_duration); | |
282 } else { | |
283 PrintF("steps_count=%d ", current_.incremental_marking_steps); | |
284 PrintF("steps_took=%.1f ", current_.incremental_marking_duration); | |
285 PrintF("longest_step=%.1f ", current_.longest_incremental_marking_step); | |
286 PrintF("incremental_marking_throughput=%" V8_PTR_PREFIX "d ", | |
287 IncrementalMarkingSpeedInBytesPerMillisecond()); | |
288 } | |
289 | |
290 PrintF("\n"); | |
291 } | |
292 | |
293 | |
294 double GCTracer::MeanDuration(const EventBuffer& events) const { | |
295 if (events.empty()) return 0.0; | |
296 | |
297 double mean = 0.0; | |
298 EventBuffer::const_iterator iter = events.begin(); | |
299 while (iter != events.end()) { | |
300 mean += iter->end_time - iter->start_time; | |
301 ++iter; | |
302 } | |
303 | |
304 return mean / events.size(); | |
305 } | |
306 | |
307 | |
308 double GCTracer::MaxDuration(const EventBuffer& events) const { | |
309 if (events.empty()) return 0.0; | |
310 | |
311 double maximum = 0.0f; | |
312 EventBuffer::const_iterator iter = events.begin(); | |
313 while (iter != events.end()) { | |
314 maximum = Max(iter->end_time - iter->start_time, maximum); | |
315 ++iter; | |
316 } | |
317 | |
318 return maximum; | |
319 } | |
320 | |
321 | |
322 double GCTracer::MeanIncrementalMarkingDuration() const { | |
323 if (cumulative_incremental_marking_steps_ == 0) return 0.0; | |
324 | |
325 // We haven't completed an entire round of incremental marking, yet. | |
326 // Use data from GCTracer instead of data from event buffers. | |
327 if (mark_compactor_events_.empty()) { | |
328 return cumulative_incremental_marking_duration_ / | |
329 cumulative_incremental_marking_steps_; | |
330 } | |
331 | |
332 int steps = 0; | |
333 double durations = 0.0; | |
334 EventBuffer::const_iterator iter = mark_compactor_events_.begin(); | |
335 while (iter != mark_compactor_events_.end()) { | |
336 steps += iter->incremental_marking_steps; | |
337 durations += iter->incremental_marking_duration; | |
338 ++iter; | |
339 } | |
340 | |
341 if (steps == 0) return 0.0; | |
342 | |
343 return durations / steps; | |
344 } | |
345 | |
346 | |
347 double GCTracer::MaxIncrementalMarkingDuration() const { | |
348 // We haven't completed an entire round of incremental marking, yet. | |
349 // Use data from GCTracer instead of data from event buffers. | |
350 if (mark_compactor_events_.empty()) return longest_incremental_marking_step_; | |
351 | |
352 double max_duration = 0.0; | |
353 EventBuffer::const_iterator iter = mark_compactor_events_.begin(); | |
354 while (iter != mark_compactor_events_.end()) | |
355 max_duration = Max(iter->longest_incremental_marking_step, max_duration); | |
356 | |
357 return max_duration; | |
358 } | |
359 | |
360 | |
361 intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const { | |
362 if (cumulative_incremental_marking_duration_ == 0.0) return 0; | |
363 | |
364 // We haven't completed an entire round of incremental marking, yet. | |
365 // Use data from GCTracer instead of data from event buffers. | |
366 if (mark_compactor_events_.empty()) { | |
367 return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ / | |
368 cumulative_incremental_marking_duration_); | |
369 } | |
370 | |
371 intptr_t bytes = 0; | |
372 double durations = 0.0; | |
373 EventBuffer::const_iterator iter = mark_compactor_events_.begin(); | |
374 while (iter != mark_compactor_events_.end()) { | |
375 bytes += iter->incremental_marking_bytes; | |
376 durations += iter->incremental_marking_duration; | |
377 ++iter; | |
378 } | |
379 | |
380 if (durations == 0.0) return 0; | |
381 | |
382 return static_cast<intptr_t>(bytes / durations); | |
383 } | |
384 } | |
385 } // namespace v8::internal | |
OLD | NEW |