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 |