Commit 70e2a040 authored by ernstm@chromium.org's avatar ernstm@chromium.org

Move GCTracer to separate files.

- No functional changes.

R=hpayer@chromium.org
BUG=

Review URL: https://codereview.chromium.org/416543003

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22600 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 29338fa1
......@@ -543,6 +543,8 @@ source_set("v8_base") {
"src/full-codegen.h",
"src/func-name-inferrer.cc",
"src/func-name-inferrer.h",
"src/gc-tracer.cc",
"src/gc-tracer.h",
"src/gdb-jit.cc",
"src/gdb-jit.h",
"src/global-handles.cc",
......
// 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"
#include "src/gc-tracer.h"
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;
}
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),
incremental_marking_steps(0),
incremental_marking_duration(0.0) {
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:
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),
incremental_marking_steps_(0),
incremental_marking_duration_(0.0),
longest_incremental_marking_step_(0.0) {
current_ = Event(Event::START, NULL, NULL);
current_.end_time = base::OS::TimeCurrentMillis();
previous_ = previous_mark_compactor_event_ = current_;
}
void GCTracer::Start(GarbageCollector collector, const char* gc_reason,
const char* collector_reason) {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
previous_ = current_;
if (current_.type == Event::MARK_COMPACTOR)
previous_mark_compactor_event_ = current_;
if (collector == SCAVENGER) {
current_ = Event(Event::SCAVENGER, gc_reason, collector_reason);
} else {
current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
}
current_.start_time = base::OS::TimeCurrentMillis();
current_.start_object_size = heap_->SizeOfObjects();
current_.start_memory_size = heap_->isolate()->memory_allocator()->Size();
current_.start_holes_size = CountTotalHolesSize(heap_);
current_.incremental_marking_steps = incremental_marking_steps_;
current_.incremental_marking_duration = incremental_marking_duration_;
current_.longest_incremental_marking_step = longest_incremental_marking_step_;
for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
current_.scopes[i] = 0;
}
}
void GCTracer::Stop() {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
current_.end_time = base::OS::TimeCurrentMillis();
current_.end_object_size = heap_->SizeOfObjects();
current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
current_.end_holes_size = CountTotalHolesSize(heap_);
if (current_.type == Event::SCAVENGER) {
scavenger_events_.push_front(current_);
} else {
mark_compactor_events_.push_front(current_);
}
if (current_.type == Event::MARK_COMPACTOR)
longest_incremental_marking_step_ = 0.0;
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();
}
}
void GCTracer::AddIncrementalMarkingStep(double duration) {
incremental_marking_steps_++;
incremental_marking_duration_ += duration;
longest_incremental_marking_step_ =
Max(longest_incremental_marking_step_, duration);
}
void GCTracer::Print() const {
PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
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) {
int steps = current_.incremental_marking_steps -
previous_.incremental_marking_steps;
if (steps > 0) {
PrintF(" (+ %.1f ms in %d steps since last GC)",
current_.incremental_marking_duration -
previous_.incremental_marking_duration,
steps);
}
} else {
int steps = current_.incremental_marking_steps -
previous_mark_compactor_event_.incremental_marking_steps;
if (steps > 0) {
PrintF(
" (+ %.1f ms in %d steps since start of marking, "
"biggest step %.1f ms)",
current_.incremental_marking_duration -
previous_mark_compactor_event_.incremental_marking_duration,
steps, current_.longest_incremental_marking_step);
}
}
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 {
PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
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]);
PrintF("weakcollection_process=%.1f ",
current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]);
PrintF("weakcollection_clear=%.1f ",
current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]);
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_);
PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_);
PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_);
if (current_.type == Event::SCAVENGER) {
PrintF("stepscount=%d ", current_.incremental_marking_steps -
previous_.incremental_marking_steps);
PrintF("stepstook=%.1f ", current_.incremental_marking_duration -
previous_.incremental_marking_duration);
} else {
PrintF("stepscount=%d ",
current_.incremental_marking_steps -
previous_mark_compactor_event_.incremental_marking_steps);
PrintF("stepstook=%.1f ",
current_.incremental_marking_duration -
previous_mark_compactor_event_.incremental_marking_duration);
PrintF("longeststep=%.1f ", current_.longest_incremental_marking_step);
}
PrintF("\n");
}
}
} // namespace v8::internal
// 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.
#ifndef V8_GC_TRACER_H_
#define V8_GC_TRACER_H_
namespace v8 {
namespace internal {
// A simple ring buffer class with maximum size known at compile time.
// The class only implements the functionality required in GCTracer.
template <typename T, size_t MAX_SIZE>
class RingBuffer {
public:
class const_iterator {
public:
const_iterator() : index_(0), elements_(NULL) {}
const_iterator(size_t index, const T* elements)
: index_(index), elements_(elements) {}
bool operator==(const const_iterator& rhs) const {
return elements_ == rhs.elements_ && index_ == rhs.index_;
}
bool operator!=(const const_iterator& rhs) const {
return elements_ != rhs.elements_ || index_ != rhs.index_;
}
operator const T*() const { return elements_ + index_; }
const T* operator->() const { return elements_ + index_; }
const T& operator*() const { return elements_[index_]; }
const_iterator& operator++() {
index_ = (index_ + 1) % (MAX_SIZE + 1);
return *this;
}
const_iterator& operator--() {
index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1);
return *this;
}
private:
size_t index_;
const T* elements_;
};
RingBuffer() : begin_(0), end_(0) {}
bool empty() const { return begin_ == end_; }
size_t size() const {
return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
}
const_iterator begin() const { return const_iterator(begin_, elements_); }
const_iterator end() const { return const_iterator(end_, elements_); }
const_iterator back() const { return --end(); }
void push_back(const T& element) {
elements_[end_] = element;
end_ = (end_ + 1) % (MAX_SIZE + 1);
if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1);
}
void push_front(const T& element) {
begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1);
if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1);
elements_[begin_] = element;
}
private:
T elements_[MAX_SIZE + 1];
size_t begin_;
size_t end_;
DISALLOW_COPY_AND_ASSIGN(RingBuffer);
};
// GCTracer collects and prints ONE line after each garbage collector
// invocation IFF --trace_gc is used.
// TODO(ernstm): Unit tests.
class GCTracer BASE_EMBEDDED {
public:
class Scope BASE_EMBEDDED {
public:
enum ScopeId {
EXTERNAL,
MC_MARK,
MC_SWEEP,
MC_SWEEP_NEWSPACE,
MC_SWEEP_OLDSPACE,
MC_SWEEP_CODE,
MC_SWEEP_CELL,
MC_SWEEP_MAP,
MC_EVACUATE_PAGES,
MC_UPDATE_NEW_TO_NEW_POINTERS,
MC_UPDATE_ROOT_TO_NEW_POINTERS,
MC_UPDATE_OLD_TO_NEW_POINTERS,
MC_UPDATE_POINTERS_TO_EVACUATED,
MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
MC_UPDATE_MISC_POINTERS,
MC_WEAKCOLLECTION_PROCESS,
MC_WEAKCOLLECTION_CLEAR,
MC_FLUSH_CODE,
NUMBER_OF_SCOPES
};
Scope(GCTracer* tracer, ScopeId scope) : tracer_(tracer), scope_(scope) {
start_time_ = base::OS::TimeCurrentMillis();
}
~Scope() {
ASSERT(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
tracer_->current_.scopes[scope_] +=
base::OS::TimeCurrentMillis() - start_time_;
}
private:
GCTracer* tracer_;
ScopeId scope_;
double start_time_;
DISALLOW_COPY_AND_ASSIGN(Scope);
};
class Event {
public:
enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 };
// Default constructor leaves the event uninitialized.
Event() {}
Event(Type type, const char* gc_reason, const char* collector_reason);
// Returns a string describing the event type.
const char* TypeName(bool short_name) const;
// Type of event
Type type;
const char* gc_reason;
const char* collector_reason;
// Timestamp set in the constructor.
double start_time;
// Timestamp set in the destructor.
double end_time;
// Size of objects in heap set in constructor.
intptr_t start_object_size;
// Size of objects in heap set in destructor.
intptr_t end_object_size;
// Size of memory allocated from OS set in constructor.
intptr_t start_memory_size;
// Size of memory allocated from OS set in destructor.
intptr_t end_memory_size;
// Total amount of space either wasted or contained in one of free lists
// before the current GC.
intptr_t start_holes_size;
// Total amount of space either wasted or contained in one of free lists
// after the current GC.
intptr_t end_holes_size;
// Number of incremental marking steps since creation of tracer.
// (value at start of event)
int incremental_marking_steps;
// Cumulative duration of incremental marking steps since creation of
// tracer. (value at start of event)
double incremental_marking_duration;
// Longest incremental marking step since start of marking.
// (value at start of event)
double longest_incremental_marking_step;
// Amounts of time spent in different scopes during GC.
double scopes[Scope::NUMBER_OF_SCOPES];
};
static const int kRingBufferMaxSize = 10;
typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
explicit GCTracer(Heap* heap);
// Start collecting data.
void Start(GarbageCollector collector, const char* gc_reason,
const char* collector_reason);
// Stop collecting data and print results.
void Stop();
// Log an incremental marking step.
void AddIncrementalMarkingStep(double duration);
private:
// Print one detailed trace line in name=value format.
// TODO(ernstm): Move to Heap.
void PrintNVP() const;
// Print one trace line.
// TODO(ernstm): Move to Heap.
void Print() const;
// Pointer to the heap that owns this tracer.
Heap* heap_;
// Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
// has returned.
Event current_;
// Previous tracer event.
Event previous_;
// Previous MARK_COMPACTOR event.
Event previous_mark_compactor_event_;
// RingBuffers for SCAVENGER events.
EventBuffer scavenger_events_;
// RingBuffers for MARK_COMPACTOR events.
EventBuffer mark_compactor_events_;
// Cumulative number of incremental marking steps since creation of tracer.
int incremental_marking_steps_;
// Cumulative duration of incremental marking steps since creation of tracer.
double incremental_marking_duration_;
// Longest incremental marking step since start of marking.
double longest_incremental_marking_step_;
DISALLOW_COPY_AND_ASSIGN(GCTracer);
};
}
} // namespace v8::internal
#endif // V8_GC_TRACER_H_
......@@ -5955,18 +5955,6 @@ void Heap::TracePathToGlobal() {
#endif
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;
}
void Heap::UpdateCumulativeGCStatistics(double duration,
double spent_in_mutator,
double marking_time) {
......@@ -5983,257 +5971,6 @@ void Heap::UpdateCumulativeGCStatistics(double duration,
}
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),
incremental_marking_steps(0),
incremental_marking_duration(0.0) {
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:
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),
incremental_marking_steps_(0),
incremental_marking_duration_(0.0),
longest_incremental_marking_step_(0.0) {
current_ = Event(Event::START, NULL, NULL);
current_.end_time = base::OS::TimeCurrentMillis();
previous_ = previous_mark_compactor_event_ = current_;
}
void GCTracer::Start(GarbageCollector collector, const char* gc_reason,
const char* collector_reason) {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
previous_ = current_;
if (current_.type == Event::MARK_COMPACTOR)
previous_mark_compactor_event_ = current_;
if (collector == SCAVENGER) {
current_ = Event(Event::SCAVENGER, gc_reason, collector_reason);
} else {
current_ = Event(Event::MARK_COMPACTOR, gc_reason, collector_reason);
}
current_.start_time = base::OS::TimeCurrentMillis();
current_.start_object_size = heap_->SizeOfObjects();
current_.start_memory_size = heap_->isolate()->memory_allocator()->Size();
current_.start_holes_size = CountTotalHolesSize(heap_);
current_.incremental_marking_steps = incremental_marking_steps_;
current_.incremental_marking_duration = incremental_marking_duration_;
current_.longest_incremental_marking_step = longest_incremental_marking_step_;
for (int i = 0; i < Scope::NUMBER_OF_SCOPES; i++) {
current_.scopes[i] = 0;
}
}
void GCTracer::Stop() {
if (!FLAG_trace_gc && !FLAG_print_cumulative_gc_stat) return;
current_.end_time = base::OS::TimeCurrentMillis();
current_.end_object_size = heap_->SizeOfObjects();
current_.end_memory_size = heap_->isolate()->memory_allocator()->Size();
current_.end_holes_size = CountTotalHolesSize(heap_);
if (current_.type == Event::SCAVENGER) {
scavenger_events_.push_front(current_);
} else {
mark_compactor_events_.push_front(current_);
}
if (current_.type == Event::MARK_COMPACTOR)
longest_incremental_marking_step_ = 0.0;
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();
}
}
void GCTracer::AddIncrementalMarkingStep(double duration) {
incremental_marking_steps_++;
incremental_marking_duration_ += duration;
longest_incremental_marking_step_ =
Max(longest_incremental_marking_step_, duration);
}
void GCTracer::Print() const {
PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
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) {
int steps = current_.incremental_marking_steps -
previous_.incremental_marking_steps;
if (steps > 0) {
PrintF(" (+ %.1f ms in %d steps since last GC)",
current_.incremental_marking_duration -
previous_.incremental_marking_duration,
steps);
}
} else {
int steps = current_.incremental_marking_steps -
previous_mark_compactor_event_.incremental_marking_steps;
if (steps > 0) {
PrintF(
" (+ %.1f ms in %d steps since start of marking, "
"biggest step %.1f ms)",
current_.incremental_marking_duration -
previous_mark_compactor_event_.incremental_marking_duration,
steps, current_.longest_incremental_marking_step);
}
}
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 {
PrintPID("%8.0f ms: ", heap_->isolate()->time_millis_since_init());
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]);
PrintF("weakcollection_process=%.1f ",
current_.scopes[Scope::MC_WEAKCOLLECTION_PROCESS]);
PrintF("weakcollection_clear=%.1f ",
current_.scopes[Scope::MC_WEAKCOLLECTION_CLEAR]);
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_);
PrintF("promotion_rate=%.1f%% ", heap_->promotion_rate_);
PrintF("semi_space_copy_rate=%.1f%% ", heap_->semi_space_copied_rate_);
if (current_.type == Event::SCAVENGER) {
PrintF("stepscount=%d ", current_.incremental_marking_steps -
previous_.incremental_marking_steps);
PrintF("stepstook=%.1f ", current_.incremental_marking_duration -
previous_.incremental_marking_duration);
} else {
PrintF("stepscount=%d ",
current_.incremental_marking_steps -
previous_mark_compactor_event_.incremental_marking_steps);
PrintF("stepstook=%.1f ",
current_.incremental_marking_duration -
previous_mark_compactor_event_.incremental_marking_duration);
PrintF("longeststep=%.1f ", current_.longest_incremental_marking_step);
}
PrintF("\n");
}
int KeyedLookupCache::Hash(Handle<Map> map, Handle<Name> name) {
DisallowHeapAllocation no_gc;
// Uses only lower 32 bits if pointers are larger.
......
......@@ -10,6 +10,7 @@
#include "src/allocation.h"
#include "src/assert-scope.h"
#include "src/counters.h"
#include "src/gc-tracer.h"
#include "src/globals.h"
#include "src/incremental-marking.h"
#include "src/list.h"
......@@ -547,244 +548,6 @@ enum ArrayStorageAllocationMode {
INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
};
// TODO(ernstm): Move into GCTracer.
// A simple ring buffer class with maximum size known at compile time.
// The class only implements the functionality required in GCTracer.
template <typename T, size_t MAX_SIZE>
class RingBuffer {
public:
class const_iterator {
public:
const_iterator() : index_(0), elements_(NULL) {}
const_iterator(size_t index, const T* elements)
: index_(index), elements_(elements) {}
bool operator==(const const_iterator& rhs) const {
return elements_ == rhs.elements_ && index_ == rhs.index_;
}
bool operator!=(const const_iterator& rhs) const {
return elements_ != rhs.elements_ || index_ != rhs.index_;
}
operator const T*() const { return elements_ + index_; }
const T* operator->() const { return elements_ + index_; }
const T& operator*() const { return elements_[index_]; }
const_iterator& operator++() {
index_ = (index_ + 1) % (MAX_SIZE + 1);
return *this;
}
const_iterator& operator--() {
index_ = (index_ + MAX_SIZE) % (MAX_SIZE + 1);
return *this;
}
private:
size_t index_;
const T* elements_;
};
RingBuffer() : begin_(0), end_(0) {}
bool empty() const { return begin_ == end_; }
size_t size() const {
return (end_ - begin_ + MAX_SIZE + 1) % (MAX_SIZE + 1);
}
const_iterator begin() const { return const_iterator(begin_, elements_); }
const_iterator end() const { return const_iterator(end_, elements_); }
const_iterator back() const { return --end(); }
void push_back(const T& element) {
elements_[end_] = element;
end_ = (end_ + 1) % (MAX_SIZE + 1);
if (end_ == begin_) begin_ = (begin_ + 1) % (MAX_SIZE + 1);
}
void push_front(const T& element) {
begin_ = (begin_ + MAX_SIZE) % (MAX_SIZE + 1);
if (begin_ == end_) end_ = (end_ + MAX_SIZE) % (MAX_SIZE + 1);
elements_[begin_] = element;
}
private:
T elements_[MAX_SIZE + 1];
size_t begin_;
size_t end_;
DISALLOW_COPY_AND_ASSIGN(RingBuffer);
};
// GCTracer collects and prints ONE line after each garbage collector
// invocation IFF --trace_gc is used.
// TODO(ernstm): Unit tests. Move to separate file.
class GCTracer BASE_EMBEDDED {
public:
class Scope BASE_EMBEDDED {
public:
enum ScopeId {
EXTERNAL,
MC_MARK,
MC_SWEEP,
MC_SWEEP_NEWSPACE,
MC_SWEEP_OLDSPACE,
MC_SWEEP_CODE,
MC_SWEEP_CELL,
MC_SWEEP_MAP,
MC_EVACUATE_PAGES,
MC_UPDATE_NEW_TO_NEW_POINTERS,
MC_UPDATE_ROOT_TO_NEW_POINTERS,
MC_UPDATE_OLD_TO_NEW_POINTERS,
MC_UPDATE_POINTERS_TO_EVACUATED,
MC_UPDATE_POINTERS_BETWEEN_EVACUATED,
MC_UPDATE_MISC_POINTERS,
MC_WEAKCOLLECTION_PROCESS,
MC_WEAKCOLLECTION_CLEAR,
MC_FLUSH_CODE,
NUMBER_OF_SCOPES
};
Scope(GCTracer* tracer, ScopeId scope)
: tracer_(tracer),
scope_(scope) {
start_time_ = base::OS::TimeCurrentMillis();
}
~Scope() {
ASSERT(scope_ < NUMBER_OF_SCOPES); // scope_ is unsigned.
tracer_->current_.scopes[scope_] +=
base::OS::TimeCurrentMillis() - start_time_;
}
private:
GCTracer* tracer_;
ScopeId scope_;
double start_time_;
DISALLOW_COPY_AND_ASSIGN(Scope);
};
class Event {
public:
enum Type { SCAVENGER = 0, MARK_COMPACTOR = 1, START = 2 };
// Default constructor leaves the event uninitialized.
Event() {}
Event(Type type, const char* gc_reason, const char* collector_reason);
// Returns a string describing the event type.
const char* TypeName(bool short_name) const;
// Type of event
Type type;
const char* gc_reason;
const char* collector_reason;
// Timestamp set in the constructor.
double start_time;
// Timestamp set in the destructor.
double end_time;
// Size of objects in heap set in constructor.
intptr_t start_object_size;
// Size of objects in heap set in destructor.
intptr_t end_object_size;
// Size of memory allocated from OS set in constructor.
intptr_t start_memory_size;
// Size of memory allocated from OS set in destructor.
intptr_t end_memory_size;
// Total amount of space either wasted or contained in one of free lists
// before the current GC.
intptr_t start_holes_size;
// Total amount of space either wasted or contained in one of free lists
// after the current GC.
intptr_t end_holes_size;
// Number of incremental marking steps since creation of tracer.
// (value at start of event)
int incremental_marking_steps;
// Cumulative duration of incremental marking steps since creation of
// tracer. (value at start of event)
double incremental_marking_duration;
// Longest incremental marking step since start of marking.
// (value at start of event)
double longest_incremental_marking_step;
// Amounts of time spent in different scopes during GC.
double scopes[Scope::NUMBER_OF_SCOPES];
};
static const int kRingBufferMaxSize = 10;
typedef RingBuffer<Event, kRingBufferMaxSize> EventBuffer;
explicit GCTracer(Heap* heap);
// Start collecting data.
void Start(GarbageCollector collector, const char* gc_reason,
const char* collector_reason);
// Stop collecting data and print results.
void Stop();
// Log an incremental marking step.
void AddIncrementalMarkingStep(double duration);
private:
// Print one detailed trace line in name=value format.
// TODO(ernstm): Move to Heap.
void PrintNVP() const;
// Print one trace line.
// TODO(ernstm): Move to Heap.
void Print() const;
// Pointer to the heap that owns this tracer.
Heap* heap_;
// Current tracer event. Populated during Start/Stop cycle. Valid after Stop()
// has returned.
Event current_;
// Previous tracer event.
Event previous_;
// Previous MARK_COMPACTOR event.
Event previous_mark_compactor_event_;
// RingBuffers for SCAVENGER events.
EventBuffer scavenger_events_;
// RingBuffers for MARK_COMPACTOR events.
EventBuffer mark_compactor_events_;
// Cumulative number of incremental marking steps since creation of tracer.
int incremental_marking_steps_;
// Cumulative duration of incremental marking steps since creation of tracer.
double incremental_marking_duration_;
// Longest incremental marking step since start of marking.
double longest_incremental_marking_step_;
DISALLOW_COPY_AND_ASSIGN(GCTracer);
};
class Heap {
public:
......
......@@ -443,6 +443,8 @@
'../../src/full-codegen.h',
'../../src/func-name-inferrer.cc',
'../../src/func-name-inferrer.h',
'../../src/gc-tracer.cc',
'../../src/gc-tracer.h',
'../../src/gdb-jit.cc',
'../../src/gdb-jit.h',
'../../src/global-handles.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment