Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1272)

Unified Diff: runtime/vm/class_table.cc

Issue 51653006: Track live instance and allocation counts for classes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
« no previous file with comments | « runtime/vm/class_table.h ('k') | runtime/vm/gc_marker.cc » ('j') | runtime/vm/gc_marker.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698