OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // | 2 // |
3 // Tests for heap profiler | 3 // Tests for heap profiler |
4 | 4 |
5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
6 | 6 |
7 #include "v8.h" | 7 #include "v8.h" |
8 #include "heap-profiler.h" | 8 #include "heap-profiler.h" |
9 #include "string-stream.h" | 9 #include "string-stream.h" |
10 #include "cctest.h" | 10 #include "cctest.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 while (iterator.has_next()) { | 67 while (iterator.has_next()) { |
68 i::HeapObject* obj = iterator.next(); | 68 i::HeapObject* obj = iterator.next(); |
69 cons_profile.CollectStats(obj); | 69 cons_profile.CollectStats(obj); |
70 } | 70 } |
71 CHECK_EQ(0, cons_profile.f_count()); | 71 CHECK_EQ(0, cons_profile.f_count()); |
72 cons_profile.PrintStats(); | 72 cons_profile.PrintStats(); |
73 CHECK_EQ(2, cons_profile.f_count()); | 73 CHECK_EQ(2, cons_profile.f_count()); |
74 } | 74 } |
75 | 75 |
76 | 76 |
77 static JSObjectsCluster AddHeapObjectToTree( | 77 static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree, |
78 JSObjectsRetainerTree* tree, | 78 i::String* constructor, |
79 i::String* constructor, | 79 int instance, |
80 int instance, | 80 JSObjectsCluster* ref1 = NULL, |
81 JSObjectsCluster* ref1 = NULL, | 81 JSObjectsCluster* ref2 = NULL, |
82 JSObjectsCluster* ref2 = NULL, | 82 JSObjectsCluster* ref3 = NULL) { |
83 JSObjectsCluster* ref3 = NULL) { | |
84 JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance)); | 83 JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance)); |
85 JSObjectsClusterTree* o_tree = new JSObjectsClusterTree(); | 84 JSObjectsClusterTree* o_tree = new JSObjectsClusterTree(); |
86 JSObjectsClusterTree::Locator o_loc; | 85 JSObjectsClusterTree::Locator o_loc; |
87 if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc); | 86 if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc); |
88 if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc); | 87 if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc); |
89 if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc); | 88 if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc); |
90 JSObjectsRetainerTree::Locator loc; | 89 JSObjectsRetainerTree::Locator loc; |
91 tree->Insert(o, &loc); | 90 tree->Insert(o, &loc); |
92 loc.set_value(o_tree); | 91 loc.set_value(o_tree); |
93 return o; | 92 return o; |
94 } | 93 } |
95 | 94 |
96 | 95 |
| 96 static void AddSelfReferenceToTree(JSObjectsRetainerTree* tree, |
| 97 JSObjectsCluster* self_ref) { |
| 98 JSObjectsRetainerTree::Locator loc; |
| 99 CHECK(tree->Find(*self_ref, &loc)); |
| 100 JSObjectsClusterTree::Locator o_loc; |
| 101 CHECK_NE(NULL, loc.value()); |
| 102 loc.value()->Insert(*self_ref, &o_loc); |
| 103 } |
| 104 |
| 105 |
97 static inline void CheckEqualsHelper(const char* file, int line, | 106 static inline void CheckEqualsHelper(const char* file, int line, |
98 const char* expected_source, | 107 const char* expected_source, |
99 const JSObjectsCluster& expected, | 108 const JSObjectsCluster& expected, |
100 const char* value_source, | 109 const char* value_source, |
101 const JSObjectsCluster& value) { | 110 const JSObjectsCluster& value) { |
102 if (JSObjectsCluster::Compare(expected, value) != 0) { | 111 if (JSObjectsCluster::Compare(expected, value) != 0) { |
103 i::HeapStringAllocator allocator; | 112 i::HeapStringAllocator allocator; |
104 i::StringStream stream(&allocator); | 113 i::StringStream stream(&allocator); |
105 stream.Add("# Expected: "); | 114 stream.Add("# Expected: "); |
106 expected.DebugPrint(&stream); | 115 expected.DebugPrint(&stream); |
107 stream.Add("\n# Found: "); | 116 stream.Add("\n# Found: "); |
108 value.DebugPrint(&stream); | 117 value.DebugPrint(&stream); |
109 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s", | 118 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s", |
110 expected_source, value_source, | 119 expected_source, value_source, |
111 *stream.ToCString()); | 120 *stream.ToCString()); |
112 } | 121 } |
113 } | 122 } |
114 | 123 |
115 | 124 |
116 static inline void CheckNonEqualsHelper(const char* file, int line, | 125 static inline void CheckNonEqualsHelper(const char* file, int line, |
117 const char* expected_source, | 126 const char* expected_source, |
118 const JSObjectsCluster& expected, | 127 const JSObjectsCluster& expected, |
119 const char* value_source, | 128 const char* value_source, |
120 const JSObjectsCluster& value) { | 129 const JSObjectsCluster& value) { |
121 if (JSObjectsCluster::Compare(expected, value) == 0) { | 130 if (JSObjectsCluster::Compare(expected, value) == 0) { |
122 i::HeapStringAllocator allocator; | 131 i::HeapStringAllocator allocator; |
123 i::StringStream stream(&allocator); | 132 i::StringStream stream(&allocator); |
124 stream.Add("# Expected: "); | 133 stream.Add("# !Expected: "); |
125 expected.DebugPrint(&stream); | 134 expected.DebugPrint(&stream); |
126 stream.Add("\n# Found: "); | 135 stream.Add("\n# Found: "); |
127 value.DebugPrint(&stream); | 136 value.DebugPrint(&stream); |
128 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s", | 137 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s", |
129 expected_source, value_source, | 138 expected_source, value_source, |
130 *stream.ToCString()); | 139 *stream.ToCString()); |
131 } | 140 } |
132 } | 141 } |
133 | 142 |
134 | 143 |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21); | 245 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21); |
237 JSObjectsCluster q = | 246 JSObjectsCluster q = |
238 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22); | 247 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22); |
239 JSObjectsCluster r = | 248 JSObjectsCluster r = |
240 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22); | 249 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22); |
241 | 250 |
242 ClustersCoarser coarser; | 251 ClustersCoarser coarser; |
243 coarser.Process(&tree); | 252 coarser.Process(&tree); |
244 | 253 |
245 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o)); | 254 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o)); |
| 255 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11)); |
246 CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12)); | 256 CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12)); |
247 CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22)); | 257 CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22)); |
248 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21)); | 258 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21)); |
| 259 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p)); |
249 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q)); | 260 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q)); |
250 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r)); | 261 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r)); |
251 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p)); | 262 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p)); |
252 CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p)); | 263 CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p)); |
253 } | 264 } |
254 | 265 |
255 | 266 |
| 267 TEST(ClustersCoarserSelf) { |
| 268 v8::HandleScope scope; |
| 269 v8::Handle<v8::Context> env = v8::Context::New(); |
| 270 env->Enter(); |
| 271 |
| 272 i::ZoneScope zn_scope(i::DELETE_ON_EXIT); |
| 273 |
| 274 JSObjectsRetainerTree tree; |
| 275 |
| 276 // On the following graph: |
| 277 // |
| 278 // p (self-referencing) |
| 279 // <- o1 <- |
| 280 // q (self-referencing) o |
| 281 // <- o2 <- |
| 282 // r (self-referencing) |
| 283 // |
| 284 // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2; |
| 285 |
| 286 JSObjectsCluster o = |
| 287 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100); |
| 288 JSObjectsCluster o1 = |
| 289 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o); |
| 290 JSObjectsCluster o2 = |
| 291 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o); |
| 292 JSObjectsCluster p = |
| 293 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1); |
| 294 AddSelfReferenceToTree(&tree, &p); |
| 295 JSObjectsCluster q = |
| 296 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2); |
| 297 AddSelfReferenceToTree(&tree, &q); |
| 298 JSObjectsCluster r = |
| 299 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2); |
| 300 AddSelfReferenceToTree(&tree, &r); |
| 301 |
| 302 ClustersCoarser coarser; |
| 303 coarser.Process(&tree); |
| 304 |
| 305 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o)); |
| 306 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1)); |
| 307 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2)); |
| 308 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p)); |
| 309 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q)); |
| 310 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r)); |
| 311 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p)); |
| 312 } |
| 313 |
| 314 |
256 namespace { | 315 namespace { |
257 | 316 |
258 class RetainerProfilePrinter : public RetainerHeapProfile::Printer { | 317 class RetainerProfilePrinter : public RetainerHeapProfile::Printer { |
259 public: | 318 public: |
260 RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {} | 319 RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {} |
261 | 320 |
262 void PrintRetainers(const JSObjectsCluster& cluster, | 321 void PrintRetainers(const JSObjectsCluster& cluster, |
263 const i::StringStream& retainers) { | 322 const i::StringStream& retainers) { |
264 cluster.Print(&stream_); | 323 cluster.Print(&stream_); |
265 stream_.Add("%s", *(retainers.ToCString())); | 324 stream_.Add("%s", *(retainers.ToCString())); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
315 | 374 |
316 RetainerHeapProfile ret_profile; | 375 RetainerHeapProfile ret_profile; |
317 i::AssertNoAllocation no_alloc; | 376 i::AssertNoAllocation no_alloc; |
318 i::HeapIterator iterator; | 377 i::HeapIterator iterator; |
319 while (iterator.has_next()) { | 378 while (iterator.has_next()) { |
320 i::HeapObject* obj = iterator.next(); | 379 i::HeapObject* obj = iterator.next(); |
321 ret_profile.CollectStats(obj); | 380 ret_profile.CollectStats(obj); |
322 } | 381 } |
323 RetainerProfilePrinter printer; | 382 RetainerProfilePrinter printer; |
324 ret_profile.DebugPrintStats(&printer); | 383 ret_profile.DebugPrintStats(&printer); |
325 CHECK_EQ("(global property);1,B;2,C;2", printer.GetRetainers("A")); | 384 const char* retainers_of_a = printer.GetRetainers("A"); |
| 385 // The order of retainers is unspecified, so we check string length, and |
| 386 // verify each retainer separately. |
| 387 CHECK_EQ(static_cast<int>(strlen("(global property);1,B;2,C;2")), |
| 388 static_cast<int>(strlen(retainers_of_a))); |
| 389 CHECK(strstr(retainers_of_a, "(global property);1") != NULL); |
| 390 CHECK(strstr(retainers_of_a, "B;2") != NULL); |
| 391 CHECK(strstr(retainers_of_a, "C;2") != NULL); |
326 CHECK_EQ("(global property);2", printer.GetRetainers("B")); | 392 CHECK_EQ("(global property);2", printer.GetRetainers("B")); |
327 CHECK_EQ("(global property);1", printer.GetRetainers("C")); | 393 CHECK_EQ("(global property);1", printer.GetRetainers("C")); |
328 } | 394 } |
329 | 395 |
330 #endif // ENABLE_LOGGING_AND_PROFILING | 396 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |