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
This commit is contained in:
parent
add296dd43
commit
aae81e125b
18
src/d8.cc
18
src/d8.cc
@ -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_;
|
||||
|
2
src/d8.h
2
src/d8.h
@ -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,
|
||||
|
33
src/heap.cc
33
src/heap.cc
@ -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
|
||||
|
15
src/heap.h
15
src/heap.h
@ -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,15 +46,52 @@ namespace internal {
|
||||
// Base class for all static visitors.
|
||||
class StaticVisitorBase : public AllStatic {
|
||||
public:
|
||||
enum VisitorId {
|
||||
kVisitSeqAsciiString = 0,
|
||||
kVisitSeqTwoByteString,
|
||||
kVisitShortcutCandidate,
|
||||
kVisitByteArray,
|
||||
kVisitFreeSpace,
|
||||
kVisitFixedArray,
|
||||
kVisitFixedDoubleArray,
|
||||
kVisitGlobalContext,
|
||||
#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
|
||||
@ -65,52 +102,14 @@ class StaticVisitorBase : public AllStatic {
|
||||
// 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,
|
||||
|
||||
enum VisitorId {
|
||||
#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)
|
||||
|
Loading…
Reference in New Issue
Block a user