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 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
838 const v8::HeapGraphNode* root1 = snapshot->GetRoot(); | 838 const v8::HeapGraphNode* root1 = snapshot->GetRoot(); |
839 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( | 839 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>( |
840 snapshot))->GetSortedEntriesList(); | 840 snapshot))->GetSortedEntriesList(); |
841 const v8::HeapGraphNode* root2 = snapshot->GetRoot(); | 841 const v8::HeapGraphNode* root2 = snapshot->GetRoot(); |
842 CHECK_EQ(root1, root2); | 842 CHECK_EQ(root1, root2); |
843 } | 843 } |
844 | 844 |
845 | 845 |
846 namespace { | 846 namespace { |
847 | 847 |
| 848 class OneByteResource : public v8::String::ExternalOneByteStringResource { |
| 849 public: |
| 850 explicit OneByteResource(i::Vector<char> string) : data_(string.start()) { |
| 851 length_ = string.length(); |
| 852 } |
| 853 virtual const char* data() const { return data_; } |
| 854 virtual size_t length() const { return length_; } |
| 855 |
| 856 private: |
| 857 const char* data_; |
| 858 size_t length_; |
| 859 }; |
| 860 |
848 class TestJSONStream : public v8::OutputStream { | 861 class TestJSONStream : public v8::OutputStream { |
849 public: | 862 public: |
850 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {} | 863 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {} |
851 explicit TestJSONStream(int abort_countdown) | 864 explicit TestJSONStream(int abort_countdown) |
852 : eos_signaled_(0), abort_countdown_(abort_countdown) {} | 865 : eos_signaled_(0), abort_countdown_(abort_countdown) {} |
853 virtual ~TestJSONStream() {} | 866 virtual ~TestJSONStream() {} |
854 virtual void EndOfStream() { ++eos_signaled_; } | 867 virtual void EndOfStream() { ++eos_signaled_; } |
855 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) { | 868 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) { |
856 if (abort_countdown_ > 0) --abort_countdown_; | 869 if (abort_countdown_ > 0) --abort_countdown_; |
857 if (abort_countdown_ == 0) return kAbort; | 870 if (abort_countdown_ == 0) return kAbort; |
858 CHECK_GT(chars_written, 0); | 871 CHECK_GT(chars_written, 0); |
859 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0'); | 872 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0'); |
860 i::MemCopy(chunk.start(), buffer, chars_written); | 873 i::MemCopy(chunk.start(), buffer, chars_written); |
861 return kContinue; | 874 return kContinue; |
862 } | 875 } |
863 virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) { | 876 virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) { |
864 CHECK(false); | 877 CHECK(false); |
865 return kAbort; | 878 return kAbort; |
866 } | 879 } |
867 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } | 880 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } |
868 int eos_signaled() { return eos_signaled_; } | 881 int eos_signaled() { return eos_signaled_; } |
869 int size() { return buffer_.size(); } | 882 int size() { return buffer_.size(); } |
870 | 883 |
| 884 // Verifies that the stream contains JSON, parses, and returns the parsed |
| 885 // result. |
| 886 v8::Local<v8::Object> verifyAndParseJSON(LocalContext& env) { |
| 887 i::ScopedVector<char> json(size()); |
| 888 WriteTo(json); |
| 889 |
| 890 // Verify that string is valid JSON. |
| 891 OneByteResource* json_res = new OneByteResource(json); |
| 892 v8::Local<v8::String> json_string = |
| 893 v8::String::NewExternalOneByte(env->GetIsolate(), json_res) |
| 894 .ToLocalChecked(); |
| 895 env->Global() |
| 896 ->Set(env.local(), v8_str("json_snapshot"), json_string) |
| 897 .FromJust(); |
| 898 v8::Local<v8::Value> snapshot_parse_result = |
| 899 CompileRun("var parsed = JSON.parse(json_snapshot); true;"); |
| 900 CHECK(!snapshot_parse_result.IsEmpty()); |
| 901 |
| 902 v8::Local<v8::Object> parsed = env->Global() |
| 903 ->Get(env.local(), v8_str("parsed")) |
| 904 .ToLocalChecked() |
| 905 ->ToObject(env.local()) |
| 906 .ToLocalChecked(); |
| 907 return parsed; |
| 908 } |
| 909 |
871 private: | 910 private: |
872 i::Collector<char> buffer_; | 911 i::Collector<char> buffer_; |
873 int eos_signaled_; | 912 int eos_signaled_; |
874 int abort_countdown_; | 913 int abort_countdown_; |
875 }; | 914 }; |
876 | 915 |
877 class OneByteResource : public v8::String::ExternalOneByteStringResource { | |
878 public: | |
879 explicit OneByteResource(i::Vector<char> string) : data_(string.start()) { | |
880 length_ = string.length(); | |
881 } | |
882 virtual const char* data() const { return data_; } | |
883 virtual size_t length() const { return length_; } | |
884 private: | |
885 const char* data_; | |
886 size_t length_; | |
887 }; | |
888 | |
889 } // namespace | 916 } // namespace |
890 | 917 |
891 TEST(HeapSnapshotJSONSerialization) { | 918 TEST(HeapSnapshotJSONSerialization) { |
892 v8::Isolate* isolate = CcTest::isolate(); | 919 v8::Isolate* isolate = CcTest::isolate(); |
893 LocalContext env; | 920 LocalContext env; |
894 v8::HandleScope scope(isolate); | 921 v8::HandleScope scope(isolate); |
895 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); | 922 v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler(); |
896 | 923 |
897 #define STRING_LITERAL_FOR_TEST \ | 924 #define STRING_LITERAL_FOR_TEST \ |
898 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\"" | 925 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\"" |
899 CompileRun( | 926 CompileRun( |
900 "function A(s) { this.s = s; }\n" | 927 "function A(s) { this.s = s; }\n" |
901 "function B(x) { this.x = x; }\n" | 928 "function B(x) { this.x = x; }\n" |
902 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" | 929 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" |
903 "var b = new B(a);"); | 930 "var b = new B(a);"); |
904 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); | 931 const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); |
905 CHECK(ValidateSnapshot(snapshot)); | 932 CHECK(ValidateSnapshot(snapshot)); |
906 | 933 |
907 TestJSONStream stream; | 934 TestJSONStream stream; |
908 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); | 935 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); |
909 CHECK_GT(stream.size(), 0); | 936 CHECK_GT(stream.size(), 0); |
910 CHECK_EQ(1, stream.eos_signaled()); | 937 CHECK_EQ(1, stream.eos_signaled()); |
911 i::ScopedVector<char> json(stream.size()); | |
912 stream.WriteTo(json); | |
913 | 938 |
914 // Verify that snapshot string is valid JSON. | 939 v8::Local<v8::Object> parsed_snapshot = stream.verifyAndParseJSON(env); |
915 OneByteResource* json_res = new OneByteResource(json); | |
916 v8::Local<v8::String> json_string = | |
917 v8::String::NewExternalOneByte(env->GetIsolate(), json_res) | |
918 .ToLocalChecked(); | |
919 env->Global() | |
920 ->Set(env.local(), v8_str("json_snapshot"), json_string) | |
921 .FromJust(); | |
922 v8::Local<v8::Value> snapshot_parse_result = CompileRun( | |
923 "var parsed = JSON.parse(json_snapshot); true;"); | |
924 CHECK(!snapshot_parse_result.IsEmpty()); | |
925 | |
926 // Verify that snapshot object has required fields. | |
927 v8::Local<v8::Object> parsed_snapshot = | |
928 env->Global() | |
929 ->Get(env.local(), v8_str("parsed")) | |
930 .ToLocalChecked() | |
931 ->ToObject(env.local()) | |
932 .ToLocalChecked(); | |
933 CHECK(parsed_snapshot->Has(env.local(), v8_str("snapshot")).FromJust()); | 940 CHECK(parsed_snapshot->Has(env.local(), v8_str("snapshot")).FromJust()); |
934 CHECK(parsed_snapshot->Has(env.local(), v8_str("nodes")).FromJust()); | 941 CHECK(parsed_snapshot->Has(env.local(), v8_str("nodes")).FromJust()); |
935 CHECK(parsed_snapshot->Has(env.local(), v8_str("edges")).FromJust()); | 942 CHECK(parsed_snapshot->Has(env.local(), v8_str("edges")).FromJust()); |
936 CHECK(parsed_snapshot->Has(env.local(), v8_str("strings")).FromJust()); | 943 CHECK(parsed_snapshot->Has(env.local(), v8_str("strings")).FromJust()); |
937 | 944 |
938 // Get node and edge "member" offsets. | 945 // Get node and edge "member" offsets. |
939 v8::Local<v8::Value> meta_analysis_result = CompileRun( | 946 v8::Local<v8::Value> meta_analysis_result = CompileRun( |
940 "var meta = parsed.snapshot.meta;\n" | 947 "var meta = parsed.snapshot.meta;\n" |
941 "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n" | 948 "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n" |
942 "var node_fields_count = meta.node_fields.length;\n" | 949 "var node_fields_count = meta.node_fields.length;\n" |
(...skipping 1902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2845 map.AddRange(ToAddress(0x180), 0x80, 6U); | 2852 map.AddRange(ToAddress(0x180), 0x80, 6U); |
2846 map.AddRange(ToAddress(0x180), 0x80, 7U); | 2853 map.AddRange(ToAddress(0x180), 0x80, 7U); |
2847 CHECK_EQ(7u, map.GetTraceNodeId(ToAddress(0x180))); | 2854 CHECK_EQ(7u, map.GetTraceNodeId(ToAddress(0x180))); |
2848 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200))); | 2855 CHECK_EQ(5u, map.GetTraceNodeId(ToAddress(0x200))); |
2849 CHECK_EQ(3u, map.size()); | 2856 CHECK_EQ(3u, map.size()); |
2850 | 2857 |
2851 map.Clear(); | 2858 map.Clear(); |
2852 CHECK_EQ(0u, map.size()); | 2859 CHECK_EQ(0u, map.size()); |
2853 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); | 2860 CHECK_EQ(0u, map.GetTraceNodeId(ToAddress(0x400))); |
2854 } | 2861 } |
| 2862 |
| 2863 |
| 2864 TEST(SamplingHeapProfiler) { |
| 2865 v8::HandleScope scope(v8::Isolate::GetCurrent()); |
| 2866 LocalContext env; |
| 2867 v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); |
| 2868 |
| 2869 // GetHeapSample should return an empty stream when called before starting |
| 2870 // the sampling heap profiler. |
| 2871 TestJSONStream stream0; |
| 2872 heap_profiler->GetHeapSample(&stream0); |
| 2873 CHECK_EQ(stream0.size(), 0); |
| 2874 CHECK_EQ(1, stream0.eos_signaled()); |
| 2875 |
| 2876 heap_profiler->StartSamplingHeapProfiler(); |
| 2877 CompileRun( |
| 2878 "var A = [];\n" |
| 2879 "function bar(size) { return new Array(size); }\n" |
| 2880 "var foo = function() {\n" |
| 2881 " for (var i = 0; i < 1024; ++i) {\n" |
| 2882 " A[i] = bar(1024);\n" |
| 2883 " }\n" |
| 2884 "}\n" |
| 2885 "foo();"); |
| 2886 |
| 2887 TestJSONStream stream1; |
| 2888 heap_profiler->GetHeapSample(&stream1); |
| 2889 heap_profiler->StopSamplingHeapProfiler(); |
| 2890 |
| 2891 CHECK_GT(stream1.size(), 0); |
| 2892 CHECK_EQ(1, stream1.eos_signaled()); |
| 2893 |
| 2894 v8::Local<v8::Object> sample = stream1.verifyAndParseJSON(env); |
| 2895 CHECK(sample->IsArray()); |
| 2896 v8::Local<v8::Value> validation_result = CompileRun( |
| 2897 "parsed.every(allocation => {\n" |
| 2898 " return allocation.size && Array.isArray(allocation.stack) &&\n" |
| 2899 " allocation.stack.every(frame => {\n" |
| 2900 " return frame.hasOwnProperty('name') &&\n" |
| 2901 " frame.hasOwnProperty('scriptName') &&\n" |
| 2902 " frame.hasOwnProperty('line') &&\n" |
| 2903 " frame.hasOwnProperty('column');\n" |
| 2904 " });\n" |
| 2905 "});"); |
| 2906 CHECK(validation_result->IsTrue()); |
| 2907 |
| 2908 // Samples are reset once sampling heap profiler is stopped. |
| 2909 TestJSONStream stream2; |
| 2910 heap_profiler->GetHeapSample(&stream2); |
| 2911 CHECK_EQ(stream2.size(), 0); |
| 2912 CHECK_EQ(1, stream2.eos_signaled()); |
| 2913 } |
OLD | NEW |