Index: runtime/vm/class_table.cc |
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc |
index e85053a6d9cf5eb652c9f35946ae7343a929f40e..46965376694d6e082f643353603da735d1f7394d 100644 |
--- a/runtime/vm/class_table.cc |
+++ b/runtime/vm/class_table.cc |
@@ -5,6 +5,7 @@ |
#include "vm/class_table.h" |
#include "vm/flags.h" |
#include "vm/freelist.h" |
+#include "vm/heap.h" |
#include "vm/object.h" |
#include "vm/raw_object.h" |
#include "vm/visitor.h" |
@@ -14,7 +15,9 @@ namespace dart { |
DEFINE_FLAG(bool, print_class_table, false, "Print initial class table."); |
ClassTable::ClassTable() |
- : top_(kNumPredefinedCids), capacity_(0), table_(NULL) { |
+ : top_(kNumPredefinedCids), capacity_(0), table_(NULL), |
+ class_heap_stats_table_(NULL), |
+ predefined_class_heap_stats_table_(NULL) { |
if (Dart::vm_isolate() == NULL) { |
capacity_ = initial_capacity_; |
table_ = reinterpret_cast<RawClass**>( |
@@ -31,12 +34,24 @@ ClassTable::ClassTable() |
table_[kFreeListElement] = vm_class_table->At(kFreeListElement); |
table_[kDynamicCid] = vm_class_table->At(kDynamicCid); |
table_[kVoidCid] = vm_class_table->At(kVoidCid); |
+ class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>( |
+ calloc(capacity_, sizeof(ClassHeapStats))); // NOLINT |
+ for (intptr_t i = 0; i < capacity_; i++) { |
+ class_heap_stats_table_[i].Initialize(); |
+ } |
+ } |
+ predefined_class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>( |
+ calloc(kNumPredefinedCids, sizeof(ClassHeapStats))); // NOLINT |
+ for (intptr_t i = 0; i < kNumPredefinedCids; i++) { |
+ predefined_class_heap_stats_table_[i].Initialize(); |
} |
} |
ClassTable::~ClassTable() { |
free(table_); |
+ free(predefined_class_heap_stats_table_); |
+ free(class_heap_stats_table_); |
} |
@@ -62,11 +77,16 @@ void ClassTable::Register(const Class& cls) { |
intptr_t new_capacity = capacity_ + capacity_increment_; |
RawClass** new_table = reinterpret_cast<RawClass**>( |
realloc(table_, new_capacity * sizeof(RawClass*))); // NOLINT |
+ ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>( |
+ realloc(class_heap_stats_table_, |
+ new_capacity * sizeof(ClassHeapStats))); // NOLINT |
for (intptr_t i = capacity_; i < new_capacity; i++) { |
new_table[i] = NULL; |
+ new_stats_table[i].Initialize(); |
} |
capacity_ = new_capacity; |
table_ = new_table; |
+ class_heap_stats_table_ = new_stats_table; |
} |
ASSERT(top_ < capacity_); |
cls.set_id(top_); |
@@ -111,4 +131,213 @@ void ClassTable::PrintToJSONStream(JSONStream* stream) { |
} |
} |
+ |
+void ClassHeapStats::Initialize() { |
+ allocated_before_gc_old_space = 0; |
+ allocated_before_gc_new_space = 0; |
+ allocated_size_before_gc_old_space = 0; |
+ allocated_size_before_gc_new_space = 0; |
+ live_after_gc_old_space = 0; |
+ live_after_gc_new_space = 0; |
+ live_size_after_gc_old_space = 0; |
+ live_size_after_gc_new_space = 0; |
+ allocated_since_gc_new_space = 0; |
+ allocated_since_gc_old_space = 0; |
+ allocated_size_since_gc_new_space = 0; |
+ allocated_size_since_gc_old_space = 0; |
+} |
+ |
+ |
+void ClassHeapStats::ResetAtNewGC() { |
+ allocated_before_gc_new_space = live_after_gc_new_space + |
+ allocated_since_gc_new_space; |
+ allocated_size_before_gc_new_space = live_size_after_gc_new_space + |
+ allocated_size_since_gc_new_space; |
+ live_after_gc_new_space = 0; |
+ live_size_after_gc_new_space = 0; |
+ allocated_since_gc_new_space = 0; |
+ allocated_size_since_gc_new_space = 0; |
+} |
+ |
+ |
+void ClassHeapStats::ResetAtOldGC() { |
+ allocated_before_gc_old_space = live_after_gc_old_space + |
+ allocated_since_gc_old_space; |
+ allocated_size_before_gc_old_space = live_size_after_gc_old_space + |
+ allocated_size_since_gc_old_space; |
+ live_after_gc_old_space = 0; |
+ live_size_after_gc_old_space = 0; |
+ allocated_since_gc_old_space = 0; |
+ allocated_size_since_gc_old_space = 0; |
+} |
+ |
+ |
+void ClassHeapStats::UpdateSize(intptr_t instance_size) { |
+ ASSERT(instance_size > 0); |
+ // For classes with fixed instance size we do not emit code to update |
+ // the size statistics. Update them here. |
+ allocated_size_before_gc_old_space = |
+ allocated_before_gc_old_space * instance_size; |
+ allocated_size_before_gc_new_space = |
+ allocated_before_gc_new_space * instance_size; |
+ live_size_after_gc_old_space = |
+ live_after_gc_old_space * instance_size; |
+ live_size_after_gc_new_space = |
+ live_after_gc_new_space * instance_size; |
+ allocated_size_since_gc_new_space = |
+ allocated_since_gc_new_space * instance_size; |
+ allocated_size_since_gc_old_space = |
+ allocated_since_gc_old_space * instance_size; |
+} |
+ |
+ |
+void ClassHeapStats::PrintTOJSONArray(const Class& cls, JSONArray* array) { |
+ JSONObject obj(array); |
+ obj.AddProperty("type", "ClassHeapStats"); |
+ obj.AddProperty("class", cls); |
+ { |
+ JSONArray new_stats(&obj, "new"); |
+ new_stats.AddValue(allocated_before_gc_new_space); |
+ new_stats.AddValue(allocated_size_before_gc_new_space); |
+ new_stats.AddValue(live_after_gc_new_space); |
+ new_stats.AddValue(live_size_after_gc_new_space); |
+ new_stats.AddValue(allocated_since_gc_new_space); |
+ new_stats.AddValue(allocated_size_since_gc_new_space); |
+ } |
+ { |
+ JSONArray old_stats(&obj, "old"); |
+ old_stats.AddValue(allocated_before_gc_old_space); |
+ old_stats.AddValue(allocated_size_before_gc_old_space); |
+ old_stats.AddValue(live_after_gc_old_space); |
+ old_stats.AddValue(live_size_after_gc_old_space); |
+ old_stats.AddValue(allocated_since_gc_old_space); |
+ old_stats.AddValue(allocated_size_since_gc_old_space); |
+ } |
+} |
+ |
+ |
+void ClassTable::UpdateAllocatedNew(intptr_t cid, intptr_t size) { |
+ ClassHeapStats* stats = StatsAt(cid); |
+ ASSERT(stats != NULL); |
+ ASSERT(size != 0); |
+ stats->allocated_since_gc_new_space++; |
+ stats->allocated_size_since_gc_new_space += size; |
+} |
+ |
+ |
+void ClassTable::UpdateAllocatedOld(intptr_t cid, intptr_t size) { |
+ ClassHeapStats* stats = StatsAt(cid); |
+ ASSERT(stats != NULL); |
+ ASSERT(size != 0); |
+ stats->allocated_since_gc_old_space++; |
+ stats->allocated_size_since_gc_old_space += size; |
+} |
+ |
+ |
+bool ClassTable::ShouldUpdateSizeForClassId(intptr_t cid) { |
+ return !RawObject::IsVariableSizeClassId(cid); |
+} |
+ |
+ |
+ClassHeapStats* ClassTable::StatsAt(intptr_t cid) { |
+ ASSERT(cid > 0); |
+ if (cid < kNumPredefinedCids) { |
+ return &predefined_class_heap_stats_table_[cid]; |
+ } |
+ ASSERT(cid < top_); |
+ return &class_heap_stats_table_[cid]; |
+} |
+ |
+ |
+void ClassTable::ResetCountersOld() { |
+ for (intptr_t i = 0; i < kNumPredefinedCids; i++) { |
+ predefined_class_heap_stats_table_[i].ResetAtOldGC(); |
+ } |
+ for (intptr_t i = kNumPredefinedCids; i < top_; i++) { |
+ class_heap_stats_table_[i].ResetAtOldGC(); |
+ } |
+} |
+ |
+ |
+void ClassTable::ResetCountersNew() { |
+ for (intptr_t i = 0; i < kNumPredefinedCids; i++) { |
+ predefined_class_heap_stats_table_[i].ResetAtNewGC(); |
+ } |
+ for (intptr_t i = kNumPredefinedCids; i < top_; i++) { |
+ class_heap_stats_table_[i].ResetAtNewGC(); |
+ } |
+} |
+ |
+ |
+void ClassTable::AllocationProfilePrintToJSONStream(JSONStream* stream) { |
+ Isolate* isolate = Isolate::Current(); |
+ ASSERT(isolate != NULL); |
+ Heap* heap = isolate->heap(); |
+ ASSERT(heap != NULL); |
+ JSONObject obj(stream); |
+ obj.AddProperty("type", "AllocationProfile"); |
+ { |
+ JSONObject heaps(&obj, "heaps"); |
+ { |
+ heap->PrintToJSONObject(Heap::kNew, &heaps); |
+ } |
+ { |
+ heap->PrintToJSONObject(Heap::kOld, &heaps); |
+ } |
+ } |
+ { |
+ Class& cls = Class::Handle(); |
+ JSONArray arr(&obj, "members"); |
+ for (intptr_t i = 1; i < kNumPredefinedCids; i++) { |
+ if (!HasValidClassAt(i) || (i == kFreeListElement) || (i == kSmiCid)) { |
+ continue; |
+ } |
+ cls = At(i); |
+ if (!(cls.is_finalized() || cls.is_prefinalized())) { |
+ // Not finalized. |
+ continue; |
+ } |
+ if (ShouldUpdateSizeForClassId(i)) { |
+ intptr_t instance_size = cls.instance_size(); |
+ predefined_class_heap_stats_table_[i].UpdateSize(instance_size); |
+ } |
+ predefined_class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr); |
+ } |
+ for (intptr_t i = kNumPredefinedCids; i < top_; i++) { |
+ if (!HasValidClassAt(i)) { |
+ continue; |
+ } |
+ cls = At(i); |
+ if (!(cls.is_finalized() || cls.is_prefinalized())) { |
+ // Not finalized. |
+ continue; |
+ } |
+ if (ShouldUpdateSizeForClassId(i)) { |
+ intptr_t instance_size = cls.instance_size(); |
+ class_heap_stats_table_[i].UpdateSize(instance_size); |
+ } |
+ class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr); |
+ } |
+ } |
+} |
+ |
+ |
+void ClassTable::UpdateLiveOld(intptr_t cid, intptr_t size) { |
+ ClassHeapStats* stats = StatsAt(cid); |
+ ASSERT(stats != NULL); |
+ ASSERT(size >= 0); |
+ stats->live_after_gc_old_space++; |
+ stats->live_size_after_gc_old_space += size; |
+} |
+ |
+ |
+void ClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) { |
+ ClassHeapStats* stats = StatsAt(cid); |
+ ASSERT(stats != NULL); |
+ ASSERT(size >= 0); |
+ stats->live_after_gc_new_space++; |
+ stats->live_size_after_gc_new_space += size; |
+} |
+ |
+ |
} // namespace dart |