PrintF("new_space_capacity=%" V8_PTR_PREFIX "d ", new_space_capacity);
PrintF("new_space_allocation_throughput=%" V8_PTR_PREFIX "d ",
new_space_allocation_throughput_in_bytes_per_ms);
- PrintF("current_new_space_allocation_throughput=%" V8_PTR_PREFIX "d",
- current_new_space_allocation_throughput_in_bytes_per_ms);
+ PrintF("current_allocation_throughput=%" V8_PTR_PREFIX "d",
+ current_allocation_throughput_in_bytes_per_ms);
}
size_t used_new_space_size;
size_t new_space_capacity;
size_t new_space_allocation_throughput_in_bytes_per_ms;
- size_t current_new_space_allocation_throughput_in_bytes_per_ms;
+ size_t current_allocation_throughput_in_bytes_per_ms;
};
GCIdleTimeHandler()
longest_incremental_marking_step_(0.0),
cumulative_marking_duration_(0.0),
cumulative_sweeping_duration_(0.0),
- new_space_allocation_time_ms_(0.0),
+ allocation_time_ms_(0.0),
new_space_allocation_counter_bytes_(0),
- new_space_allocation_duration_since_gc_(0.0),
+ old_generation_allocation_counter_bytes_(0),
+ allocation_duration_since_gc_(0.0),
new_space_allocation_in_bytes_since_gc_(0),
+ old_generation_allocation_in_bytes_since_gc_(0),
start_counter_(0) {
current_ = Event(Event::START, NULL, NULL);
current_.end_time = base::OS::TimeCurrentMillis();
previous_ = current_;
double start_time = heap_->MonotonicallyIncreasingTimeInMs();
- SampleNewSpaceAllocation(start_time, heap_->NewSpaceAllocationCounter());
+ SampleAllocation(start_time, heap_->NewSpaceAllocationCounter(),
+ heap_->OldGenerationAllocationCounter());
if (current_.type == Event::INCREMENTAL_MARK_COMPACTOR)
previous_incremental_mark_compactor_event_ = current_;
current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
current_.end_holes_size = CountTotalHolesSize(heap_);
- AddNewSpaceAllocation(current_.end_time);
+ AddAllocation(current_.end_time);
int committed_memory = static_cast<int>(heap_->CommittedMemory() / KB);
int used_memory = static_cast<int>(current_.end_object_size / KB);
}
-void GCTracer::SampleNewSpaceAllocation(double current_ms,
- size_t counter_bytes) {
- if (new_space_allocation_time_ms_ == 0) {
+void GCTracer::SampleAllocation(double current_ms,
+ size_t new_space_counter_bytes,
+ size_t old_generation_counter_bytes) {
+ if (allocation_time_ms_ == 0) {
// It is the first sample.
- new_space_allocation_time_ms_ = current_ms;
- new_space_allocation_counter_bytes_ = counter_bytes;
+ allocation_time_ms_ = current_ms;
+ new_space_allocation_counter_bytes_ = new_space_counter_bytes;
+ old_generation_allocation_counter_bytes_ = old_generation_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_;
+ 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_;
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;
+ 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;
}
-void GCTracer::AddNewSpaceAllocation(double current_ms) {
- new_space_allocation_time_ms_ = current_ms;
+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_));
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;
+ AllocationEvent(allocation_duration_since_gc_,
+ new_space_allocation_in_bytes_since_gc_ +
+ old_generation_allocation_in_bytes_since_gc_));
+ allocation_duration_since_gc_ = 0;
new_space_allocation_in_bytes_since_gc_ = 0;
+ old_generation_allocation_in_bytes_since_gc_ = 0;
}
size_t GCTracer::NewSpaceAllocationThroughputInBytesPerMillisecond() 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();
+ double durations = allocation_duration_since_gc_;
+ AllocationEventBuffer::const_iterator iter =
+ new_space_allocation_events_.begin();
const size_t max_bytes = static_cast<size_t>(-1);
- while (iter != allocation_events_.end() && bytes < max_bytes - bytes) {
+ while (iter != new_space_allocation_events_.end() &&
+ bytes < max_bytes - bytes) {
bytes += iter->allocation_in_bytes_;
durations += iter->duration_;
++iter;
}
-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_;
+size_t GCTracer::AllocatedBytesInLast(double time_ms) const {
+ size_t bytes = new_space_allocation_in_bytes_since_gc_ +
+ old_generation_allocation_in_bytes_since_gc_;
+ double durations = 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 &&
}
-size_t GCTracer::CurrentNewSpaceAllocationThroughputInBytesPerMillisecond()
- const {
+size_t GCTracer::CurrentAllocationThroughputInBytesPerMillisecond() const {
static const double kThroughputTimeFrame = 5000;
- size_t allocated_bytes = NewSpaceAllocatedBytesInLast(kThroughputTimeFrame);
+ size_t allocated_bytes = AllocatedBytesInLast(kThroughputTimeFrame);
if (allocated_bytes == 0) return 0;
return static_cast<size_t>((allocated_bytes / kThroughputTimeFrame) + 1);
}
void Stop(GarbageCollector collector);
// Sample and accumulate bytes allocated since the last GC.
- void SampleNewSpaceAllocation(double current_ms, size_t counter_bytes);
+ void SampleAllocation(double current_ms, size_t new_space_counter_bytes,
+ size_t old_generation_counter_bytes);
// Log the accumulated new space allocation bytes.
- void AddNewSpaceAllocation(double current_ms);
+ void AddAllocation(double current_ms);
void AddContextDisposalTime(double time);
// Returns 0 if no allocation events have been recorded.
size_t NewSpaceAllocationThroughputInBytesPerMillisecond() const;
- // Bytes allocated in new space in the specified time.
+ // Bytes allocated in heap in the specified time.
// Returns 0 if no allocation events have been recorded.
- size_t NewSpaceAllocatedBytesInLast(double time_ms) const;
+ size_t AllocatedBytesInLast(double time_ms) const;
- // Allocation throughput in the new space in bytes/milliseconds in
+ // Allocation throughput in heap in bytes/milliseconds in
// the last five seconds.
// Returns 0 if no allocation events have been recorded.
- size_t CurrentNewSpaceAllocationThroughputInBytesPerMillisecond() const;
+ size_t CurrentAllocationThroughputInBytesPerMillisecond() const;
// Computes the context disposal rate in milliseconds. It takes the time
// frame of the first recorded context disposal to the current time and
EventBuffer incremental_mark_compactor_events_;
// RingBuffer for allocation events.
+ AllocationEventBuffer new_space_allocation_events_;
AllocationEventBuffer allocation_events_;
// RingBuffer for context disposal events.
double cumulative_sweeping_duration_;
// Timestamp and allocation counter at the last sampled allocation event.
- double new_space_allocation_time_ms_;
+ double allocation_time_ms_;
size_t new_space_allocation_counter_bytes_;
+ size_t old_generation_allocation_counter_bytes_;
// Accumulated duration and allocated bytes since the last GC.
- double new_space_allocation_duration_since_gc_;
+ double allocation_duration_since_gc_;
size_t new_space_allocation_in_bytes_since_gc_;
+ size_t old_generation_allocation_in_bytes_since_gc_;
// Counts how many tracers were started without stopping.
int start_counter_;
full_codegen_bytes_generated_(0),
crankshaft_codegen_bytes_generated_(0),
new_space_allocation_counter_(0),
+ old_generation_allocation_counter_(0),
+ old_generation_size_at_last_gc_(0),
gcs_since_last_deopt_(0),
allocation_sites_scratchpad_length_(0),
promotion_queue_(this),
}
CheckNewSpaceExpansionCriteria();
UpdateNewSpaceAllocationCounter();
+ UpdateOldGenerationAllocationCounter();
}
last_gc_time_ = MonotonicallyIncreasingTimeInMs();
ReduceNewSpaceSize(
- tracer()->CurrentNewSpaceAllocationThroughputInBytesPerMillisecond());
+ tracer()->CurrentAllocationThroughputInBytesPerMillisecond());
}
Scavenge();
}
+ // This should be updated before PostGarbageCollectionProcessing, which can
+ // cause another GC.
+ old_generation_size_at_last_gc_ = PromotedSpaceSizeOfObjects();
+
UpdateSurvivalStatistics(start_new_space_size);
ConfigureInitialOldGenerationSize();
heap_state.new_space_capacity = new_space_.Capacity();
heap_state.new_space_allocation_throughput_in_bytes_per_ms =
tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond();
- heap_state.current_new_space_allocation_throughput_in_bytes_per_ms =
- tracer()->CurrentNewSpaceAllocationThroughputInBytesPerMillisecond();
+ heap_state.current_allocation_throughput_in_bytes_per_ms =
+ tracer()->CurrentAllocationThroughputInBytesPerMillisecond();
intptr_t limit = old_generation_allocation_limit_;
if (HasLowAllocationRate(
- heap_state.current_new_space_allocation_throughput_in_bytes_per_ms)) {
+ heap_state.current_allocation_throughput_in_bytes_per_ms)) {
limit = idle_old_generation_allocation_limit_;
}
heap_state.can_start_incremental_marking =
GCIdleTimeHandler::kMaxFrameRenderingIdleTime;
if (is_long_idle_notification) {
- tracer()->SampleNewSpaceAllocation(start_ms, NewSpaceAllocationCounter());
+ tracer()->SampleAllocation(start_ms, NewSpaceAllocationCounter(),
+ OldGenerationAllocationCounter());
}
GCIdleTimeHandler::HeapState heap_state = ComputeHeapState();
new_space_allocation_counter_ = new_value;
}
+ void UpdateOldGenerationAllocationCounter() {
+ old_generation_allocation_counter_ = OldGenerationAllocationCounter();
+ }
+
+ size_t OldGenerationAllocationCounter() {
+ return old_generation_allocation_counter_ + PromotedSinceLastGC();
+ }
+
+ // This should be used only for testing.
+ void set_old_generation_allocation_counter(size_t new_value) {
+ old_generation_allocation_counter_ = new_value;
+ }
+
+ size_t PromotedSinceLastGC() {
+ return PromotedSpaceSizeOfObjects() - old_generation_size_at_last_gc_;
+ }
+
// Update GC statistics that are tracked on the Heap.
void UpdateCumulativeGCStatistics(double duration, double spent_in_mutator,
double marking_time);
// NewSpaceAllocationCounter() function.
size_t new_space_allocation_counter_;
+ // This counter is increased before each GC and never reset. To
+ // account for the bytes allocated since the last GC, use the
+ // OldGenerationAllocationCounter() function.
+ size_t old_generation_allocation_counter_;
+
+ // The size of objects in old generation after the last MarkCompact GC.
+ size_t old_generation_size_at_last_gc_;
+
// If the --deopt_every_n_garbage_collections flag is set to a positive value,
// this variable holds the number of garbage collections since the last
// deoptimization triggered by garbage collection.
}
-void AllocateInNewSpace(Isolate* isolate, size_t bytes) {
+void AllocateInSpace(Isolate* isolate, size_t bytes, AllocationSpace space) {
CHECK(bytes >= FixedArray::kHeaderSize);
CHECK(bytes % kPointerSize == 0);
Factory* factory = isolate->factory();
AlwaysAllocateScope always_allocate(isolate);
int elements =
static_cast<int>((bytes - FixedArray::kHeaderSize) / kPointerSize);
- Handle<FixedArray> array = factory->NewFixedArray(elements, NOT_TENURED);
- CHECK(isolate->heap()->InNewSpace(*array));
+ Handle<FixedArray> array = factory->NewFixedArray(
+ elements, space == NEW_SPACE ? NOT_TENURED : TENURED);
+ CHECK((space == NEW_SPACE) == isolate->heap()->InNewSpace(*array));
CHECK_EQ(bytes, static_cast<size_t>(array->Size()));
}
size_t counter1 = heap->NewSpaceAllocationCounter();
heap->CollectGarbage(NEW_SPACE);
const size_t kSize = 1024;
- AllocateInNewSpace(isolate, kSize);
+ AllocateInSpace(isolate, kSize, NEW_SPACE);
size_t counter2 = heap->NewSpaceAllocationCounter();
CHECK_EQ(kSize, counter2 - counter1);
heap->CollectGarbage(NEW_SPACE);
heap->set_new_space_allocation_counter(max_counter - 10 * kSize);
size_t start = heap->NewSpaceAllocationCounter();
for (int i = 0; i < 20; i++) {
- AllocateInNewSpace(isolate, kSize);
+ AllocateInSpace(isolate, kSize, NEW_SPACE);
size_t counter = heap->NewSpaceAllocationCounter();
CHECK_EQ(kSize, counter - start);
start = counter;
}
+TEST(OldSpaceAllocationCounter) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Heap* heap = isolate->heap();
+ size_t counter1 = heap->OldGenerationAllocationCounter();
+ heap->CollectGarbage(NEW_SPACE);
+ const size_t kSize = 1024;
+ AllocateInSpace(isolate, kSize, OLD_SPACE);
+ size_t counter2 = heap->OldGenerationAllocationCounter();
+ CHECK_EQ(kSize, counter2 - counter1);
+ heap->CollectGarbage(NEW_SPACE);
+ size_t counter3 = heap->OldGenerationAllocationCounter();
+ CHECK_EQ(0, counter3 - counter2);
+ AllocateInSpace(isolate, kSize, OLD_SPACE);
+ heap->CollectGarbage(OLD_SPACE);
+ size_t counter4 = heap->OldGenerationAllocationCounter();
+ CHECK_EQ(kSize, counter4 - counter3);
+ // Test counter overflow.
+ size_t max_counter = -1;
+ heap->set_old_generation_allocation_counter(max_counter - 10 * kSize);
+ size_t start = heap->OldGenerationAllocationCounter();
+ for (int i = 0; i < 20; i++) {
+ AllocateInSpace(isolate, kSize, OLD_SPACE);
+ size_t counter = heap->OldGenerationAllocationCounter();
+ CHECK_EQ(kSize, counter - start);
+ start = counter;
+ }
+}
+
+
TEST(NewSpaceAllocationThroughput) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
GCTracer* tracer = heap->tracer();
int time1 = 100;
size_t counter1 = 1000;
- tracer->SampleNewSpaceAllocation(time1, counter1);
+ tracer->SampleAllocation(time1, counter1, 0);
int time2 = 200;
size_t counter2 = 2000;
- tracer->SampleNewSpaceAllocation(time2, counter2);
+ tracer->SampleAllocation(time2, counter2, 0);
size_t throughput =
tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
CHECK_EQ((counter2 - counter1) / (time2 - time1), throughput);
int time3 = 1000;
size_t counter3 = 30000;
- tracer->SampleNewSpaceAllocation(time3, counter3);
+ tracer->SampleAllocation(time3, counter3, 0);
throughput = tracer->NewSpaceAllocationThroughputInBytesPerMillisecond();
CHECK_EQ((counter3 - counter1) / (time3 - time1), throughput);
}
GCTracer* tracer = heap->tracer();
int time1 = 100;
size_t counter1 = 1000;
- tracer->SampleNewSpaceAllocation(time1, counter1);
+ tracer->SampleAllocation(time1, counter1, 0);
int time2 = 200;
size_t counter2 = 2000;
- tracer->SampleNewSpaceAllocation(time2, counter2);
- size_t bytes = tracer->NewSpaceAllocatedBytesInLast(1000);
+ tracer->SampleAllocation(time2, counter2, 0);
+ size_t bytes = tracer->AllocatedBytesInLast(1000);
CHECK_EQ(10000, bytes);
int time3 = 1000;
size_t counter3 = 30000;
- tracer->SampleNewSpaceAllocation(time3, counter3);
- bytes = tracer->NewSpaceAllocatedBytesInLast(100);
+ tracer->SampleAllocation(time3, counter3, 0);
+ bytes = tracer->AllocatedBytesInLast(100);
CHECK_EQ((counter3 - counter1) * 100 / (time3 - time1), bytes);
}
CompileRun(test);
}
+
+
+TEST(OldGenerationAllocationThroughput) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Heap* heap = isolate->heap();
+ GCTracer* tracer = heap->tracer();
+ int time1 = 100;
+ size_t counter1 = 1000;
+ tracer->SampleAllocation(time1, 0, counter1);
+ int time2 = 200;
+ size_t counter2 = 2000;
+ tracer->SampleAllocation(time2, 0, counter2);
+ size_t bytes = tracer->AllocatedBytesInLast(1000);
+ CHECK_EQ(10000, bytes);
+ int time3 = 1000;
+ size_t counter3 = 30000;
+ tracer->SampleAllocation(time3, 0, counter3);
+ bytes = tracer->AllocatedBytesInLast(100);
+ CHECK_EQ((counter3 - counter1) * 100 / (time3 - time1), bytes);
+}
+
+
+TEST(AllocationThroughput) {
+ CcTest::InitializeVM();
+ v8::HandleScope scope(CcTest::isolate());
+ Isolate* isolate = CcTest::i_isolate();
+ Heap* heap = isolate->heap();
+ GCTracer* tracer = heap->tracer();
+ int time1 = 100;
+ size_t counter1 = 1000;
+ tracer->SampleAllocation(time1, counter1, counter1);
+ int time2 = 200;
+ size_t counter2 = 2000;
+ tracer->SampleAllocation(time2, counter2, counter2);
+ size_t bytes = tracer->AllocatedBytesInLast(1000);
+ CHECK_EQ(20000, bytes);
+ int time3 = 1000;
+ size_t counter3 = 30000;
+ tracer->SampleAllocation(time3, counter3, counter3);
+ bytes = tracer->AllocatedBytesInLast(100);
+ CHECK_EQ(2 * (counter3 - counter1) * 100 / (time3 - time1), bytes);
+}