Index: runtime/vm/heap_test.cc |
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc |
index 54d0cd7b28f7e6fbf3bb1082590a4b697564de33..de78beab0f30a97438c56310ca1e5d54829331b1 100644 |
--- a/runtime/vm/heap_test.cc |
+++ b/runtime/vm/heap_test.cc |
@@ -3,6 +3,7 @@ |
// BSD-style license that can be found in the LICENSE file. |
#include "platform/assert.h" |
+#include "vm/dart_api_impl.h" |
#include "vm/globals.h" |
#include "vm/heap.h" |
#include "vm/unit_test.h" |
@@ -46,4 +47,118 @@ TEST_CASE(LargeSweep) { |
Dart_ExitScope(); |
heap->CollectGarbage(Heap::kOld); |
} |
+ |
+class ClassHeapStatsTestHelper { |
+ public: |
+ static ClassHeapStats* GetHeapStatsForCid(ClassTable* class_table, |
+ intptr_t cid) { |
+ return class_table->StatsAt(cid); |
+ } |
+ |
+ static void DumpClassHeapStats(ClassHeapStats* stats) { |
+ printf("%" Pd " ", stats->allocated_since_gc_new_space); |
+ printf("%" Pd " ", stats->live_after_gc_new_space); |
+ printf("%" Pd " ", stats->allocated_before_gc_new_space); |
+ printf("\n"); |
+ } |
+}; |
+ |
+ |
+static RawClass* GetClass(const Library& lib, const char* name) { |
+ const Class& cls = Class::Handle( |
+ lib.LookupClass(String::Handle(Symbols::New(name)))); |
+ EXPECT(!cls.IsNull()); // No ambiguity error expected. |
+ return cls.raw(); |
+} |
+ |
+ |
+TEST_CASE(ClassHeapStats) { |
+ const char* kScriptChars = |
+ "class A {\n" |
+ " var a;\n" |
+ " var b;\n" |
+ "}\n" |
+ "" |
+ "main() {\n" |
+ " var x = new A();\n" |
+ " return new A();\n" |
+ "}\n"; |
+ Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL); |
+ Isolate* isolate = Isolate::Current(); |
+ ClassTable* class_table = isolate->class_table(); |
+ Heap* heap = isolate->heap(); |
+ Dart_EnterScope(); |
+ Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL); |
+ EXPECT_VALID(result); |
+ EXPECT(!Dart_IsNull(result)); |
+ Library& lib = Library::Handle(); |
+ lib ^= Api::UnwrapHandle(h_lib); |
+ EXPECT(!lib.IsNull()); |
+ const Class& cls = Class::Handle(GetClass(lib, "A")); |
+ ASSERT(!cls.IsNull()); |
+ intptr_t cid = cls.id(); |
+ ClassHeapStats* class_stats = |
+ ClassHeapStatsTestHelper::GetHeapStatsForCid(class_table, |
+ cid); |
+ // Verify preconditions: |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_new_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_new_space); |
+ // Class allocated twice since GC from new space. |
+ EXPECT_EQ(2, class_stats->allocated_since_gc_new_space); |
+ // Perform GC. |
+ heap->CollectGarbage(Heap::kNew); |
+ // Verify postconditions: |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_old_space); |
+ // Total allocations before GC. |
+ EXPECT_EQ(2, class_stats->allocated_before_gc_new_space); |
+ // Only one survived. |
+ EXPECT_EQ(1, class_stats->live_after_gc_new_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_new_space); |
+ // Perform GC. The following is heavily dependent on the behaviour |
+ // of the GC: Retained instance of A will be promoted. |
+ heap->CollectGarbage(Heap::kNew); |
+ // Verify postconditions: |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_old_space); |
+ // Promotion counted as an allocation from old space. |
+ EXPECT_EQ(1, class_stats->allocated_since_gc_old_space); |
+ // There was one instance allocated before GC. |
+ EXPECT_EQ(1, class_stats->allocated_before_gc_new_space); |
+ // There are no instances allocated in new space after GC. |
+ EXPECT_EQ(0, class_stats->live_after_gc_new_space); |
+ // No new allocations. |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_new_space); |
+ // Perform a GC on new space. |
+ heap->CollectGarbage(Heap::kNew); |
+ // There were no instances allocated before GC. |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_new_space); |
+ // There are no instances allocated in new space after GC. |
+ EXPECT_EQ(0, class_stats->live_after_gc_new_space); |
+ // No new allocations. |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_new_space); |
+ heap->CollectGarbage(Heap::kOld); |
+ // Verify postconditions: |
+ EXPECT_EQ(1, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(1, class_stats->live_after_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_old_space); |
+ // Exit scope, freeing instance. |
+ Dart_ExitScope(); |
+ // Perform GC. |
+ heap->CollectGarbage(Heap::kOld); |
+ // Verify postconditions: |
+ EXPECT_EQ(1, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_old_space); |
+ // Perform GC. |
+ heap->CollectGarbage(Heap::kOld); |
+ EXPECT_EQ(0, class_stats->allocated_before_gc_old_space); |
+ EXPECT_EQ(0, class_stats->live_after_gc_old_space); |
+ EXPECT_EQ(0, class_stats->allocated_since_gc_old_space); |
} |
+ |
+} // namespace dart. |