gc-tracer.cc 25.7 KB
Newer Older
1 2 3 4 5 6
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/v8.h"

7
#include "src/heap/gc-tracer.h"
8 9 10 11 12 13 14 15 16 17 18 19 20 21

namespace v8 {
namespace internal {

static intptr_t CountTotalHolesSize(Heap* heap) {
  intptr_t holes_size = 0;
  OldSpaces spaces(heap);
  for (OldSpace* space = spaces.next(); space != NULL; space = spaces.next()) {
    holes_size += space->Waste() + space->Available();
  }
  return holes_size;
}


22
GCTracer::AllocationEvent::AllocationEvent(double duration,
23
                                           size_t allocation_in_bytes) {
24 25 26 27 28
  duration_ = duration;
  allocation_in_bytes_ = allocation_in_bytes;
}


29 30 31 32 33
GCTracer::ContextDisposalEvent::ContextDisposalEvent(double time) {
  time_ = time;
}


34
GCTracer::SurvivalEvent::SurvivalEvent(double promotion_ratio) {
35
  promotion_ratio_ = promotion_ratio;
36 37 38
}


39 40 41 42 43 44 45 46 47 48 49 50 51
GCTracer::Event::Event(Type type, const char* gc_reason,
                       const char* collector_reason)
    : type(type),
      gc_reason(gc_reason),
      collector_reason(collector_reason),
      start_time(0.0),
      end_time(0.0),
      start_object_size(0),
      end_object_size(0),
      start_memory_size(0),
      end_memory_size(0),
      start_holes_size(0),
      end_holes_size(0),
52
      cumulative_incremental_marking_steps(0),
53
      incremental_marking_steps(0),
54 55 56 57
      cumulative_incremental_marking_bytes(0),
      incremental_marking_bytes(0),
      cumulative_incremental_marking_duration(0.0),
      incremental_marking_duration(0.0),
58 59
      cumulative_pure_incremental_marking_duration(0.0),
      pure_incremental_marking_duration(0.0),
60
      longest_incremental_marking_step(0.0) {
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
    scopes[i] = 0;
  }
}


const char* GCTracer::Event::TypeName(bool short_name) const {
  switch (type) {
    case SCAVENGER:
      if (short_name) {
        return "s";
      } else {
        return "Scavenge";
      }
    case MARK_COMPACTOR:
76
    case INCREMENTAL_MARK_COMPACTOR:
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
      if (short_name) {
        return "ms";
      } else {
        return "Mark-sweep";
      }
    case START:
      if (short_name) {
        return "st";
      } else {
        return "Start";
      }
  }
  return "Unknown Event Type";
}


GCTracer::GCTracer(Heap* heap)
    : heap_(heap),
95 96 97
      cumulative_incremental_marking_steps_(0),
      cumulative_incremental_marking_bytes_(0),
      cumulative_incremental_marking_duration_(0.0),
98
      cumulative_pure_incremental_marking_duration_(0.0),
99 100
      longest_incremental_marking_step_(0.0),
      cumulative_marking_duration_(0.0),
101
      cumulative_sweeping_duration_(0.0),
102
      allocation_time_ms_(0.0),
103
      new_space_allocation_counter_bytes_(0),
104 105
      old_generation_allocation_counter_bytes_(0),
      allocation_duration_since_gc_(0.0),
106
      new_space_allocation_in_bytes_since_gc_(0),
107
      old_generation_allocation_in_bytes_since_gc_(0),
108
      combined_mark_compact_speed_cache_(0.0),
hpayer's avatar
hpayer committed
109
      start_counter_(0) {
110 111
  current_ = Event(Event::START, NULL, NULL);
  current_.end_time = base::OS::TimeCurrentMillis();
112
  previous_ = previous_incremental_mark_compactor_event_ = current_;
113 114 115 116 117
}


void GCTracer::Start(GarbageCollector collector, const char* gc_reason,
                     const char* collector_reason) {
hpayer's avatar
hpayer committed
118 119 120
  start_counter_++;
  if (start_counter_ != 1) return;

121
  previous_ = current_;
122
  double start_time = heap_->MonotonicallyIncreasingTimeInMs();
123 124
  SampleAllocation(start_time, heap_->NewSpaceAllocationCounter(),
                   heap_->OldGenerationAllocationCounter());
125 126
  if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR)
    previous_incremental_mark_compactor_event_ = current_;
127 128 129

  if (collector == SCAVENGER) {
    current_ = Event(Event::SCAVENGER, gc_reason, collector_reason);
130
  } else if (collector == MARK_COMPACTOR) {
131
    if (heap_->incremental_marking()->WasActivated()) {
132 133 134 135 136
      current_ =
          Event(Event::INCREMENTAL_MARK_COMPACTOR, gc_reason, collector_reason);
    } else {
      current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
    }
137 138
  }

139
  current_.start_time = start_time;
140 141 142
  current_.start_object_size = heap_->SizeOfObjects();
  current_.start_memory_size = heap_->isolate()->memory_allocator()->Size();
  current_.start_holes_size = CountTotalHolesSize(heap_);
143 144
  current_.new_space_object_size =
      heap_->new_space()->top() - heap_->new_space()->bottom();
145

146 147 148 149 150 151
  current_.cumulative_incremental_marking_steps =
      cumulative_incremental_marking_steps_;
  current_.cumulative_incremental_marking_bytes =
      cumulative_incremental_marking_bytes_;
  current_.cumulative_incremental_marking_duration =
      cumulative_incremental_marking_duration_;
152 153
  current_.cumulative_pure_incremental_marking_duration =
      cumulative_pure_incremental_marking_duration_;
154 155 156 157 158
  current_.longest_incremental_marking_step = longest_incremental_marking_step_;

  for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
    current_.scopes[i] = 0;
  }
159 160 161 162 163 164
  int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB);
  int used_memory = static_cast<int>(current_.start_object_size / KB);
  heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample(
      start_time, committed_memory);
  heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample(
      start_time, used_memory);
165 166 167
}


hpayer's avatar
hpayer committed
168 169 170
void GCTracer::Stop(GarbageCollector collector) {
  start_counter_--;
  if (start_counter_ != 0) {
171 172 173
    Output("[Finished reentrant %s during %s.]\n",
           collector == SCAVENGER ? "Scavenge" : "Mark-sweep",
           current_.TypeName(false));
hpayer's avatar
hpayer committed
174 175 176 177
    return;
  }

  DCHECK(start_counter_ >= 0);
178 179 180 181
  DCHECK((collector == SCAVENGER && current_.type == Event::SCAVENGER) ||
         (collector == MARK_COMPACTOR &&
          (current_.type == Event::MARK_COMPACTOR ||
           current_.type == Event::INCREMENTAL_MARK_COMPACTOR)));
hpayer's avatar
hpayer committed
182

183
  current_.end_time = heap_->MonotonicallyIncreasingTimeInMs();
184 185 186
  current_.end_object_size = heap_->SizeOfObjects();
  current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
  current_.end_holes_size = CountTotalHolesSize(heap_);
187
  current_.survived_new_space_object_size = heap_->SurvivedNewSpaceObjectSize();
188

189
  AddAllocation(current_.end_time);
190

191 192 193 194 195 196 197
  int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB);
  int used_memory = static_cast<int>(current_.end_object_size / KB);
  heap_->isolate()->counters()->aggregated_memory_heap_committed()->AddSample(
      current_.end_time, committed_memory);
  heap_->isolate()->counters()->aggregated_memory_heap_used()->AddSample(
      current_.end_time, used_memory);

198
  if (current_.type == Event::SCAVENGER) {
199 200 201 202 203 204 205 206 207
    current_.incremental_marking_steps =
        current_.cumulative_incremental_marking_steps -
        previous_.cumulative_incremental_marking_steps;
    current_.incremental_marking_bytes =
        current_.cumulative_incremental_marking_bytes -
        previous_.cumulative_incremental_marking_bytes;
    current_.incremental_marking_duration =
        current_.cumulative_incremental_marking_duration -
        previous_.cumulative_incremental_marking_duration;
208 209 210
    current_.pure_incremental_marking_duration =
        current_.cumulative_pure_incremental_marking_duration -
        previous_.cumulative_pure_incremental_marking_duration;
211
    scavenger_events_.push_front(current_);
212
  } else if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR) {
213 214
    current_.incremental_marking_steps =
        current_.cumulative_incremental_marking_steps -
215 216
        previous_incremental_mark_compactor_event_
            .cumulative_incremental_marking_steps;
217 218
    current_.incremental_marking_bytes =
        current_.cumulative_incremental_marking_bytes -
219 220
        previous_incremental_mark_compactor_event_
            .cumulative_incremental_marking_bytes;
221 222
    current_.incremental_marking_duration =
        current_.cumulative_incremental_marking_duration -
223 224
        previous_incremental_mark_compactor_event_
            .cumulative_incremental_marking_duration;
225 226
    current_.pure_incremental_marking_duration =
        current_.cumulative_pure_incremental_marking_duration -
227
        previous_incremental_mark_compactor_event_
228
            .cumulative_pure_incremental_marking_duration;
229
    longest_incremental_marking_step_ = 0.0;
230
    incremental_mark_compactor_events_.push_front(current_);
231
    combined_mark_compact_speed_cache_ = 0.0;
232 233 234 235
  } else {
    DCHECK(current_.incremental_marking_bytes == 0);
    DCHECK(current_.incremental_marking_duration == 0);
    DCHECK(current_.pure_incremental_marking_duration == 0);
236
    longest_incremental_marking_step_ = 0.0;
237
    mark_compactor_events_.push_front(current_);
238
    combined_mark_compact_speed_cache_ = 0.0;
239 240
  }

241 242
  // TODO(ernstm): move the code below out of GCTracer.

243 244 245 246 247 248 249 250 251
  double duration = current_.end_time - current_.start_time;
  double spent_in_mutator = Max(current_.start_time - previous_.end_time, 0.0);

  heap_->UpdateCumulativeGCStatistics(duration, spent_in_mutator,
                                      current_.scopes[Scope::MC_MARK]);

  if (current_.type == Event::SCAVENGER && FLAG_trace_gc_ignore_scavenger)
    return;

252 253 254 255
  if (FLAG_trace_gc_nvp)
    PrintNVP();
  else
    Print();
256

257
  if (FLAG_trace_gc) {
258 259 260 261 262
    heap_->PrintShortHeapStatistics();
  }
}


263 264 265 266
void GCTracer::SampleAllocation(double current_ms,
                                size_t new_space_counter_bytes,
                                size_t old_generation_counter_bytes) {
  if (allocation_time_ms_ == 0) {
267
    // It is the first sample.
268 269 270
    allocation_time_ms_ = current_ms;
    new_space_allocation_counter_bytes_ = new_space_counter_bytes;
    old_generation_allocation_counter_bytes_ = old_generation_counter_bytes;
271 272 273 274
    return;
  }
  // This assumes that counters are unsigned integers so that the subtraction
  // below works even if the new counter is less then the old counter.
275 276 277 278 279 280 281 282 283 284 285 286
  size_t new_space_allocated_bytes =
      new_space_counter_bytes - new_space_allocation_counter_bytes_;
  size_t old_generation_allocated_bytes =
      old_generation_counter_bytes - old_generation_allocation_counter_bytes_;
  double duration = current_ms - allocation_time_ms_;
  allocation_time_ms_ = current_ms;
  new_space_allocation_counter_bytes_ = new_space_counter_bytes;
  old_generation_allocation_counter_bytes_ = old_generation_counter_bytes;
  allocation_duration_since_gc_ += duration;
  new_space_allocation_in_bytes_since_gc_ += new_space_allocated_bytes;
  old_generation_allocation_in_bytes_since_gc_ +=
      old_generation_allocated_bytes;
287 288 289
}


290 291 292 293
void GCTracer::AddAllocation(double current_ms) {
  allocation_time_ms_ = current_ms;
  new_space_allocation_events_.push_front(AllocationEvent(
      allocation_duration_since_gc_, new_space_allocation_in_bytes_since_gc_));
294
  old_generation_allocation_events_.push_front(
295
      AllocationEvent(allocation_duration_since_gc_,
296
                      old_generation_allocation_in_bytes_since_gc_));
297
  allocation_duration_since_gc_ = 0;
298
  new_space_allocation_in_bytes_since_gc_ = 0;
299
  old_generation_allocation_in_bytes_since_gc_ = 0;
300 301 302
}


303 304 305 306 307
void GCTracer::AddContextDisposalTime(double time) {
  context_disposal_events_.push_front(ContextDisposalEvent(time));
}


308 309
void GCTracer::AddSurvivalRatio(double promotion_ratio) {
  survival_events_.push_front(SurvivalEvent(promotion_ratio));
310 311 312
}


313 314 315 316
void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) {
  cumulative_incremental_marking_steps_++;
  cumulative_incremental_marking_bytes_ += bytes;
  cumulative_incremental_marking_duration_ += duration;
317 318
  longest_incremental_marking_step_ =
      Max(longest_incremental_marking_step_, duration);
319
  cumulative_marking_duration_ += duration;
320 321 322
  if (bytes > 0) {
    cumulative_pure_incremental_marking_duration_ += duration;
  }
323 324 325
}


326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
void GCTracer::Output(const char* format, ...) const {
  if (FLAG_trace_gc) {
    va_list arguments;
    va_start(arguments, format);
    base::OS::VPrint(format, arguments);
    va_end(arguments);
  }

  const int kBufferSize = 256;
  char raw_buffer[kBufferSize];
  Vector<char> buffer(raw_buffer, kBufferSize);
  va_list arguments2;
  va_start(arguments2, format);
  VSNPrintF(buffer, format, arguments2);
  va_end(arguments2);

  heap_->AddToRingBuffer(buffer.start());
}


346
void GCTracer::Print() const {
347 348 349 350
  if (FLAG_trace_gc) {
    PrintIsolate(heap_->isolate(), "");
  }
  Output("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
351

352
  Output("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", current_.TypeName(false),
353 354 355 356 357 358 359
         static_cast<double>(current_.start_object_size) / MB,
         static_cast<double>(current_.start_memory_size) / MB,
         static_cast<double>(current_.end_object_size) / MB,
         static_cast<double>(current_.end_memory_size) / MB);

  int external_time = static_cast<int>(current_.scopes[Scope::EXTERNAL]);
  double duration = current_.end_time - current_.start_time;
360 361
  Output("%.1f / %d ms", duration, external_time);

362
  if (current_.type == Event::SCAVENGER) {
363
    if (current_.incremental_marking_steps > 0) {
364
      Output(" (+ %.1f ms in %d steps since last GC)",
365 366
             current_.incremental_marking_duration,
             current_.incremental_marking_steps);
367 368
    }
  } else {
369
    if (current_.incremental_marking_steps > 0) {
370
      Output(
371 372
          " (+ %.1f ms in %d steps since start of marking, "
          "biggest step %.1f ms)",
373 374 375
          current_.incremental_marking_duration,
          current_.incremental_marking_steps,
          current_.longest_incremental_marking_step);
376 377 378 379
    }
  }

  if (current_.gc_reason != NULL) {
380
    Output(" [%s]", current_.gc_reason);
381 382 383
  }

  if (current_.collector_reason != NULL) {
384
    Output(" [%s]", current_.collector_reason);
385 386
  }

387
  Output(".\n");
388 389 390 391
}


void GCTracer::PrintNVP() const {
392 393
  PrintIsolate(heap_->isolate(), "[I:%p] %8.0f ms: ", heap_->isolate(),
               heap_->isolate()->time_millis_since_init());
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422

  double duration = current_.end_time - current_.start_time;
  double spent_in_mutator = current_.start_time - previous_.end_time;

  PrintF("pause=%.1f ", duration);
  PrintF("mutator=%.1f ", spent_in_mutator);
  PrintF("gc=%s ", current_.TypeName(true));

  PrintF("external=%.1f ", current_.scopes[Scope::EXTERNAL]);
  PrintF("mark=%.1f ", current_.scopes[Scope::MC_MARK]);
  PrintF("sweep=%.2f ", current_.scopes[Scope::MC_SWEEP]);
  PrintF("sweepns=%.2f ", current_.scopes[Scope::MC_SWEEP_NEWSPACE]);
  PrintF("sweepos=%.2f ", current_.scopes[Scope::MC_SWEEP_OLDSPACE]);
  PrintF("sweepcode=%.2f ", current_.scopes[Scope::MC_SWEEP_CODE]);
  PrintF("sweepcell=%.2f ", current_.scopes[Scope::MC_SWEEP_CELL]);
  PrintF("sweepmap=%.2f ", current_.scopes[Scope::MC_SWEEP_MAP]);
  PrintF("evacuate=%.1f ", current_.scopes[Scope::MC_EVACUATE_PAGES]);
  PrintF("new_new=%.1f ",
         current_.scopes[Scope::MC_UPDATE_NEW_TO_NEW_POINTERS]);
  PrintF("root_new=%.1f ",
         current_.scopes[Scope::MC_UPDATE_ROOT_TO_NEW_POINTERS]);
  PrintF("old_new=%.1f ",
         current_.scopes[Scope::MC_UPDATE_OLD_TO_NEW_POINTERS]);
  PrintF("compaction_ptrs=%.1f ",
         current_.scopes[Scope::MC_UPDATE_POINTERS_TO_EVACUATED]);
  PrintF("intracompaction_ptrs=%.1f ",
         current_.scopes[Scope::MC_UPDATE_POINTERS_BETWEEN_EVACUATED]);
  PrintF("misc_compaction=%.1f ",
         current_.scopes[Scope::MC_UPDATE_MISC_POINTERS]);
423
  PrintF("weak_closure=%.1f ", current_.scopes[Scope::MC_WEAKCLOSURE]);
424 425
  PrintF("inc_weak_closure=%.1f ",
         current_.scopes[Scope::MC_INCREMENTAL_WEAKCLOSURE]);
426 427 428 429
  PrintF("weakcollection_process=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]);
  PrintF("weakcollection_clear=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]);
430 431
  PrintF("weakcollection_abort=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_ABORT]);
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

  PrintF("total_size_before=%" V8_PTR_PREFIX "d ", current_.start_object_size);
  PrintF("total_size_after=%" V8_PTR_PREFIX "d ", current_.end_object_size);
  PrintF("holes_size_before=%" V8_PTR_PREFIX "d ", current_.start_holes_size);
  PrintF("holes_size_after=%" V8_PTR_PREFIX "d ", current_.end_holes_size);

  intptr_t allocated_since_last_gc =
      current_.start_object_size - previous_.end_object_size;
  PrintF("allocated=%" V8_PTR_PREFIX "d ", allocated_since_last_gc);
  PrintF("promoted=%" V8_PTR_PREFIX "d ", heap_->promoted_objects_size_);
  PrintF("semi_space_copied=%" V8_PTR_PREFIX "d ",
         heap_->semi_space_copied_object_size_);
  PrintF("nodes_died_in_new=%d ", heap_->nodes_died_in_new_space_);
  PrintF("nodes_copied_in_new=%d ", heap_->nodes_copied_in_new_space_);
  PrintF("nodes_promoted=%d ", heap_->nodes_promoted_);
447
  PrintF("promotion_ratio=%.1f%% ", heap_->promotion_ratio_);
448
  PrintF("average_survival_ratio=%.1f%% ", AverageSurvivalRatio());
449 450
  PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_);
  PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_);
svenpanne@chromium.org's avatar
svenpanne@chromium.org committed
451
  PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ",
452
         NewSpaceAllocationThroughputInBytesPerMillisecond());
453
  PrintF("context_disposal_rate=%.1f ", ContextDisposalRateInMilliseconds());
454 455

  if (current_.type == Event::SCAVENGER) {
456 457
    PrintF("steps_count=%d ", current_.incremental_marking_steps);
    PrintF("steps_took=%.1f ", current_.incremental_marking_duration);
458 459
    PrintF("scavenge_throughput=%" V8_PTR_PREFIX "d ",
           ScavengeSpeedInBytesPerMillisecond());
460
  } else {
461 462 463
    PrintF("steps_count=%d ", current_.incremental_marking_steps);
    PrintF("steps_took=%.1f ", current_.incremental_marking_duration);
    PrintF("longest_step=%.1f ", current_.longest_incremental_marking_step);
464 465
    PrintF("incremental_marking_throughput=%" V8_PTR_PREFIX "d ",
           IncrementalMarkingSpeedInBytesPerMillisecond());
466 467 468 469
  }

  PrintF("\n");
}
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500


double GCTracer::MeanDuration(const EventBuffer& events) const {
  if (events.empty()) return 0.0;

  double mean = 0.0;
  EventBuffer::const_iterator iter = events.begin();
  while (iter != events.end()) {
    mean += iter->end_time - iter->start_time;
    ++iter;
  }

  return mean / events.size();
}


double GCTracer::MaxDuration(const EventBuffer& events) const {
  if (events.empty()) return 0.0;

  double maximum = 0.0f;
  EventBuffer::const_iterator iter = events.begin();
  while (iter != events.end()) {
    maximum = Max(iter->end_time - iter->start_time, maximum);
    ++iter;
  }

  return maximum;
}


double GCTracer::MeanIncrementalMarkingDuration() const {
501 502 503 504
  if (cumulative_incremental_marking_steps_ == 0) return 0.0;

  // We haven't completed an entire round of incremental marking, yet.
  // Use data from GCTracer instead of data from event buffers.
505
  if (incremental_mark_compactor_events_.empty()) {
506 507 508
    return cumulative_incremental_marking_duration_ /
           cumulative_incremental_marking_steps_;
  }
509

510 511
  int steps = 0;
  double durations = 0.0;
512 513
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end()) {
514 515 516 517 518 519 520 521
    steps += iter->incremental_marking_steps;
    durations += iter->incremental_marking_duration;
    ++iter;
  }

  if (steps == 0) return 0.0;

  return durations / steps;
522 523 524 525
}


double GCTracer::MaxIncrementalMarkingDuration() const {
526 527
  // We haven't completed an entire round of incremental marking, yet.
  // Use data from GCTracer instead of data from event buffers.
528 529
  if (incremental_mark_compactor_events_.empty())
    return longest_incremental_marking_step_;
530 531

  double max_duration = 0.0;
532 533
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end())
534 535 536 537 538 539
    max_duration = Max(iter->longest_incremental_marking_step, max_duration);

  return max_duration;
}


540
intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const {
541 542 543 544
  if (cumulative_incremental_marking_duration_ == 0.0) return 0;

  // We haven't completed an entire round of incremental marking, yet.
  // Use data from GCTracer instead of data from event buffers.
545
  if (incremental_mark_compactor_events_.empty()) {
546
    return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ /
547
                                 cumulative_pure_incremental_marking_duration_);
548 549 550 551
  }

  intptr_t bytes = 0;
  double durations = 0.0;
552 553
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end()) {
554
    bytes += iter->incremental_marking_bytes;
555
    durations += iter->pure_incremental_marking_duration;
556 557 558 559
    ++iter;
  }

  if (durations == 0.0) return 0;
560 561
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
562
}
563 564


565 566
intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond(
    ScavengeSpeedMode mode) const {
567 568 569 570
  intptr_t bytes = 0;
  double durations = 0.0;
  EventBuffer::const_iterator iter = scavenger_events_.begin();
  while (iter != scavenger_events_.end()) {
571 572
    bytes += mode == kForAllObjects ? iter->new_space_object_size
                                    : iter->survived_new_space_object_size;
573 574 575 576 577
    durations += iter->end_time - iter->start_time;
    ++iter;
  }

  if (durations == 0.0) return 0;
578 579
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
580
}
581 582 583 584 585 586 587 588


intptr_t GCTracer::MarkCompactSpeedInBytesPerMillisecond() const {
  intptr_t bytes = 0;
  double durations = 0.0;
  EventBuffer::const_iterator iter = mark_compactor_events_.begin();
  while (iter != mark_compactor_events_.end()) {
    bytes += iter->start_object_size;
589 590 591 592 593
    durations += iter->end_time - iter->start_time;
    ++iter;
  }

  if (durations == 0.0) return 0;
594 595
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
596 597 598 599 600 601 602 603 604 605 606
}


intptr_t GCTracer::FinalIncrementalMarkCompactSpeedInBytesPerMillisecond()
    const {
  intptr_t bytes = 0;
  double durations = 0.0;
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end()) {
    bytes += iter->start_object_size;
    durations += iter->end_time - iter->start_time;
607 608 609 610
    ++iter;
  }

  if (durations == 0.0) return 0;
611 612 613
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
}
614

615 616 617 618

double GCTracer::CombinedMarkCompactSpeedInBytesPerMillisecond() {
  if (combined_mark_compact_speed_cache_ > 0)
    return combined_mark_compact_speed_cache_;
619
  const double kMinimumMarkingSpeed = 0.5;
620 621 622 623
  double speed1 =
      static_cast<double>(IncrementalMarkingSpeedInBytesPerMillisecond());
  double speed2 = static_cast<double>(
      FinalIncrementalMarkCompactSpeedInBytesPerMillisecond());
624
  if (speed1 < kMinimumMarkingSpeed || speed2 < kMinimumMarkingSpeed) {
625 626 627 628 629 630 631 632 633 634
    // No data for the incremental marking speed.
    // Return the non-incremental mark-compact speed.
    combined_mark_compact_speed_cache_ =
        static_cast<double>(MarkCompactSpeedInBytesPerMillisecond());
  } else {
    // Combine the speed of incremental step and the speed of the final step.
    // 1 / (1 / speed1 + 1 / speed2) = speed1 * speed2 / (speed1 + speed2).
    combined_mark_compact_speed_cache_ = speed1 * speed2 / (speed1 + speed2);
  }
  return combined_mark_compact_speed_cache_;
635
}
636 637


638 639
size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond(
    double time_ms) const {
640
  size_t bytes = new_space_allocation_in_bytes_since_gc_;
641 642 643
  double durations = allocation_duration_since_gc_;
  AllocationEventBuffer::const_iterator iter =
      new_space_allocation_events_.begin();
644
  const size_t max_bytes = static_cast<size_t>(-1);
645
  while (iter != new_space_allocation_events_.end() &&
646
         bytes < max_bytes - bytes && (time_ms == 0 || durations < time_ms)) {
647 648 649 650 651 652
    bytes += iter->allocation_in_bytes_;
    durations += iter->duration_;
    ++iter;
  }

  if (durations == 0.0) return 0;
653 654
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
655 656 657
}


658
size_t GCTracer::OldGenerationAllocationThroughputInBytesPerMillisecond(
659
    double time_ms) const {
660
  size_t bytes = old_generation_allocation_in_bytes_since_gc_;
661
  double durations = allocation_duration_since_gc_;
662 663
  AllocationEventBuffer::const_iterator iter =
      old_generation_allocation_events_.begin();
664
  const size_t max_bytes = static_cast<size_t>(-1);
665 666
  while (iter != old_generation_allocation_events_.end() &&
         bytes < max_bytes - bytes && (time_ms == 0 || durations < time_ms)) {
667 668 669 670 671
    bytes += iter->allocation_in_bytes_;
    durations += iter->duration_;
    ++iter;
  }

672
  if (durations == 0.0) return 0;
673 674 675
  // Make sure the result is at least 1.
  return Max<size_t>(static_cast<size_t>(bytes / durations + 0.5), 1);
}
676

677 678 679 680 681

size_t GCTracer::AllocationThroughputInBytesPerMillisecond(
    double time_ms) const {
  return NewSpaceAllocationThroughputInBytesPerMillisecond(time_ms) +
         OldGenerationAllocationThroughputInBytesPerMillisecond(time_ms);
682
}
683 684


685 686
size_t GCTracer::CurrentOldGenerationAllocationThroughputInBytesPerMillisecond()
    const {
687
  static const double kThroughputTimeFrame = 5000;
688 689
  return OldGenerationAllocationThroughputInBytesPerMillisecond(
      kThroughputTimeFrame);
690 691 692
}


693
double GCTracer::ContextDisposalRateInMilliseconds() const {
694
  if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0;
695

696
  double begin = base::OS::TimeCurrentMillis();
697 698 699 700 701 702 703 704 705 706
  double end = 0.0;
  ContextDisposalEventBuffer::const_iterator iter =
      context_disposal_events_.begin();
  while (iter != context_disposal_events_.end()) {
    end = iter->time_;
    ++iter;
  }

  return (begin - end) / context_disposal_events_.size();
}
707 708


709 710
double GCTracer::AverageSurvivalRatio() const {
  if (survival_events_.size() == 0) return 0.0;
711 712

  double sum_of_rates = 0.0;
713 714
  SurvivalEventBuffer::const_iterator iter = survival_events_.begin();
  while (iter != survival_events_.end()) {
715
    sum_of_rates += iter->promotion_ratio_;
716 717 718
    ++iter;
  }

719
  return sum_of_rates / static_cast<double>(survival_events_.size());
720 721 722 723
}


bool GCTracer::SurvivalEventsRecorded() const {
724
  return survival_events_.size() > 0;
725
}
726 727


728
void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); }
729 730
}  // namespace internal
}  // namespace v8