| 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 |