gc-tracer.cc 22.6 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 103 104 105
      new_space_allocation_time_ms_(0.0),
      new_space_allocation_counter_bytes_(0),
      new_space_allocation_duration_since_gc_(0.0),
      new_space_allocation_in_bytes_since_gc_(0),
hpayer's avatar
hpayer committed
106
      start_counter_(0) {
107 108
  current_ = Event(Event::START, NULL, NULL);
  current_.end_time = base::OS::TimeCurrentMillis();
109
  previous_ = previous_incremental_mark_compactor_event_ = current_;
110 111 112 113 114
}


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

118
  previous_ = current_;
119
  double start_time = heap_->MonotonicallyIncreasingTimeInMs();
120
  SampleNewSpaceAllocation(start_time, heap_->NewSpaceAllocationCounter());
121 122
  if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR)
    previous_incremental_mark_compactor_event_ = current_;
123 124 125

  if (collector == SCAVENGER) {
    current_ = Event(Event::SCAVENGER, gc_reason, collector_reason);
126
  } else if (collector == MARK_COMPACTOR) {
127
    if (heap_->incremental_marking()->WasActivated()) {
128 129 130 131 132
      current_ =
          Event(Event::INCREMENTAL_MARK_COMPACTOR, gc_reason, collector_reason);
    } else {
      current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
    }
133 134
  }

135
  current_.start_time = start_time;
136 137 138
  current_.start_object_size = heap_->SizeOfObjects();
  current_.start_memory_size = heap_->isolate()->memory_allocator()->Size();
  current_.start_holes_size = CountTotalHolesSize(heap_);
139 140
  current_.new_space_object_size =
      heap_->new_space()->top() - heap_->new_space()->bottom();
141

142 143 144 145 146 147
  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_;
148 149
  current_.cumulative_pure_incremental_marking_duration =
      cumulative_pure_incremental_marking_duration_;
150 151 152 153 154
  current_.longest_incremental_marking_step = longest_incremental_marking_step_;

  for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
    current_.scopes[i] = 0;
  }
155 156 157 158 159 160
  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);
161 162 163
}


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

  DCHECK(start_counter_ >= 0);
176 177 178 179
  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
180

181
  current_.end_time = heap_->MonotonicallyIncreasingTimeInMs();
182 183 184
  current_.end_object_size = heap_->SizeOfObjects();
  current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
  current_.end_holes_size = CountTotalHolesSize(heap_);
185 186

  AddNewSpaceAllocation(current_.end_time);
187

188 189 190 191 192 193 194
  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);

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

236 237 238 239
  // TODO(ernstm): move the code below out of GCTracer.

  if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
  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;

  if (FLAG_trace_gc) {
    if (FLAG_trace_gc_nvp)
      PrintNVP();
    else
      Print();

    heap_->PrintShortHeapStatistics();
  }
}


260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
void GCTracer::SampleNewSpaceAllocation(double current_ms,
                                        size_t counter_bytes) {
  if (new_space_allocation_time_ms_ == 0) {
    // It is the first sample.
    new_space_allocation_time_ms_ = current_ms;
    new_space_allocation_counter_bytes_ = counter_bytes;
    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.
  size_t allocated_bytes = counter_bytes - new_space_allocation_counter_bytes_;
  double duration = current_ms - new_space_allocation_time_ms_;
  const double kMinDurationMs = 1;
  if (duration < kMinDurationMs) {
    // Do not sample small durations to avoid precision errors.
    return;
  }
  new_space_allocation_time_ms_ = current_ms;
  new_space_allocation_counter_bytes_ = counter_bytes;
  new_space_allocation_duration_since_gc_ += duration;
  new_space_allocation_in_bytes_since_gc_ += allocated_bytes;
}


void GCTracer::AddNewSpaceAllocation(double current_ms) {
  new_space_allocation_time_ms_ = current_ms;
  allocation_events_.push_front(
      AllocationEvent(new_space_allocation_duration_since_gc_,
                      new_space_allocation_in_bytes_since_gc_));
  new_space_allocation_duration_since_gc_ = 0;
  new_space_allocation_in_bytes_since_gc_ = 0;
291 292 293
}


294 295 296 297 298
void GCTracer::AddContextDisposalTime(double time) {
  context_disposal_events_.push_front(ContextDisposalEvent(time));
}


299 300
void GCTracer::AddSurvivalRatio(double promotion_ratio) {
  survival_events_.push_front(SurvivalEvent(promotion_ratio));
301 302 303
}


304 305 306 307
void GCTracer::AddIncrementalMarkingStep(double duration, intptr_t bytes) {
  cumulative_incremental_marking_steps_++;
  cumulative_incremental_marking_bytes_ += bytes;
  cumulative_incremental_marking_duration_ += duration;
308 309
  longest_incremental_marking_step_ =
      Max(longest_incremental_marking_step_, duration);
310
  cumulative_marking_duration_ += duration;
311 312 313
  if (bytes > 0) {
    cumulative_pure_incremental_marking_duration_ += duration;
  }
314 315 316 317
}


void GCTracer::Print() const {
318 319
  PrintIsolate(heap_->isolate(), "%8.0f ms: ",
               heap_->isolate()->time_millis_since_init());
320 321 322 323 324 325 326 327 328 329 330 331 332

  PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ", current_.TypeName(false),
         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]);
  if (external_time > 0) PrintF("%d / ", external_time);

  double duration = current_.end_time - current_.start_time;
  PrintF("%.1f ms", duration);
  if (current_.type == Event::SCAVENGER) {
333
    if (current_.incremental_marking_steps > 0) {
334
      PrintF(" (+ %.1f ms in %d steps since last GC)",
335 336
             current_.incremental_marking_duration,
             current_.incremental_marking_steps);
337 338
    }
  } else {
339
    if (current_.incremental_marking_steps > 0) {
340 341 342
      PrintF(
          " (+ %.1f ms in %d steps since start of marking, "
          "biggest step %.1f ms)",
343 344 345
          current_.incremental_marking_duration,
          current_.incremental_marking_steps,
          current_.longest_incremental_marking_step);
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
    }
  }

  if (current_.gc_reason != NULL) {
    PrintF(" [%s]", current_.gc_reason);
  }

  if (current_.collector_reason != NULL) {
    PrintF(" [%s]", current_.collector_reason);
  }

  PrintF(".\n");
}


void GCTracer::PrintNVP() const {
362 363
  PrintIsolate(heap_->isolate(), "[I:%p] %8.0f ms: ", heap_->isolate(),
               heap_->isolate()->time_millis_since_init());
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

  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]);
393
  PrintF("weak_closure=%.1f ", current_.scopes[Scope::MC_WEAKCLOSURE]);
394 395
  PrintF("inc_weak_closure=%.1f ",
         current_.scopes[Scope::MC_INCREMENTAL_WEAKCLOSURE]);
396 397 398 399
  PrintF("weakcollection_process=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]);
  PrintF("weakcollection_clear=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]);
400 401
  PrintF("weakcollection_abort=%.1f ",
         current_.scopes[Scope::MC_WEAKCOLLECTION_ABORT]);
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

  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_);
417
  PrintF("promotion_ratio=%.1f%% ", heap_->promotion_ratio_);
418
  PrintF("average_survival_ratio=%.1f%% ", AverageSurvivalRatio());
419 420
  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
421
  PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ",
422
         NewSpaceAllocationThroughputInBytesPerMillisecond());
423
  PrintF("context_disposal_rate=%.1f ", ContextDisposalRateInMilliseconds());
424 425

  if (current_.type == Event::SCAVENGER) {
426 427
    PrintF("steps_count=%d ", current_.incremental_marking_steps);
    PrintF("steps_took=%.1f ", current_.incremental_marking_duration);
428 429
    PrintF("scavenge_throughput=%" V8_PTR_PREFIX "d ",
           ScavengeSpeedInBytesPerMillisecond());
430
  } else {
431 432 433
    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);
434 435
    PrintF("incremental_marking_throughput=%" V8_PTR_PREFIX "d ",
           IncrementalMarkingSpeedInBytesPerMillisecond());
436 437 438 439
  }

  PrintF("\n");
}
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470


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 {
471 472 473 474
  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.
475
  if (incremental_mark_compactor_events_.empty()) {
476 477 478
    return cumulative_incremental_marking_duration_ /
           cumulative_incremental_marking_steps_;
  }
479

480 481
  int steps = 0;
  double durations = 0.0;
482 483
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end()) {
484 485 486 487 488 489 490 491
    steps += iter->incremental_marking_steps;
    durations += iter->incremental_marking_duration;
    ++iter;
  }

  if (steps == 0) return 0.0;

  return durations / steps;
492 493 494 495
}


double GCTracer::MaxIncrementalMarkingDuration() const {
496 497
  // We haven't completed an entire round of incremental marking, yet.
  // Use data from GCTracer instead of data from event buffers.
498 499
  if (incremental_mark_compactor_events_.empty())
    return longest_incremental_marking_step_;
500 501

  double max_duration = 0.0;
502 503
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end())
504 505 506 507 508 509
    max_duration = Max(iter->longest_incremental_marking_step, max_duration);

  return max_duration;
}


510
intptr_t GCTracer::IncrementalMarkingSpeedInBytesPerMillisecond() const {
511 512 513 514
  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.
515
  if (incremental_mark_compactor_events_.empty()) {
516
    return static_cast<intptr_t>(cumulative_incremental_marking_bytes_ /
517
                                 cumulative_pure_incremental_marking_duration_);
518 519 520 521
  }

  intptr_t bytes = 0;
  double durations = 0.0;
522 523
  EventBuffer::const_iterator iter = incremental_mark_compactor_events_.begin();
  while (iter != incremental_mark_compactor_events_.end()) {
524
    bytes += iter->incremental_marking_bytes;
525
    durations += iter->pure_incremental_marking_duration;
526 527 528 529
    ++iter;
  }

  if (durations == 0.0) return 0;
530

531
  return static_cast<intptr_t>(bytes / durations);
532
}
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548


intptr_t GCTracer::ScavengeSpeedInBytesPerMillisecond() const {
  intptr_t bytes = 0;
  double durations = 0.0;
  EventBuffer::const_iterator iter = scavenger_events_.begin();
  while (iter != scavenger_events_.end()) {
    bytes += iter->new_space_object_size;
    durations += iter->end_time - iter->start_time;
    ++iter;
  }

  if (durations == 0.0) return 0;

  return static_cast<intptr_t>(bytes / durations);
}
549 550 551 552 553 554 555 556


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;
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    durations += iter->end_time - iter->start_time;
    ++iter;
  }

  if (durations == 0.0) return 0;

  return static_cast<intptr_t>(bytes / durations);
}


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;
575 576 577 578 579 580 581
    ++iter;
  }

  if (durations == 0.0) return 0;

  return static_cast<intptr_t>(bytes / durations);
}
582 583


584 585 586
size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() const {
  size_t bytes = new_space_allocation_in_bytes_since_gc_;
  double durations = new_space_allocation_duration_since_gc_;
587
  AllocationEventBuffer::const_iterator iter = allocation_events_.begin();
588 589
  const size_t max_bytes = static_cast<size_t>(-1);
  while (iter != allocation_events_.end() && bytes < max_bytes - bytes) {
590 591 592 593 594 595 596
    bytes += iter->allocation_in_bytes_;
    durations += iter->duration_;
    ++iter;
  }

  if (durations == 0.0) return 0;

597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
  return static_cast<size_t>(bytes / durations + 0.5);
}


size_t GCTracer::NewSpaceAllocatedBytesInLast(double time_ms) const {
  size_t bytes = new_space_allocation_in_bytes_since_gc_;
  double durations = new_space_allocation_duration_since_gc_;
  AllocationEventBuffer::const_iterator iter = allocation_events_.begin();
  const size_t max_bytes = static_cast<size_t>(-1);
  while (iter != allocation_events_.end() && bytes < max_bytes - bytes &&
         durations < time_ms) {
    bytes += iter->allocation_in_bytes_;
    durations += iter->duration_;
    ++iter;
  }

  if (durations < time_ms) return 0;

  bytes = static_cast<size_t>(bytes * (time_ms / durations) + 0.5);
  // Return at least 1 since 0 means "no data".
  return std::max<size_t>(bytes, 1);
618
}
619 620 621


double GCTracer::ContextDisposalRateInMilliseconds() const {
622
  if (context_disposal_events_.size() < kRingBufferMaxSize) return 0.0;
623

624
  double begin = base::OS::TimeCurrentMillis();
625 626 627 628 629 630 631 632 633 634
  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();
}
635 636


637 638
double GCTracer::AverageSurvivalRatio() const {
  if (survival_events_.size() == 0) return 0.0;
639 640

  double sum_of_rates = 0.0;
641 642
  SurvivalEventBuffer::const_iterator iter = survival_events_.begin();
  while (iter != survival_events_.end()) {
643
    sum_of_rates += iter->promotion_ratio_;
644 645 646
    ++iter;
  }

647
  return sum_of_rates / static_cast<double>(survival_events_.size());
648 649 650 651
}


bool GCTracer::SurvivalEventsRecorded() const {
652
  return survival_events_.size() > 0;
653
}
654 655


656
void GCTracer::ResetSurvivalEvents() { survival_events_.reset(); }
657 658
}
}  // namespace v8::internal