| 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 "snapshot.h" | 9 #include "snapshot.h" | 
| 10 #include "string-stream.h" | 10 #include "string-stream.h" | 
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 426   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 426   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 
| 427     const v8::HeapGraphEdge* prop = node->GetChild(i); | 427     const v8::HeapGraphEdge* prop = node->GetChild(i); | 
| 428     v8::String::AsciiValue prop_name(prop->GetName()); | 428     v8::String::AsciiValue prop_name(prop->GetName()); | 
| 429     if (prop->GetType() == type && strcmp(name, *prop_name) == 0) | 429     if (prop->GetType() == type && strcmp(name, *prop_name) == 0) | 
| 430       return prop->GetToNode(); | 430       return prop->GetToNode(); | 
| 431   } | 431   } | 
| 432   return NULL; | 432   return NULL; | 
| 433 } | 433 } | 
| 434 | 434 | 
| 435 | 435 | 
| 436 static bool IsNodeRetainedAs(const v8::HeapGraphNode* node, |  | 
| 437                              v8::HeapGraphEdge::Type type, |  | 
| 438                              const char* name) { |  | 
| 439   for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) { |  | 
| 440     const v8::HeapGraphEdge* prop = node->GetRetainer(i); |  | 
| 441     v8::String::AsciiValue prop_name(prop->GetName()); |  | 
| 442     if (prop->GetType() == type && strcmp(name, *prop_name) == 0) |  | 
| 443       return true; |  | 
| 444   } |  | 
| 445   return false; |  | 
| 446 } |  | 
| 447 |  | 
| 448 |  | 
| 449 static bool HasString(const v8::HeapGraphNode* node, const char* contents) { | 436 static bool HasString(const v8::HeapGraphNode* node, const char* contents) { | 
| 450   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 437   for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { | 
| 451     const v8::HeapGraphEdge* prop = node->GetChild(i); | 438     const v8::HeapGraphEdge* prop = node->GetChild(i); | 
| 452     const v8::HeapGraphNode* node = prop->GetToNode(); | 439     const v8::HeapGraphNode* node = prop->GetToNode(); | 
| 453     if (node->GetType() == v8::HeapGraphNode::kString) { | 440     if (node->GetType() == v8::HeapGraphNode::kString) { | 
| 454       v8::String::AsciiValue node_name(node->GetName()); | 441       v8::String::AsciiValue node_name(node->GetName()); | 
| 455       if (strcmp(contents, *node_name) == 0) return true; | 442       if (strcmp(contents, *node_name) == 0) return true; | 
| 456     } | 443     } | 
| 457   } | 444   } | 
| 458   return false; | 445   return false; | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
| 489       NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1")); | 476       NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1")); | 
| 490   CHECK_NE( | 477   CHECK_NE( | 
| 491       NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2")); | 478       NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2")); | 
| 492   CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2")); | 479   CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2")); | 
| 493 | 480 | 
| 494   NamedEntriesDetector det; | 481   NamedEntriesDetector det; | 
| 495   i_snapshot_env2->IterateEntries(&det); | 482   i_snapshot_env2->IterateEntries(&det); | 
| 496   CHECK(det.has_A2); | 483   CHECK(det.has_A2); | 
| 497   CHECK(det.has_B2); | 484   CHECK(det.has_B2); | 
| 498   CHECK(det.has_C2); | 485   CHECK(det.has_C2); | 
| 499 |  | 
| 500   /* |  | 
| 501     // Currently disabled. Too many retaining paths emerge, need to |  | 
| 502     // reduce the amount. |  | 
| 503 |  | 
| 504   // Verify 'a2' object retainers. They are: |  | 
| 505   //  - (global object).a2 |  | 
| 506   //  - c2.x1, c2.x2, c2[1] |  | 
| 507   //  - b2_1 and b2_2 closures: via 'x' variable |  | 
| 508   CHECK_EQ(6, a2_node->GetRetainingPathsCount()); |  | 
| 509   bool has_global_obj_a2_ref = false; |  | 
| 510   bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false; |  | 
| 511   bool has_b2_1_x_ref = false, has_b2_2_x_ref = false; |  | 
| 512   for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) { |  | 
| 513     const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i); |  | 
| 514     const int edges_count = path->GetEdgesCount(); |  | 
| 515     CHECK_GT(edges_count, 0); |  | 
| 516     const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1); |  | 
| 517     v8::String::AsciiValue last_edge_name(last_edge->GetName()); |  | 
| 518     if (strcmp("a2", *last_edge_name) == 0 |  | 
| 519         && last_edge->GetType() == v8::HeapGraphEdge::kProperty) { |  | 
| 520       has_global_obj_a2_ref = true; |  | 
| 521       continue; |  | 
| 522     } |  | 
| 523     CHECK_GT(edges_count, 1); |  | 
| 524     const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2); |  | 
| 525     v8::String::AsciiValue prev_edge_name(prev_edge->GetName()); |  | 
| 526     if (strcmp("x1", *last_edge_name) == 0 |  | 
| 527         && last_edge->GetType() == v8::HeapGraphEdge::kProperty |  | 
| 528         && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true; |  | 
| 529     if (strcmp("x2", *last_edge_name) == 0 |  | 
| 530         && last_edge->GetType() == v8::HeapGraphEdge::kProperty |  | 
| 531         && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true; |  | 
| 532     if (strcmp("1", *last_edge_name) == 0 |  | 
| 533         && last_edge->GetType() == v8::HeapGraphEdge::kElement |  | 
| 534         && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true; |  | 
| 535     if (strcmp("x", *last_edge_name) == 0 |  | 
| 536         && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable |  | 
| 537         && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true; |  | 
| 538     if (strcmp("x", *last_edge_name) == 0 |  | 
| 539         && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable |  | 
| 540         && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; |  | 
| 541   } |  | 
| 542   CHECK(has_global_obj_a2_ref); |  | 
| 543   CHECK(has_c2_x1_ref); |  | 
| 544   CHECK(has_c2_x2_ref); |  | 
| 545   CHECK(has_c2_1_ref); |  | 
| 546   CHECK(has_b2_1_x_ref); |  | 
| 547   CHECK(has_b2_2_x_ref); |  | 
| 548   */ |  | 
| 549 } | 486 } | 
| 550 | 487 | 
| 551 | 488 | 
| 552 TEST(HeapSnapshotObjectSizes) { | 489 TEST(HeapSnapshotObjectSizes) { | 
| 553   v8::HandleScope scope; | 490   v8::HandleScope scope; | 
| 554   LocalContext env; | 491   LocalContext env; | 
| 555 | 492 | 
| 556   //   -a-> X1 --a | 493   //   -a-> X1 --a | 
| 557   // x -b-> X2 <-| | 494   // x -b-> X2 <-| | 
| 558   CompileRun( | 495   CompileRun( | 
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 767       GetProperty(global1, v8::HeapGraphEdge::kProperty, "b"); | 704       GetProperty(global1, v8::HeapGraphEdge::kProperty, "b"); | 
| 768   CHECK_NE(NULL, b1); | 705   CHECK_NE(NULL, b1); | 
| 769   const v8::HeapGraphNode* b2 = | 706   const v8::HeapGraphNode* b2 = | 
| 770       GetProperty(global2, v8::HeapGraphEdge::kProperty, "b"); | 707       GetProperty(global2, v8::HeapGraphEdge::kProperty, "b"); | 
| 771   CHECK_NE(NULL, b2); | 708   CHECK_NE(NULL, b2); | 
| 772   CHECK_NE_UINT64_T(0, b1->GetId()); | 709   CHECK_NE_UINT64_T(0, b1->GetId()); | 
| 773   CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId()); | 710   CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId()); | 
| 774 } | 711 } | 
| 775 | 712 | 
| 776 | 713 | 
| 777 TEST(HeapSnapshotsDiff) { |  | 
| 778   v8::HandleScope scope; |  | 
| 779   LocalContext env; |  | 
| 780 |  | 
| 781   CompileRun( |  | 
| 782       "function A() {}\n" |  | 
| 783       "function B(x) { this.x = x; }\n" |  | 
| 784       "function A2(a) { for (var i = 0; i < a; ++i) this[i] = i; }\n" |  | 
| 785       "var a = new A();\n" |  | 
| 786       "var b = new B(a);"); |  | 
| 787   const v8::HeapSnapshot* snapshot1 = |  | 
| 788       v8::HeapProfiler::TakeSnapshot(v8::String::New("s1")); |  | 
| 789 |  | 
| 790   CompileRun( |  | 
| 791       "delete a;\n" |  | 
| 792       "b.x = null;\n" |  | 
| 793       "var a = new A2(20);\n" |  | 
| 794       "var b2 = new B(a);"); |  | 
| 795   const v8::HeapSnapshot* snapshot2 = |  | 
| 796       v8::HeapProfiler::TakeSnapshot(v8::String::New("s2")); |  | 
| 797 |  | 
| 798   const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2); |  | 
| 799 |  | 
| 800   // Verify additions: ensure that addition of A and B was detected. |  | 
| 801   const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot(); |  | 
| 802   bool found_A = false, found_B = false; |  | 
| 803   uint64_t s1_A_id = 0; |  | 
| 804   for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) { |  | 
| 805     const v8::HeapGraphEdge* prop = additions_root->GetChild(i); |  | 
| 806     const v8::HeapGraphNode* node = prop->GetToNode(); |  | 
| 807     if (node->GetType() == v8::HeapGraphNode::kObject) { |  | 
| 808       v8::String::AsciiValue node_name(node->GetName()); |  | 
| 809       if (strcmp(*node_name, "A2") == 0) { |  | 
| 810         CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a")); |  | 
| 811         CHECK(!found_A); |  | 
| 812         found_A = true; |  | 
| 813         s1_A_id = node->GetId(); |  | 
| 814       } else if (strcmp(*node_name, "B") == 0) { |  | 
| 815         CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2")); |  | 
| 816         CHECK(!found_B); |  | 
| 817         found_B = true; |  | 
| 818       } |  | 
| 819     } |  | 
| 820   } |  | 
| 821   CHECK(found_A); |  | 
| 822   CHECK(found_B); |  | 
| 823 |  | 
| 824   // Verify deletions: ensure that deletion of A was detected. |  | 
| 825   const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot(); |  | 
| 826   bool found_A_del = false; |  | 
| 827   uint64_t s2_A_id = 0; |  | 
| 828   for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) { |  | 
| 829     const v8::HeapGraphEdge* prop = deletions_root->GetChild(i); |  | 
| 830     const v8::HeapGraphNode* node = prop->GetToNode(); |  | 
| 831     if (node->GetType() == v8::HeapGraphNode::kObject) { |  | 
| 832       v8::String::AsciiValue node_name(node->GetName()); |  | 
| 833       if (strcmp(*node_name, "A") == 0) { |  | 
| 834         CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a")); |  | 
| 835         CHECK(!found_A_del); |  | 
| 836         found_A_del = true; |  | 
| 837         s2_A_id = node->GetId(); |  | 
| 838       } |  | 
| 839     } |  | 
| 840   } |  | 
| 841   CHECK(found_A_del); |  | 
| 842   CHECK_NE_UINT64_T(0, s1_A_id); |  | 
| 843   CHECK(s1_A_id != s2_A_id); |  | 
| 844 } |  | 
| 845 |  | 
| 846 |  | 
| 847 TEST(HeapSnapshotRootPreservedAfterSorting) { | 714 TEST(HeapSnapshotRootPreservedAfterSorting) { | 
| 848   v8::HandleScope scope; | 715   v8::HandleScope scope; | 
| 849   LocalContext env; | 716   LocalContext env; | 
| 850   const v8::HeapSnapshot* snapshot = | 717   const v8::HeapSnapshot* snapshot = | 
| 851       v8::HeapProfiler::TakeSnapshot(v8::String::New("s")); | 718       v8::HeapProfiler::TakeSnapshot(v8::String::New("s")); | 
| 852   const v8::HeapGraphNode* root1 = snapshot->GetRoot(); | 719   const v8::HeapGraphNode* root1 = snapshot->GetRoot(); | 
| 853   const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( | 720   const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( | 
| 854       snapshot))->GetSortedEntriesList(); | 721       snapshot))->GetSortedEntriesList(); | 
| 855   const v8::HeapGraphNode* root2 = snapshot->GetRoot(); | 722   const v8::HeapGraphNode* root2 = snapshot->GetRoot(); | 
| 856   CHECK_EQ(root1, root2); | 723   CHECK_EQ(root1, root2); | 
| (...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1447   const_cast<v8::HeapSnapshot*>(s2)->Delete(); | 1314   const_cast<v8::HeapSnapshot*>(s2)->Delete(); | 
| 1448   CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); | 1315   CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount()); | 
| 1449   CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2)); | 1316   CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2)); | 
| 1450   CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3)); | 1317   CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3)); | 
| 1451   const_cast<v8::HeapSnapshot*>(s3)->Delete(); | 1318   const_cast<v8::HeapSnapshot*>(s3)->Delete(); | 
| 1452   CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); | 1319   CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount()); | 
| 1453   CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3)); | 1320   CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3)); | 
| 1454 } | 1321 } | 
| 1455 | 1322 | 
| 1456 #endif  // ENABLE_LOGGING_AND_PROFILING | 1323 #endif  // ENABLE_LOGGING_AND_PROFILING | 
| OLD | NEW | 
|---|