OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 2834 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2845 map.AddRange(ToAddress(0x180), 0x80, 6U); | 2845 map.AddRange(ToAddress(0x180), 0x80, 6U); |
2846 map.AddRange(ToAddress(0x180), 0x80, 7U); | 2846 map.AddRange(ToAddress(0x180), 0x80, 7U); |
2847 CHECK_EQ(7u, map.GetTraceNodeId(ToAddress(0x180))); | 2847 CHECK_EQ(7u, map.GetTraceNodeId(ToAddress(0x180))); |
2848 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200))); | 2848 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200))); |
2849 CHECK_EQ(3u, map.size()); | 2849 CHECK_EQ(3u, map.size()); |
2850 | 2850 |
2851 map.Clear(); | 2851 map.Clear(); |
2852 CHECK_EQ(0u, map.size()); | 2852 CHECK_EQ(0u, map.size()); |
2853 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); | 2853 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); |
2854 } | 2854 } |
| 2855 |
| 2856 |
| 2857 static const v8::AllocationProfile::Node* FindAllocationProfileNode( |
| 2858 v8::AllocationProfile& profile, const Vector<const char*>& names) { |
| 2859 v8::AllocationProfile::Node* node = profile.GetRootNode(); |
| 2860 for (int i = 0; node != nullptr && i < names.length(); ++i) { |
| 2861 const char* name = names[i]; |
| 2862 auto children = node->children; |
| 2863 node = nullptr; |
| 2864 for (v8::AllocationProfile::Node* child : children) { |
| 2865 v8::String::Utf8Value child_name(child->name); |
| 2866 if (strcmp(*child_name, name) == 0) { |
| 2867 node = child; |
| 2868 break; |
| 2869 } |
| 2870 } |
| 2871 } |
| 2872 return node; |
| 2873 } |
| 2874 |
| 2875 |
| 2876 TEST(SamplingHeapProfiler) { |
| 2877 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 2878 LocalContext env; |
| 2879 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2880 |
| 2881 // Turn off always_opt. Inlining can cause stack traces to be shorter than |
| 2882 // what we expect in this test. |
| 2883 v8::internal::FLAG_always_opt = false; |
| 2884 |
| 2885 // Suppress randomness to avoid flakiness in tests. |
| 2886 v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; |
| 2887 |
| 2888 const char* script_source = |
| 2889 "var A = [];\n" |
| 2890 "function bar(size) { return new Array(size); }\n" |
| 2891 "var foo = function() {\n" |
| 2892 " for (var i = 0; i < 1024; ++i) {\n" |
| 2893 " A[i] = bar(1024);\n" |
| 2894 " }\n" |
| 2895 "}\n" |
| 2896 "foo();"; |
| 2897 |
| 2898 // Sample should be empty if requested before sampling has started. |
| 2899 { |
| 2900 v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); |
| 2901 CHECK(profile == nullptr); |
| 2902 } |
| 2903 |
| 2904 int count_512kb = 0; |
| 2905 { |
| 2906 heap_profiler->StartSamplingHeapProfiler(512 * 1024); |
| 2907 CompileRun(script_source); |
| 2908 |
| 2909 v8::base::SmartPointer<v8::AllocationProfile> profile( |
| 2910 heap_profiler->GetAllocationProfile()); |
| 2911 CHECK(!profile.is_empty()); |
| 2912 |
| 2913 const char* names[] = {"", "foo", "bar"}; |
| 2914 auto node_bar = FindAllocationProfileNode( |
| 2915 *profile, Vector<const char*>(names, arraysize(names))); |
| 2916 CHECK(node_bar); |
| 2917 |
| 2918 // Count the number of allocations we sampled from bar. |
| 2919 for (auto allocation : node_bar->allocations) { |
| 2920 count_512kb += allocation.count; |
| 2921 } |
| 2922 |
| 2923 heap_profiler->StopSamplingHeapProfiler(); |
| 2924 } |
| 2925 |
| 2926 // Samples should get cleared once sampling is stopped. |
| 2927 { |
| 2928 v8::AllocationProfile* profile = heap_profiler->GetAllocationProfile(); |
| 2929 CHECK(profile == nullptr); |
| 2930 } |
| 2931 |
| 2932 // Sampling at a higher rate should give us more sampled objects. |
| 2933 { |
| 2934 heap_profiler->StartSamplingHeapProfiler(32 * 1024); |
| 2935 CompileRun(script_source); |
| 2936 |
| 2937 v8::base::SmartPointer<v8::AllocationProfile> profile( |
| 2938 heap_profiler->GetAllocationProfile()); |
| 2939 CHECK(!profile.is_empty()); |
| 2940 |
| 2941 const char* names[] = {"", "foo", "bar"}; |
| 2942 auto node_bar = FindAllocationProfileNode( |
| 2943 *profile, Vector<const char*>(names, arraysize(names))); |
| 2944 CHECK(node_bar); |
| 2945 |
| 2946 // Count the number of allocations we sampled from bar. |
| 2947 int count_32kb = 0; |
| 2948 for (auto allocation : node_bar->allocations) { |
| 2949 count_32kb += allocation.count; |
| 2950 } |
| 2951 |
| 2952 // We should have roughly 16x as many sampled allocations. However, |
| 2953 // alignment and boundaries might tweak the numbers slightly. We use a |
| 2954 // slightly weaker test to account for this. |
| 2955 CHECK_GT(count_32kb, 8 * count_512kb); |
| 2956 |
| 2957 heap_profiler->StopSamplingHeapProfiler(); |
| 2958 } |
| 2959 |
| 2960 // A more complicated test cases with deeper call graph and dynamically |
| 2961 // generated function names. |
| 2962 { |
| 2963 heap_profiler->StartSamplingHeapProfiler(64); |
| 2964 CompileRun(record_trace_tree_source); |
| 2965 |
| 2966 v8::base::SmartPointer<v8::AllocationProfile> profile( |
| 2967 heap_profiler->GetAllocationProfile()); |
| 2968 CHECK(!profile.is_empty()); |
| 2969 |
| 2970 const char* names1[] = {"", "start", "f_0_0", "f_0_1", "f_0_2"}; |
| 2971 auto node1 = FindAllocationProfileNode( |
| 2972 *profile, Vector<const char*>(names1, arraysize(names1))); |
| 2973 CHECK(node1); |
| 2974 |
| 2975 const char* names2[] = {"", "generateFunctions"}; |
| 2976 auto node2 = FindAllocationProfileNode( |
| 2977 *profile, Vector<const char*>(names2, arraysize(names2))); |
| 2978 CHECK(node2); |
| 2979 |
| 2980 heap_profiler->StopSamplingHeapProfiler(); |
| 2981 } |
| 2982 } |
| 2983 |
| 2984 |
| 2985 TEST(SamplingHeapProfilerApiAllocation) { |
| 2986 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 2987 LocalContext env; |
| 2988 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2989 |
| 2990 // Suppress randomness to avoid flakiness in tests. |
| 2991 v8::internal::FLAG_sampling_heap_profiler_suppress_randomness = true; |
| 2992 |
| 2993 heap_profiler->StartSamplingHeapProfiler(256); |
| 2994 |
| 2995 for (int i = 0; i < 8 * 1024; ++i) v8::Object::New(env->GetIsolate()); |
| 2996 |
| 2997 v8::base::SmartPointer<v8::AllocationProfile> profile( |
| 2998 heap_profiler->GetAllocationProfile()); |
| 2999 CHECK(!profile.is_empty()); |
| 3000 const char* names[] = {"(V8 API)"}; |
| 3001 auto node = FindAllocationProfileNode( |
| 3002 *profile, Vector<const char*>(names, arraysize(names))); |
| 3003 CHECK(node); |
| 3004 |
| 3005 heap_profiler->StopSamplingHeapProfiler(); |
| 3006 } |
OLD | NEW |