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

Unified Diff: test/cctest/test-heap-profiler.cc

Issue 200132: Add initial version of retainers heap profile. (Closed)
Patch Set: Comments addressed Created 11 years, 3 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
« no previous file with comments | « test/cctest/SConscript ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/test-heap-profiler.cc
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a34c6093afa1da74c383a44ba03158efdf5dee9a
--- /dev/null
+++ b/test/cctest/test-heap-profiler.cc
@@ -0,0 +1,323 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+//
+// Tests for heap profiler
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+#include "v8.h"
+#include "heap-profiler.h"
+#include "string-stream.h"
+#include "cctest.h"
+
+namespace i = v8::internal;
+using i::ClustersCoarser;
+using i::JSObjectsCluster;
+using i::JSObjectsClusterTree;
+using i::RetainerHeapProfile;
+
+
+static void CompileAndRunScript(const char *src) {
+ v8::Script::Compile(v8::String::New(src))->Run();
+}
+
+
+namespace {
+
+class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
+ public:
+ ConstructorHeapProfileTestHelper()
+ : i::ConstructorHeapProfile(),
+ f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
+ f_count_(0) {
+ }
+
+ void Call(i::String* name, const i::NumberAndSizeInfo& number_and_size) {
+ CHECK(name != NULL);
+ if (f_name_->Equals(name)) {
+ CHECK_EQ(f_count_, 0);
+ f_count_ = number_and_size.number();
+ CHECK_GT(f_count_, 0);
+ }
+ }
+
+ int f_count() { return f_count_; }
+
+ private:
+ i::Handle<i::String> f_name_;
+ int f_count_;
+};
+
+} // namespace
+
+
+TEST(ConstructorProfile) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ CompileAndRunScript(
+ "function F() {} // A constructor\n"
+ "var f1 = new F();\n"
+ "var f2 = new F();\n");
+
+ ConstructorHeapProfileTestHelper cons_profile;
+ i::AssertNoAllocation no_alloc;
+ i::HeapIterator iterator;
+ while (iterator.has_next()) {
+ i::HeapObject* obj = iterator.next();
+ cons_profile.CollectStats(obj);
+ }
+ CHECK_EQ(0, cons_profile.f_count());
+ cons_profile.PrintStats();
+ CHECK_EQ(2, cons_profile.f_count());
+}
+
+
+static JSObjectsCluster AddHeapObjectToTree(
+ JSObjectsClusterTree* tree,
+ i::String* constructor,
+ int instance,
+ JSObjectsCluster* ref1 = NULL,
+ JSObjectsCluster* ref2 = NULL,
+ JSObjectsCluster* ref3 = NULL) {
+ JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
+ JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
+ JSObjectsClusterTree::Locator loc;
+ if (ref1 != NULL) o_tree->Insert(*ref1, &loc);
+ if (ref2 != NULL) o_tree->Insert(*ref2, &loc);
+ if (ref3 != NULL) o_tree->Insert(*ref3, &loc);
+ tree->Insert(o, &loc);
+ loc.set_value(o_tree);
+ return o;
+}
+
+
+static inline void CheckEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const JSObjectsCluster& expected,
+ const char* value_source,
+ const JSObjectsCluster& value) {
+ if (JSObjectsCluster::Compare(expected, value) != 0) {
+ i::HeapStringAllocator allocator;
+ i::StringStream stream(&allocator);
+ stream.Add("# Expected: ");
+ expected.DebugPrint(&stream);
+ stream.Add("\n# Found: ");
+ value.DebugPrint(&stream);
+ V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
+ expected_source, value_source,
+ *stream.ToCString());
+ }
+}
+
+
+static inline void CheckNonEqualsHelper(const char* file, int line,
+ const char* expected_source,
+ const JSObjectsCluster& expected,
+ const char* value_source,
+ const JSObjectsCluster& value) {
+ if (JSObjectsCluster::Compare(expected, value) == 0) {
+ i::HeapStringAllocator allocator;
+ i::StringStream stream(&allocator);
+ stream.Add("# Expected: ");
+ expected.DebugPrint(&stream);
+ stream.Add("\n# Found: ");
+ value.DebugPrint(&stream);
+ V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
+ expected_source, value_source,
+ *stream.ToCString());
+ }
+}
+
+
+TEST(ClustersCoarserSimple) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsClusterTree tree;
+ JSObjectsCluster function(i::Heap::function_class_symbol());
+ JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
+ JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
+
+ // o1 <- Function
+ JSObjectsCluster o1 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ // o2 <- Function
+ JSObjectsCluster o2 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ // o3 <- A, B
+ JSObjectsCluster o3 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
+ // o4 <- B, A
+ JSObjectsCluster o4 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
+ // o5 <- A, B, Function
+ JSObjectsCluster o5 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
+ &a, &b, &function);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
+ CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
+ CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
+}
+
+
+TEST(ClustersCoarserMultipleConstructors) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsClusterTree tree;
+ JSObjectsCluster function(i::Heap::function_class_symbol());
+
+ // o1 <- Function
+ JSObjectsCluster o1 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
+ // a1 <- Function
+ JSObjectsCluster a1 =
+ AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
+ // o2 <- Function
+ JSObjectsCluster o2 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
+ // a2 <- Function
+ JSObjectsCluster a2 =
+ AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
+ CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
+}
+
+
+TEST(ClustersCoarserPathsTraversal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
+
+ JSObjectsClusterTree tree;
+
+ // On the following graph:
+ //
+ // p
+ // <- o21 <- o11 <-
+ // q o
+ // <- o22 <- o12 <-
+ // r
+ //
+ // we expect that coarser will deduce equivalences: p ~ q ~ r,
+ // o21 ~ o22, and o11 ~ o12.
+
+ JSObjectsCluster o =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
+ JSObjectsCluster o11 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
+ JSObjectsCluster o12 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
+ JSObjectsCluster o21 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
+ JSObjectsCluster o22 =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
+ JSObjectsCluster p =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
+ JSObjectsCluster q =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
+ JSObjectsCluster r =
+ AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
+
+ ClustersCoarser coarser;
+ coarser.Process(&tree);
+
+ CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
+ CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
+ CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
+ CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
+ CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
+ CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
+ CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
+}
+
+
+namespace {
+
+class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
+ public:
+ RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
+
+ void PrintRetainers(const i::StringStream& retainers) {
+ stream_.Add("%s", *(retainers.ToCString()));
+ stream_.Put('\0');
+ }
+
+ const char* GetRetainers(const char* constructor) {
+ FillLines();
+ const size_t cons_len = strlen(constructor);
+ for (int i = 0; i < lines_.length(); ++i) {
+ if (strncmp(constructor, lines_[i], cons_len) == 0 &&
+ lines_[i][cons_len] == ',') {
+ return lines_[i] + cons_len + 1;
+ }
+ }
+ return NULL;
+ }
+
+ private:
+ void FillLines() {
+ if (lines_.length() > 0) return;
+ stream_.Put('\0');
+ stream_str_ = stream_.ToCString();
+ const char* pos = *stream_str_;
+ while (pos != NULL && *pos != '\0') {
+ lines_.Add(pos);
+ pos = strchr(pos, '\0');
+ if (pos != NULL) ++pos;
+ }
+ }
+
+ i::HeapStringAllocator allocator_;
+ i::StringStream stream_;
+ i::SmartPointer<const char> stream_str_;
+ i::List<const char*> lines_;
+};
+
+} // namespace
+
+
+TEST(RetainerProfile) {
+ v8::HandleScope scope;
+ v8::Handle<v8::Context> env = v8::Context::New();
+ env->Enter();
+
+ CompileAndRunScript(
+ "function A() {}\n"
+ "function B(x) { this.x = x; }\n"
+ "var a = new A();\n"
+ "var b = new B(a);\n");
+
+ RetainerHeapProfile ret_profile;
+ i::AssertNoAllocation no_alloc;
+ i::HeapIterator iterator;
+ while (iterator.has_next()) {
+ i::HeapObject* obj = iterator.next();
+ ret_profile.CollectStats(obj);
+ }
+ RetainerProfilePrinter printer;
+ ret_profile.DebugPrintStats(&printer);
+ CHECK_EQ("(global property),B", printer.GetRetainers("A"));
+ CHECK_EQ("(global property)", printer.GetRetainers("B"));
+}
+
+#endif // ENABLE_LOGGING_AND_PROFILING
« no previous file with comments | « test/cctest/SConscript ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698