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 971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
982 b_with_children, | 982 b_with_children, |
983 v8::HeapGraphNode::kObject, | 983 v8::HeapGraphNode::kObject, |
984 "A"); | 984 "A"); |
985 CHECK_NE(NULL, a_from_b); | 985 CHECK_NE(NULL, a_from_b); |
986 CHECK_EQ(0, a_from_b->GetSelfSize()); | 986 CHECK_EQ(0, a_from_b->GetSelfSize()); |
987 CHECK_EQ(0, a_from_b->GetInstancesCount()); | 987 CHECK_EQ(0, a_from_b->GetInstancesCount()); |
988 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing. | 988 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing. |
989 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A. | 989 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A. |
990 } | 990 } |
991 | 991 |
| 992 namespace { |
| 993 |
| 994 class TestJSONStream : public v8::OutputStream { |
| 995 public: |
| 996 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {} |
| 997 explicit TestJSONStream(int abort_countdown) |
| 998 : eos_signaled_(0), abort_countdown_(abort_countdown) {} |
| 999 virtual ~TestJSONStream() {} |
| 1000 virtual void EndOfStream() { ++eos_signaled_; } |
| 1001 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) { |
| 1002 if (abort_countdown_ > 0) --abort_countdown_; |
| 1003 if (abort_countdown_ == 0) return kAbort; |
| 1004 CHECK_GT(chars_written, 0); |
| 1005 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0'); |
| 1006 memcpy(chunk.start(), buffer, chars_written); |
| 1007 return kContinue; |
| 1008 } |
| 1009 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); } |
| 1010 int eos_signaled() { return eos_signaled_; } |
| 1011 int size() { return buffer_.size(); } |
| 1012 private: |
| 1013 i::Collector<char> buffer_; |
| 1014 int eos_signaled_; |
| 1015 int abort_countdown_; |
| 1016 }; |
| 1017 |
| 1018 class AsciiResource: public v8::String::ExternalAsciiStringResource { |
| 1019 public: |
| 1020 explicit AsciiResource(i::Vector<char> string): data_(string.start()) { |
| 1021 length_ = string.length(); |
| 1022 } |
| 1023 virtual const char* data() const { return data_; } |
| 1024 virtual size_t length() const { return length_; } |
| 1025 private: |
| 1026 const char* data_; |
| 1027 size_t length_; |
| 1028 }; |
| 1029 |
| 1030 } // namespace |
| 1031 |
| 1032 TEST(HeapSnapshotJSONSerialization) { |
| 1033 v8::HandleScope scope; |
| 1034 LocalContext env; |
| 1035 |
| 1036 #define STRING_LITERAL_FOR_TEST \ |
| 1037 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\"" |
| 1038 CompileAndRunScript( |
| 1039 "function A(s) { this.s = s; }\n" |
| 1040 "function B(x) { this.x = x; }\n" |
| 1041 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n" |
| 1042 "var b = new B(a);"); |
| 1043 const v8::HeapSnapshot* snapshot = |
| 1044 v8::HeapProfiler::TakeSnapshot(v8::String::New("json")); |
| 1045 TestJSONStream stream; |
| 1046 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); |
| 1047 CHECK_GT(stream.size(), 0); |
| 1048 CHECK_EQ(1, stream.eos_signaled()); |
| 1049 i::ScopedVector<char> json(stream.size()); |
| 1050 stream.WriteTo(json); |
| 1051 |
| 1052 // Verify that snapshot string is valid JSON. |
| 1053 AsciiResource json_res(json); |
| 1054 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res); |
| 1055 env->Global()->Set(v8::String::New("json_snapshot"), json_string); |
| 1056 v8::Local<v8::Value> snapshot_parse_result = CompileRun( |
| 1057 "var parsed = JSON.parse(json_snapshot); true;"); |
| 1058 CHECK(!snapshot_parse_result.IsEmpty()); |
| 1059 |
| 1060 // Verify that snapshot object has required fields. |
| 1061 v8::Local<v8::Object> parsed_snapshot = |
| 1062 env->Global()->Get(v8::String::New("parsed"))->ToObject(); |
| 1063 CHECK(parsed_snapshot->Has(v8::String::New("snapshot"))); |
| 1064 CHECK(parsed_snapshot->Has(v8::String::New("nodes"))); |
| 1065 CHECK(parsed_snapshot->Has(v8::String::New("strings"))); |
| 1066 |
| 1067 // Verify that nodes meta-info is valid JSON. |
| 1068 v8::Local<v8::Value> nodes_meta_parse_result = CompileRun( |
| 1069 "var parsed_meta = JSON.parse(parsed.nodes[0]); true;"); |
| 1070 CHECK(!nodes_meta_parse_result.IsEmpty()); |
| 1071 |
| 1072 // Get node and edge "member" offsets. |
| 1073 v8::Local<v8::Value> meta_analysis_result = CompileRun( |
| 1074 "var children_count_offset =" |
| 1075 " parsed_meta.fields.indexOf('children_count');\n" |
| 1076 "var children_offset =" |
| 1077 " parsed_meta.fields.indexOf('children');\n" |
| 1078 "var children_meta =" |
| 1079 " parsed_meta.types[children_offset];\n" |
| 1080 "var child_fields_count = children_meta.fields.length;\n" |
| 1081 "var child_type_offset =" |
| 1082 " children_meta.fields.indexOf('type');\n" |
| 1083 "var child_name_offset =" |
| 1084 " children_meta.fields.indexOf('name_or_index');\n" |
| 1085 "var child_to_node_offset =" |
| 1086 " children_meta.fields.indexOf('to_node');\n" |
| 1087 "var property_type =" |
| 1088 " children_meta.types[child_type_offset].indexOf('property');"); |
| 1089 CHECK(!meta_analysis_result.IsEmpty()); |
| 1090 |
| 1091 // A helper function for processing encoded nodes. |
| 1092 CompileRun( |
| 1093 "function GetChildPosByProperty(pos, prop_name) {\n" |
| 1094 " var nodes = parsed.nodes;\n" |
| 1095 " var strings = parsed.strings;\n" |
| 1096 " for (var i = 0,\n" |
| 1097 " count = nodes[pos + children_count_offset] * child_fields_count;\n" |
| 1098 " i < count; i += child_fields_count) {\n" |
| 1099 " var child_pos = pos + children_offset + i;\n" |
| 1100 " if (nodes[child_pos + child_type_offset] === property_type\n" |
| 1101 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n" |
| 1102 " return nodes[child_pos + child_to_node_offset];\n" |
| 1103 " }\n" |
| 1104 " return null;\n" |
| 1105 "}\n"); |
| 1106 // Get the string index using the path: <root> -> <global>.b.x.s |
| 1107 v8::Local<v8::Value> string_obj_pos_val = CompileRun( |
| 1108 "GetChildPosByProperty(\n" |
| 1109 " GetChildPosByProperty(\n" |
| 1110 " GetChildPosByProperty(" |
| 1111 " parsed.nodes[1 + children_offset + child_to_node_offset],\"b\"),\n" |
| 1112 " \"x\")," |
| 1113 " \"s\")"); |
| 1114 CHECK(!string_obj_pos_val.IsEmpty()); |
| 1115 int string_obj_pos = |
| 1116 static_cast<int>(string_obj_pos_val->ToNumber()->Value()); |
| 1117 v8::Local<v8::Object> nodes_array = |
| 1118 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject(); |
| 1119 int string_index = static_cast<int>( |
| 1120 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value()); |
| 1121 CHECK_GT(string_index, 0); |
| 1122 v8::Local<v8::Object> strings_array = |
| 1123 parsed_snapshot->Get(v8::String::New("strings"))->ToObject(); |
| 1124 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString(); |
| 1125 v8::Local<v8::String> ref_string = |
| 1126 CompileRun(STRING_LITERAL_FOR_TEST)->ToString(); |
| 1127 #undef STRING_LITERAL_FOR_TEST |
| 1128 CHECK_EQ(*v8::String::Utf8Value(ref_string), |
| 1129 *v8::String::Utf8Value(string)); |
| 1130 } |
| 1131 |
| 1132 |
| 1133 TEST(HeapSnapshotJSONSerializationAborting) { |
| 1134 v8::HandleScope scope; |
| 1135 LocalContext env; |
| 1136 const v8::HeapSnapshot* snapshot = |
| 1137 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort")); |
| 1138 TestJSONStream stream(5); |
| 1139 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON); |
| 1140 CHECK_GT(stream.size(), 0); |
| 1141 CHECK_EQ(0, stream.eos_signaled()); |
| 1142 } |
| 1143 |
992 #endif // ENABLE_LOGGING_AND_PROFILING | 1144 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |