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 incremental_marking_steps(0), |
| 36 incremental_marking_duration(0.0) { |
| 37 for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) { |
| 38 scopes[i] = 0; |
| 39 } |
| 40 } |
| 41 |
| 42 |
| 43 const char* GCTracer::Event::TypeName(bool short_name) const { |
| 44 switch (type) { |
| 45 case SCAVENGER: |
| 46 if (short_name) { |
| 47 return "s"; |
| 48 } else { |
| 49 return "Scavenge"; |
| 50 } |
| 51 case MARK_COMPACTOR: |
| 52 if (short_name) { |
| 53 return "ms"; |
| 54 } else { |
| 55 return "Mark-sweep"; |
| 56 } |
| 57 case START: |
| 58 if (short_name) { |
| 59 return "st"; |
| 60 } else { |
| 61 return "Start"; |
| 62 } |
| 63 } |
| 64 return "Unknown Event Type"; |
| 65 } |
| 66 |
| 67 |
| 68 GCTracer::GCTracer(Heap* heap) |
| 69 : heap_(heap), |
| 70 incremental_marking_steps_(0), |
| 71 incremental_marking_duration_(0.0), |
| 72 longest_incremental_marking_step_(0.0) { |
| 73 current_ = Event(Event::START, NULL, NULL); |
| 74 current_.end_time = base::OS::TimeCurrentMillis(); |
| 75 previous_ = previous_mark_compactor_event_ = current_; |
| 76 } |
| 77 |
| 78 |
| 79 void GCTracer::Start(GarbageCollector collector, const char* gc_reason, |
| 80 const char* collector_reason) { |
| 81 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 82 |
| 83 previous_ = current_; |
| 84 if (current_.type == Event::MARK_COMPACTOR) |
| 85 previous_mark_compactor_event_ = current_; |
| 86 |
| 87 if (collector == SCAVENGER) { |
| 88 current_ = Event(Event::SCAVENGER, gc_reason, collector_reason); |
| 89 } else { |
| 90 current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason); |
| 91 } |
| 92 |
| 93 current_.start_time = base::OS::TimeCurrentMillis(); |
| 94 current_.start_object_size = heap_->SizeOfObjects(); |
| 95 current_.start_memory_size = heap_->isolate()->memory_allocator()->Size(); |
| 96 current_.start_holes_size = CountTotalHolesSize(heap_); |
| 97 |
| 98 current_.incremental_marking_steps = incremental_marking_steps_; |
| 99 current_.incremental_marking_duration = incremental_marking_duration_; |
| 100 current_.longest_incremental_marking_step = longest_incremental_marking_step_; |
| 101 |
| 102 for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) { |
| 103 current_.scopes[i] = 0; |
| 104 } |
| 105 } |
| 106 |
| 107 |
| 108 void GCTracer::Stop() { |
| 109 if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return; |
| 110 |
| 111 current_.end_time = base::OS::TimeCurrentMillis(); |
| 112 current_.end_object_size = heap_->SizeOfObjects(); |
| 113 current_.end_memory_size = heap_->isolate()->memory_allocator()->Size(); |
| 114 current_.end_holes_size = CountTotalHolesSize(heap_); |
| 115 |
| 116 if (current_.type == Event::SCAVENGER) { |
| 117 scavenger_events_.push_front(current_); |
| 118 } else { |
| 119 mark_compactor_events_.push_front(current_); |
| 120 } |
| 121 |
| 122 if (current_.type == Event::MARK_COMPACTOR) |
| 123 longest_incremental_marking_step_ = 0.0; |
| 124 |
| 125 double duration = current_.end_time - current_.start_time; |
| 126 double spent_in_mutator = Max(current_.start_time - previous_.end_time, 0.0); |
| 127 |
| 128 heap_->UpdateCumulativeGCStatistics(duration, spent_in_mutator, |
| 129 current_.scopes[Scope::MC_MARK]); |
| 130 |
| 131 if (current_.type == Event::SCAVENGER && FLAG_trace_gc_ignore_scavenger) |
| 132 return; |
| 133 |
| 134 if (FLAG_trace_gc) { |
| 135 if (FLAG_trace_gc_nvp) |
| 136 PrintNVP(); |
| 137 else |
| 138 Print(); |
| 139 |
| 140 heap_->PrintShortHeapStatistics(); |
| 141 } |
| 142 } |
| 143 |
| 144 |
| 145 void GCTracer::AddIncrementalMarkingStep(double duration) { |
| 146 incremental_marking_steps_++; |
| 147 incremental_marking_duration_ += duration; |
| 148 longest_incremental_marking_step_ = |
| 149 Max(longest_incremental_marking_step_, duration); |
| 150 } |
| 151 |
| 152 |
| 153 void GCTracer::Print() const { |
| 154 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init()); |
| 155 |
| 156 PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", current_.TypeName(false), |
| 157 static_cast<double>(current_.start_object_size) / MB, |
| 158 static_cast<double>(current_.start_memory_size) / MB, |
| 159 static_cast<double>(current_.end_object_size) / MB, |
| 160 static_cast<double>(current_.end_memory_size) / MB); |
| 161 |
| 162 int external_time = static_cast<int>(current_.scopes[Scope::EXTERNAL]); |
| 163 if (external_time > 0) PrintF("%d / ", external_time); |
| 164 |
| 165 double duration = current_.end_time - current_.start_time; |
| 166 PrintF("%.1f ms", duration); |
| 167 if (current_.type == Event::SCAVENGER) { |
| 168 int steps = current_.incremental_marking_steps - |
| 169 previous_.incremental_marking_steps; |
| 170 if (steps > 0) { |
| 171 PrintF(" (+ %.1f ms in %d steps since last GC)", |
| 172 current_.incremental_marking_duration - |
| 173 previous_.incremental_marking_duration, |
| 174 steps); |
| 175 } |
| 176 } else { |
| 177 int steps = current_.incremental_marking_steps - |
| 178 previous_mark_compactor_event_.incremental_marking_steps; |
| 179 if (steps > 0) { |
| 180 PrintF( |
| 181 " (+ %.1f ms in %d steps since start of marking, " |
| 182 "biggest step %.1f ms)", |
| 183 current_.incremental_marking_duration - |
| 184 previous_mark_compactor_event_.incremental_marking_duration, |
| 185 steps, current_.longest_incremental_marking_step); |
| 186 } |
| 187 } |
| 188 |
| 189 if (current_.gc_reason != NULL) { |
| 190 PrintF(" [%s]", current_.gc_reason); |
| 191 } |
| 192 |
| 193 if (current_.collector_reason != NULL) { |
| 194 PrintF(" [%s]", current_.collector_reason); |
| 195 } |
| 196 |
| 197 PrintF(".\n"); |
| 198 } |
| 199 |
| 200 |
| 201 void GCTracer::PrintNVP() const { |
| 202 PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init()); |
| 203 |
| 204 double duration = current_.end_time - current_.start_time; |
| 205 double spent_in_mutator = current_.start_time - previous_.end_time; |
| 206 |
| 207 PrintF("pause=%.1f ", duration); |
| 208 PrintF("mutator=%.1f ", spent_in_mutator); |
| 209 PrintF("gc=%s ", current_.TypeName(true)); |
| 210 |
| 211 PrintF("external=%.1f ", current_.scopes[Scope::EXTERNAL]); |
| 212 PrintF("mark=%.1f ", current_.scopes[Scope::MC_MARK]); |
| 213 PrintF("sweep=%.2f ", current_.scopes[Scope::MC_SWEEP]); |
| 214 PrintF("sweepns=%.2f ", current_.scopes[Scope::MC_SWEEP_NEWSPACE]); |
| 215 PrintF("sweepos=%.2f ", current_.scopes[Scope::MC_SWEEP_OLDSPACE]); |
| 216 PrintF("sweepcode=%.2f ", current_.scopes[Scope::MC_SWEEP_CODE]); |
| 217 PrintF("sweepcell=%.2f ", current_.scopes[Scope::MC_SWEEP_CELL]); |
| 218 PrintF("sweepmap=%.2f ", current_.scopes[Scope::MC_SWEEP_MAP]); |
| 219 PrintF("evacuate=%.1f ", current_.scopes[Scope::MC_EVACUATE_PAGES]); |
| 220 PrintF("new_new=%.1f ", |
| 221 current_.scopes[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]); |
| 222 PrintF("root_new=%.1f ", |
| 223 current_.scopes[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]); |
| 224 PrintF("old_new=%.1f ", |
| 225 current_.scopes[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]); |
| 226 PrintF("compaction_ptrs=%.1f ", |
| 227 current_.scopes[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]); |
| 228 PrintF("intracompaction_ptrs=%.1f ", |
| 229 current_.scopes[Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]); |
| 230 PrintF("misc_compaction=%.1f ", |
| 231 current_.scopes[Scope::MC_UPDATE_MISC_POINTERS]); |
| 232 PrintF("weakcollection_process=%.1f ", |
| 233 current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]); |
| 234 PrintF("weakcollection_clear=%.1f ", |
| 235 current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]); |
| 236 |
| 237 PrintF("total_size_before=%" V8_PTR_PREFIX "d ", current_.start_object_size); |
| 238 PrintF("total_size_after=%" V8_PTR_PREFIX "d ", current_.end_object_size); |
| 239 PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", current_.start_holes_size); |
| 240 PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", current_.end_holes_size); |
| 241 |
| 242 intptr_t allocated_since_last_gc = |
| 243 current_.start_object_size - previous_.end_object_size; |
| 244 PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc); |
| 245 PrintF("promoted=%" V8_PTR_PREFIX "d ", heap_->promoted_objects_size_); |
| 246 PrintF("semi_space_copied=%" V8_PTR_PREFIX "d ", |
| 247 heap_->semi_space_copied_object_size_); |
| 248 PrintF("nodes_died_in_new=%d ", heap_->nodes_died_in_new_space_); |
| 249 PrintF("nodes_copied_in_new=%d ", heap_->nodes_copied_in_new_space_); |
| 250 PrintF("nodes_promoted=%d ", heap_->nodes_promoted_); |
| 251 PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_); |
| 252 PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_); |
| 253 |
| 254 if (current_.type == Event::SCAVENGER) { |
| 255 PrintF("stepscount=%d ", current_.incremental_marking_steps - |
| 256 previous_.incremental_marking_steps); |
| 257 PrintF("stepstook=%.1f ", current_.incremental_marking_duration - |
| 258 previous_.incremental_marking_duration); |
| 259 } else { |
| 260 PrintF("stepscount=%d ", |
| 261 current_.incremental_marking_steps - |
| 262 previous_mark_compactor_event_.incremental_marking_steps); |
| 263 PrintF("stepstook=%.1f ", |
| 264 current_.incremental_marking_duration - |
| 265 previous_mark_compactor_event_.incremental_marking_duration); |
| 266 PrintF("longeststep=%.1f ", current_.longest_incremental_marking_step); |
| 267 } |
| 268 |
| 269 PrintF("\n"); |
| 270 } |
| 271 } |
| 272 } // namespace v8::internal |
OLD | NEW |