Commit aae81e12 authored by danno@chromium.org's avatar danno@chromium.org

Add counters that automatically track object sizes and counts.

Review URL: https://chromiumcodereview.appspot.com/10702168

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12082 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent add296dd
......@@ -1301,20 +1301,24 @@ void Shell::OnExit() {
counters[j].key = i.CurrentKey();
}
qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys);
printf("+--------------------------------------------+-------------+\n");
printf("| Name | Value |\n");
printf("+--------------------------------------------+-------------+\n");
printf("+----------------------------------------------------------------+"
"-------------+\n");
printf("| Name |"
" Value |\n");
printf("+----------------------------------------------------------------+"
"-------------+\n");
for (j = 0; j < number_of_counters; j++) {
Counter* counter = counters[j].counter;
const char* key = counters[j].key;
if (counter->is_histogram()) {
printf("| c:%-40s | %11i |\n", key, counter->count());
printf("| t:%-40s | %11i |\n", key, counter->sample_total());
printf("| c:%-60s | %11i |\n", key, counter->count());
printf("| t:%-60s | %11i |\n", key, counter->sample_total());
} else {
printf("| %-42s | %11i |\n", key, counter->count());
printf("| %-62s | %11i |\n", key, counter->count());
}
}
printf("+--------------------------------------------+-------------+\n");
printf("+----------------------------------------------------------------+"
"-------------+\n");
delete [] counters;
}
delete counters_file_;
......
......@@ -67,7 +67,7 @@ class CounterCollection {
CounterCollection();
Counter* GetNextCounter();
private:
static const unsigned kMaxCounters = 256;
static const unsigned kMaxCounters = 512;
uint32_t magic_number_;
uint32_t max_counters_;
uint32_t max_name_size_;
......
......@@ -367,6 +367,8 @@ DEFINE_bool(incremental_marking, true, "use incremental marking")
DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps")
DEFINE_bool(trace_incremental_marking, false,
"trace progress of the incremental marking")
DEFINE_bool(track_gc_object_stats, false,
"track object counts and memory usage")
// v8.cc
DEFINE_bool(use_idle_notification, true,
......
......@@ -179,6 +179,8 @@ Heap::Heap()
// Put a dummy entry in the remembered pages so we can find the list the
// minidump even if there are no real unmapped pages.
RememberUnmappedPage(NULL, false);
ClearObjectStats(true);
}
......@@ -7197,4 +7199,35 @@ void Heap::RememberUnmappedPage(Address page, bool compacted) {
remembered_unmapped_pages_index_ %= kRememberedUnmappedPages;
}
void Heap::ClearObjectStats(bool clear_last_time_stats) {
memset(object_counts_, 0, sizeof(object_counts_));
memset(object_sizes_, 0, sizeof(object_sizes_));
if (clear_last_time_stats) {
memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
}
}
static LazyMutex checkpoint_object_stats_mutex = LAZY_MUTEX_INITIALIZER;
void Heap::CheckpointObjectStats() {
ScopedLock lock(checkpoint_object_stats_mutex.Pointer());
Counters* counters = isolate()->counters();
#define ADJUST_LAST_TIME_OBJECT_COUNT(name) \
counters->count_of_##name()->Increment(object_counts_[name]); \
counters->count_of_##name()->Decrement(object_counts_last_time_[name]); \
counters->size_of_##name()->Increment(object_sizes_[name]); \
counters->size_of_##name()->Decrement(object_sizes_last_time_[name]);
INSTANCE_TYPE_LIST(ADJUST_LAST_TIME_OBJECT_COUNT)
#undef ADJUST_LAST_TIME_OBJECT_COUNT
memcpy(object_counts_last_time_, object_counts_,
sizeof(object_counts_));
memcpy(object_sizes_last_time_, object_sizes_,
sizeof(object_sizes_));
ClearObjectStats();
}
} } // namespace v8::internal
......@@ -1600,6 +1600,14 @@ class Heap {
global_ic_age_ = (global_ic_age_ + 1) & SharedFunctionInfo::ICAgeBits::kMax;
}
void RecordObjectStats(InstanceType type, size_t size) {
ASSERT(type <= LAST_TYPE);
object_counts_[type]++;
object_sizes_[type] += size;
}
void CheckpointObjectStats();
private:
Heap();
......@@ -1993,11 +2001,18 @@ class Heap {
void AdvanceIdleIncrementalMarking(intptr_t step_size);
void ClearObjectStats(bool clear_last_time_stats = false);
static const int kInitialSymbolTableSize = 2048;
static const int kInitialEvalCacheSize = 64;
static const int kInitialNumberStringCacheSize = 256;
// Object counts and used memory by InstanceType
size_t object_counts_[LAST_TYPE + 1];
size_t object_counts_last_time_[LAST_TYPE + 1];
size_t object_sizes_[LAST_TYPE + 1];
size_t object_sizes_last_time_[LAST_TYPE + 1];
// Maximum GC pause.
int max_gc_pause_;
......
......@@ -944,6 +944,17 @@ class StaticMarkingVisitor : public StaticVisitorBase {
table_.GetVisitor(map)(map, obj);
}
template<int id>
class ObjectStatsTracker {
public:
static inline void Visit(Map* map, HeapObject* obj) {
Heap* heap = map->GetHeap();
int object_size = obj->Size();
heap->RecordObjectStats(map->instance_type(), object_size);
non_count_table_.GetVisitorById(static_cast<VisitorId>(id))(map, obj);
}
};
static void Initialize() {
table_.Register(kVisitShortcutCandidate,
&FixedBodyVisitor<StaticMarkingVisitor,
......@@ -1012,6 +1023,15 @@ class StaticMarkingVisitor : public StaticVisitorBase {
table_.RegisterSpecializations<StructObjectVisitor,
kVisitStruct,
kVisitStructGeneric>();
if (FLAG_track_gc_object_stats) {
// Copy the visitor table to make call-through possible.
non_count_table_.CopyFrom(&table_);
#define VISITOR_ID_COUNT_FUNCTION(id)\
table_.Register(kVisit##id, ObjectStatsTracker<kVisit##id>::Visit);
VISITOR_ID_LIST(VISITOR_ID_COUNT_FUNCTION)
#undef VISITOR_ID_COUNT_FUNCTION
}
}
INLINE(static void VisitPointer(Heap* heap, Object** p)) {
......@@ -1557,11 +1577,14 @@ class StaticMarkingVisitor : public StaticVisitorBase {
typedef void (*Callback)(Map* map, HeapObject* object);
static VisitorDispatchTable<Callback> table_;
static VisitorDispatchTable<Callback> non_count_table_;
};
VisitorDispatchTable<StaticMarkingVisitor::Callback>
StaticMarkingVisitor::table_;
VisitorDispatchTable<StaticMarkingVisitor::Callback>
StaticMarkingVisitor::non_count_table_;
class MarkingVisitor : public ObjectVisitor {
......@@ -2437,6 +2460,10 @@ void MarkCompactCollector::AfterMarking() {
// Clean up dead objects from the runtime profiler.
heap()->isolate()->runtime_profiler()->RemoveDeadSamples();
}
if (FLAG_track_gc_object_stats) {
heap()->CheckpointObjectStats();
}
}
......
......@@ -46,71 +46,70 @@ namespace internal {
// Base class for all static visitors.
class StaticVisitorBase : public AllStatic {
public:
#define VISITOR_ID_LIST(V) \
V(SeqAsciiString) \
V(SeqTwoByteString) \
V(ShortcutCandidate) \
V(ByteArray) \
V(FreeSpace) \
V(FixedArray) \
V(FixedDoubleArray) \
V(GlobalContext) \
V(DataObject2) \
V(DataObject3) \
V(DataObject4) \
V(DataObject5) \
V(DataObject6) \
V(DataObject7) \
V(DataObject8) \
V(DataObject9) \
V(DataObjectGeneric) \
V(JSObject2) \
V(JSObject3) \
V(JSObject4) \
V(JSObject5) \
V(JSObject6) \
V(JSObject7) \
V(JSObject8) \
V(JSObject9) \
V(JSObjectGeneric) \
V(Struct2) \
V(Struct3) \
V(Struct4) \
V(Struct5) \
V(Struct6) \
V(Struct7) \
V(Struct8) \
V(Struct9) \
V(StructGeneric) \
V(ConsString) \
V(SlicedString) \
V(Oddball) \
V(Code) \
V(Map) \
V(PropertyCell) \
V(SharedFunctionInfo) \
V(JSFunction) \
V(JSWeakMap) \
V(JSRegExp)
// For data objects, JS objects and structs along with generic visitor which
// can visit object of any size we provide visitors specialized by
// object size in words.
// Ids of specialized visitors are declared in a linear order (without
// holes) starting from the id of visitor specialized for 2 words objects
// (base visitor id) and ending with the id of generic visitor.
// Method GetVisitorIdForSize depends on this ordering to calculate visitor
// id of specialized visitor from given instance size, base visitor id and
// generic visitor's id.
enum VisitorId {
kVisitSeqAsciiString = 0,
kVisitSeqTwoByteString,
kVisitShortcutCandidate,
kVisitByteArray,
kVisitFreeSpace,
kVisitFixedArray,
kVisitFixedDoubleArray,
kVisitGlobalContext,
// For data objects, JS objects and structs along with generic visitor which
// can visit object of any size we provide visitors specialized by
// object size in words.
// Ids of specialized visitors are declared in a linear order (without
// holes) starting from the id of visitor specialized for 2 words objects
// (base visitor id) and ending with the id of generic visitor.
// Method GetVisitorIdForSize depends on this ordering to calculate visitor
// id of specialized visitor from given instance size, base visitor id and
// generic visitor's id.
kVisitDataObject,
kVisitDataObject2 = kVisitDataObject,
kVisitDataObject3,
kVisitDataObject4,
kVisitDataObject5,
kVisitDataObject6,
kVisitDataObject7,
kVisitDataObject8,
kVisitDataObject9,
kVisitDataObjectGeneric,
kVisitJSObject,
kVisitJSObject2 = kVisitJSObject,
kVisitJSObject3,
kVisitJSObject4,
kVisitJSObject5,
kVisitJSObject6,
kVisitJSObject7,
kVisitJSObject8,
kVisitJSObject9,
kVisitJSObjectGeneric,
kVisitStruct,
kVisitStruct2 = kVisitStruct,
kVisitStruct3,
kVisitStruct4,
kVisitStruct5,
kVisitStruct6,
kVisitStruct7,
kVisitStruct8,
kVisitStruct9,
kVisitStructGeneric,
kVisitConsString,
kVisitSlicedString,
kVisitOddball,
kVisitCode,
kVisitMap,
kVisitPropertyCell,
kVisitSharedFunctionInfo,
kVisitJSFunction,
kVisitJSWeakMap,
kVisitJSRegExp,
#define VISITOR_ID_ENUM_DECL(id) kVisit##id,
VISITOR_ID_LIST(VISITOR_ID_ENUM_DECL)
#undef VISITOR_ID_ENUM_DECL
kVisitorIdCount,
kVisitDataObject = kVisitDataObject2,
kVisitJSObject = kVisitJSObject2,
kVisitStruct = kVisitStruct2,
kMinObjectSizeInWords = 2
};
......
......@@ -53,6 +53,14 @@ Counters::Counters() {
STATS_COUNTER_LIST_2(SC)
#undef SC
#define SC(name) \
StatsCounter count_of_##name = { "c:" "V8.CountOf_" #name, NULL, false };\
count_of_##name##_ = count_of_##name; \
StatsCounter size_of_##name = { "c:" "V8.SizeOf_" #name, NULL, false };\
size_of_##name##_ = size_of_##name;
INSTANCE_TYPE_LIST(SC)
#undef SC
StatsCounter state_counters[] = {
#define COUNTER_NAME(name) \
{ "c:V8.State" #name, NULL, false },
......
......@@ -30,6 +30,7 @@
#include "allocation.h"
#include "counters.h"
#include "objects.h"
#include "v8globals.h"
namespace v8 {
......@@ -308,6 +309,12 @@ class Counters {
STATS_COUNTER_LIST_2(SC)
#undef SC
#define SC(name) \
StatsCounter* count_of_##name() { return &count_of_##name##_; } \
StatsCounter* size_of_##name() { return &size_of_##name##_; }
INSTANCE_TYPE_LIST(SC)
#undef SC
enum Id {
#define RATE_ID(name, caption) k_##name,
HISTOGRAM_TIMER_LIST(RATE_ID)
......@@ -319,6 +326,9 @@ class Counters {
STATS_COUNTER_LIST_1(COUNTER_ID)
STATS_COUNTER_LIST_2(COUNTER_ID)
#undef COUNTER_ID
#define COUNTER_ID(name) kCountOf##name, kSizeOf##name,
INSTANCE_TYPE_LIST(COUNTER_ID)
#undef COUNTER_ID
#define COUNTER_ID(name) k_##name,
STATE_TAG_LIST(COUNTER_ID)
#undef COUNTER_ID
......@@ -346,6 +356,12 @@ class Counters {
STATS_COUNTER_LIST_2(SC)
#undef SC
#define SC(name) \
StatsCounter size_of_##name##_; \
StatsCounter count_of_##name##_;
INSTANCE_TYPE_LIST(SC)
#undef SC
enum {
#define COUNTER_ID(name) __##name,
STATE_TAG_LIST(COUNTER_ID)
......
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