Chromium Code Reviews| Index: runtime/vm/class_table.cc |
| diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc |
| index e85053a6d9cf5eb652c9f35946ae7343a929f40e..80fe03eefeae0bede498077d9cf57138b88ffeff 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,258 @@ 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; |
| +} |
| + |
| + |
| +// #define DEBUG_PRINT |
|
Ivan Posva
2014/01/17 06:53:16
Debugging code should go.
Cutch
2014/01/17 18:37:59
Done.
|
| + |
| +#if defined(DEBUG_PRINT) |
| +static void PrintClassHeapStats(intptr_t cid, const ClassHeapStats& stat) { |
| + int new_new = static_cast<int>(stat.new_count_since_gc_new_space); |
| + int new_old = static_cast<int>(stat.new_count_since_gc_old_space); |
| + int b_new = static_cast<int>(stat.new_size_since_gc_new_space); |
| + int b_old = static_cast<int>(stat.new_size_since_gc_old_space); |
| + printf("%d (%d %d) [%d %d]\n", static_cast<int>(cid), |
| + new_new, b_new, new_old, b_old); |
| +} |
| +#endif |
| + |
| + |
| +bool ClassTable::CollectInstanceSizesForClass(intptr_t cid) { |
|
Ivan Posva
2014/01/17 06:53:16
We have other lists of class ids in raw_object, fo
Cutch
2014/01/17 18:37:59
Done.
|
| + // We only collect size information for classes which do not have |
| + // fixed lengths. |
| + if ((cid == kArrayCid) || |
| + (cid == kImmutableArrayCid) || |
| + RawObject::IsOneByteStringClassId(cid) || |
| + RawObject::IsTwoByteStringClassId(cid) || |
| + RawObject::IsTypedDataClassId(cid) || |
| + (cid == kContextCid) || |
| + (cid == kTypeArgumentsCid) || |
| + (cid == kInstructionsCid) || |
| + (cid == kPcDescriptorsCid) || |
| + (cid == kStackmapCid) || |
| + (cid == kLocalVarDescriptorsCid) || |
| + (cid == kExceptionHandlersCid) || |
| + (cid == kDeoptInfoCid) || |
| + (cid == kCodeCid) || |
| + (cid == kContextScopeCid) || |
| + (cid == kInstanceCid) || |
| + (cid == kBigintCid) || |
| + (cid == kJSRegExpCid) || |
| + (cid == kSmiCid)) { |
|
Ivan Posva
2014/01/17 06:53:16
SmiCid is definitely not variable in size.
|
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| + |
| +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::HeapPrintToJSONStream(JSONStream* stream) { |
| + Isolate* isolate = Isolate::Current(); |
| + ASSERT(isolate != NULL); |
| + Heap* heap = isolate->heap(); |
| + ASSERT(heap != NULL); |
| + JSONObject obj(stream); |
| + obj.AddProperty("type", "HeapProfile"); |
| + { |
| + JSONObject heaps(&obj, "heap"); |
|
Ivan Posva
2014/01/17 06:53:16
The heap should print itself here at least as a re
|
| + { |
| + JSONObject space(&heaps, "new"); |
| + space.AddProperty("collections", heap->Collections(Heap::kNew)); |
| + space.AddProperty("used", heap->UsedInWords(Heap::kNew) * kWordSize); |
| + space.AddProperty("capacity", |
| + heap->CapacityInWords(Heap::kNew) * kWordSize); |
| + space.AddProperty("time", heap->GCTimeInSeconds(Heap::kNew)); |
| + } |
| + { |
| + JSONObject space(&heaps, "old"); |
| + space.AddProperty("collections", heap->Collections(Heap::kOld)); |
| + space.AddProperty("used", heap->UsedInWords(Heap::kOld) * kWordSize); |
| + space.AddProperty("capacity", |
| + heap->CapacityInWords(Heap::kOld) * kWordSize); |
| + space.AddProperty("time", heap->GCTimeInSeconds(Heap::kOld)); |
| + } |
| + } |
| + { |
| + Class& cls = Class::Handle(); |
| + JSONArray arr(&obj, "members"); |
| + for (intptr_t i = 1; i < kNumPredefinedCids; i++) { |
| + if (!HasValidClassAt(i) || (i == kFreeListElement)) { |
| + continue; |
| + } |
| + cls = At(i); |
| + if (!(cls.is_finalized() || cls.is_prefinalized())) { |
| + // Not finalized. |
| + continue; |
| + } |
| + if (!CollectInstanceSizesForClass(i)) { |
| + predefined_class_heap_stats_table_[i].UpdateSize(cls.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 (!CollectInstanceSizesForClass(i)) { |
| + class_heap_stats_table_[i].UpdateSize(cls.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 |