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 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 "function C(x) { this.x1 = x; this.x2 = x; }\n" | 365 "function C(x) { this.x1 = x; this.x2 = x; }\n" |
366 "var a = new A();\n" | 366 "var a = new A();\n" |
367 "var b1 = new B(a), b2 = new B(a);\n" | 367 "var b1 = new B(a), b2 = new B(a);\n" |
368 "var c = new C(a);"); | 368 "var c = new C(a);"); |
369 | 369 |
370 RetainerHeapProfile ret_profile; | 370 RetainerHeapProfile ret_profile; |
371 i::AssertNoAllocation no_alloc; | 371 i::AssertNoAllocation no_alloc; |
372 i::HeapIterator iterator; | 372 i::HeapIterator iterator; |
373 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) | 373 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) |
374 ret_profile.CollectStats(obj); | 374 ret_profile.CollectStats(obj); |
| 375 ret_profile.CoarseAndAggregate(); |
375 RetainerProfilePrinter printer; | 376 RetainerProfilePrinter printer; |
376 ret_profile.DebugPrintStats(&printer); | 377 ret_profile.DebugPrintStats(&printer); |
377 const char* retainers_of_a = printer.GetRetainers("A"); | 378 const char* retainers_of_a = printer.GetRetainers("A"); |
378 // The order of retainers is unspecified, so we check string length, and | 379 // The order of retainers is unspecified, so we check string length, and |
379 // verify each retainer separately. | 380 // verify each retainer separately. |
380 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"), | 381 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"), |
381 i::StrLength(retainers_of_a)); | 382 i::StrLength(retainers_of_a)); |
382 CHECK(strstr(retainers_of_a, "(global property);1") != NULL); | 383 CHECK(strstr(retainers_of_a, "(global property);1") != NULL); |
383 CHECK(strstr(retainers_of_a, "B;2") != NULL); | 384 CHECK(strstr(retainers_of_a, "B;2") != NULL); |
384 CHECK(strstr(retainers_of_a, "C;2") != NULL); | 385 CHECK(strstr(retainers_of_a, "C;2") != NULL); |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
643 } | 644 } |
644 | 645 |
645 | 646 |
646 TEST(HeapSnapshotCodeObjects) { | 647 TEST(HeapSnapshotCodeObjects) { |
647 v8::HandleScope scope; | 648 v8::HandleScope scope; |
648 LocalContext env; | 649 LocalContext env; |
649 | 650 |
650 CompileAndRunScript( | 651 CompileAndRunScript( |
651 "function lazy(x) { return x - 1; }\n" | 652 "function lazy(x) { return x - 1; }\n" |
652 "function compiled(x) { return x + 1; }\n" | 653 "function compiled(x) { return x + 1; }\n" |
| 654 "var inferred = function(x) { return x; }\n" |
| 655 "var anonymous = (function() { return function() { return 0; } })();\n" |
653 "compiled(1)"); | 656 "compiled(1)"); |
654 const v8::HeapSnapshot* snapshot = | 657 const v8::HeapSnapshot* snapshot = |
655 v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); | 658 v8::HeapProfiler::TakeSnapshot(v8::String::New("code")); |
656 | 659 |
657 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); | 660 const v8::HeapGraphNode* global = GetGlobalObject(snapshot); |
658 const v8::HeapGraphNode* compiled = | 661 const v8::HeapGraphNode* compiled = |
659 GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled"); | 662 GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled"); |
660 CHECK_NE(NULL, compiled); | 663 CHECK_NE(NULL, compiled); |
661 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); | 664 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType()); |
662 const v8::HeapGraphNode* lazy = | 665 const v8::HeapGraphNode* lazy = |
663 GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy"); | 666 GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy"); |
664 CHECK_NE(NULL, lazy); | 667 CHECK_NE(NULL, lazy); |
665 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); | 668 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType()); |
| 669 const v8::HeapGraphNode* inferred = |
| 670 GetProperty(global, v8::HeapGraphEdge::kProperty, "inferred"); |
| 671 CHECK_NE(NULL, inferred); |
| 672 CHECK_EQ(v8::HeapGraphNode::kClosure, inferred->GetType()); |
| 673 v8::String::AsciiValue inferred_name(inferred->GetName()); |
| 674 CHECK_EQ("inferred", *inferred_name); |
| 675 const v8::HeapGraphNode* anonymous = |
| 676 GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous"); |
| 677 CHECK_NE(NULL, anonymous); |
| 678 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType()); |
| 679 v8::String::AsciiValue anonymous_name(anonymous->GetName()); |
| 680 CHECK_EQ("(anonymous function)", *anonymous_name); |
666 | 681 |
667 // Find references to code. | 682 // Find references to code. |
668 const v8::HeapGraphNode* compiled_code = | 683 const v8::HeapGraphNode* compiled_code = |
669 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code"); | 684 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code"); |
670 CHECK_NE(NULL, compiled_code); | 685 CHECK_NE(NULL, compiled_code); |
671 const v8::HeapGraphNode* lazy_code = | 686 const v8::HeapGraphNode* lazy_code = |
672 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "code"); | 687 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "code"); |
673 CHECK_NE(NULL, lazy_code); | 688 CHECK_NE(NULL, lazy_code); |
674 | 689 |
675 // Verify that non-compiled code doesn't contain references to "x" | 690 // Verify that non-compiled code doesn't contain references to "x" |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount, | 872 i::Handle<i::PixelArray> pixels = i::Factory::NewPixelArray(kElementCount, |
858 pixel_data); | 873 pixel_data); |
859 v8::Handle<v8::Object> obj = v8::Object::New(); | 874 v8::Handle<v8::Object> obj = v8::Object::New(); |
860 // Set the elements to be the pixels. | 875 // Set the elements to be the pixels. |
861 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); | 876 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); |
862 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); | 877 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); |
863 // This call must not cause an assertion error in debug builds. | 878 // This call must not cause an assertion error in debug builds. |
864 i::HeapSnapshotTester::CalculateNetworkSize(*jsobj); | 879 i::HeapSnapshotTester::CalculateNetworkSize(*jsobj); |
865 } | 880 } |
866 | 881 |
| 882 |
| 883 static const v8::HeapGraphNode* GetChild( |
| 884 const v8::HeapGraphNode* node, |
| 885 v8::HeapGraphNode::Type type, |
| 886 const char* name, |
| 887 const v8::HeapGraphNode* after = NULL) { |
| 888 bool ignore_child = after == NULL ? false : true; |
| 889 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) { |
| 890 const v8::HeapGraphEdge* prop = node->GetChild(i); |
| 891 const v8::HeapGraphNode* child = prop->GetToNode(); |
| 892 v8::String::AsciiValue child_name(child->GetName()); |
| 893 if (!ignore_child |
| 894 && child->GetType() == type |
| 895 && strcmp(name, *child_name) == 0) |
| 896 return child; |
| 897 if (after != NULL && child == after) ignore_child = false; |
| 898 } |
| 899 return NULL; |
| 900 } |
| 901 |
| 902 static bool IsNodeRetainedAs(const v8::HeapGraphNode* node, |
| 903 int element) { |
| 904 for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) { |
| 905 const v8::HeapGraphEdge* prop = node->GetRetainer(i); |
| 906 if (prop->GetType() == v8::HeapGraphEdge::kElement |
| 907 && element == prop->GetName()->Int32Value()) |
| 908 return true; |
| 909 } |
| 910 return false; |
| 911 } |
| 912 |
| 913 TEST(AggregatedHeapSnapshot) { |
| 914 v8::HandleScope scope; |
| 915 LocalContext env; |
| 916 |
| 917 CompileAndRunScript( |
| 918 "function A() {}\n" |
| 919 "function B(x) { this.x = x; }\n" |
| 920 "var a = new A();\n" |
| 921 "var b = new B(a);"); |
| 922 const v8::HeapSnapshot* snapshot = |
| 923 v8::HeapProfiler::TakeSnapshot( |
| 924 v8::String::New("agg"), v8::HeapSnapshot::kAggregated); |
| 925 const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(), |
| 926 v8::HeapGraphNode::kInternal, |
| 927 "STRING_TYPE"); |
| 928 CHECK_NE(NULL, strings); |
| 929 CHECK_NE(0, strings->GetSelfSize()); |
| 930 CHECK_NE(0, strings->GetInstancesCount()); |
| 931 const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(), |
| 932 v8::HeapGraphNode::kInternal, |
| 933 "MAP_TYPE"); |
| 934 CHECK_NE(NULL, maps); |
| 935 CHECK_NE(0, maps->GetSelfSize()); |
| 936 CHECK_NE(0, maps->GetInstancesCount()); |
| 937 |
| 938 const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(), |
| 939 v8::HeapGraphNode::kObject, |
| 940 "A"); |
| 941 CHECK_NE(NULL, a); |
| 942 CHECK_NE(0, a->GetSelfSize()); |
| 943 CHECK_EQ(1, a->GetInstancesCount()); |
| 944 |
| 945 const v8::HeapGraphNode* b = GetChild(snapshot->GetRoot(), |
| 946 v8::HeapGraphNode::kObject, |
| 947 "B"); |
| 948 CHECK_NE(NULL, b); |
| 949 CHECK_NE(0, b->GetSelfSize()); |
| 950 CHECK_EQ(1, b->GetInstancesCount()); |
| 951 |
| 952 const v8::HeapGraphNode* glob_prop = GetChild(snapshot->GetRoot(), |
| 953 v8::HeapGraphNode::kObject, |
| 954 "(global property)", |
| 955 b); |
| 956 CHECK_NE(NULL, glob_prop); |
| 957 CHECK_EQ(0, glob_prop->GetSelfSize()); |
| 958 CHECK_EQ(0, glob_prop->GetInstancesCount()); |
| 959 CHECK_NE(0, glob_prop->GetChildrenCount()); |
| 960 |
| 961 const v8::HeapGraphNode* a_from_glob_prop = GetChild( |
| 962 glob_prop, |
| 963 v8::HeapGraphNode::kObject, |
| 964 "A"); |
| 965 CHECK_NE(NULL, a_from_glob_prop); |
| 966 CHECK_EQ(0, a_from_glob_prop->GetSelfSize()); |
| 967 CHECK_EQ(0, a_from_glob_prop->GetInstancesCount()); |
| 968 CHECK_EQ(0, a_from_glob_prop->GetChildrenCount()); // Retains nothing. |
| 969 CHECK(IsNodeRetainedAs(a_from_glob_prop, 1)); // (global propery) has 1 ref. |
| 970 |
| 971 const v8::HeapGraphNode* b_with_children = GetChild( |
| 972 snapshot->GetRoot(), |
| 973 v8::HeapGraphNode::kObject, |
| 974 "B", |
| 975 b); |
| 976 CHECK_NE(NULL, b_with_children); |
| 977 CHECK_EQ(0, b_with_children->GetSelfSize()); |
| 978 CHECK_EQ(0, b_with_children->GetInstancesCount()); |
| 979 CHECK_NE(0, b_with_children->GetChildrenCount()); |
| 980 |
| 981 const v8::HeapGraphNode* a_from_b = GetChild( |
| 982 b_with_children, |
| 983 v8::HeapGraphNode::kObject, |
| 984 "A"); |
| 985 CHECK_NE(NULL, a_from_b); |
| 986 CHECK_EQ(0, a_from_b->GetSelfSize()); |
| 987 CHECK_EQ(0, a_from_b->GetInstancesCount()); |
| 988 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing. |
| 989 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A. |
| 990 } |
| 991 |
867 #endif // ENABLE_LOGGING_AND_PROFILING | 992 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |