OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 851 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 void HeapEntry::Init(HeapSnapshot* snapshot, | 862 void HeapEntry::Init(HeapSnapshot* snapshot, |
863 Type type, | 863 Type type, |
864 const char* name, | 864 const char* name, |
865 uint64_t id, | 865 uint64_t id, |
866 int self_size, | 866 int self_size, |
867 int children_count, | 867 int children_count, |
868 int retainers_count) { | 868 int retainers_count) { |
869 snapshot_ = snapshot; | 869 snapshot_ = snapshot; |
870 type_ = type; | 870 type_ = type; |
871 painted_ = kUnpainted; | 871 painted_ = kUnpainted; |
872 calculated_data_index_ = kNoCalculatedData; | |
873 name_ = name; | 872 name_ = name; |
874 id_ = id; | 873 id_ = id; |
875 self_size_ = self_size; | 874 self_size_ = self_size; |
| 875 retained_size_ = 0; |
876 children_count_ = children_count; | 876 children_count_ = children_count; |
877 retainers_count_ = retainers_count; | 877 retainers_count_ = retainers_count; |
| 878 dominator_ = NULL; |
878 } | 879 } |
879 | 880 |
880 | 881 |
881 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, | 882 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
882 int child_index, | 883 int child_index, |
883 const char* name, | 884 const char* name, |
884 HeapEntry* entry, | 885 HeapEntry* entry, |
885 int retainer_index) { | 886 int retainer_index) { |
886 children_arr()[child_index].Init(child_index, type, name, entry); | 887 children_arr()[child_index].Init(child_index, type, name, entry); |
887 entry->retainers_arr()[retainer_index] = children_arr() + child_index; | 888 entry->retainers_arr()[retainer_index] = children_arr() + child_index; |
888 } | 889 } |
889 | 890 |
890 | 891 |
891 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, | 892 void HeapEntry::SetIndexedReference(HeapGraphEdge::Type type, |
892 int child_index, | 893 int child_index, |
893 int index, | 894 int index, |
894 HeapEntry* entry, | 895 HeapEntry* entry, |
895 int retainer_index) { | 896 int retainer_index) { |
896 children_arr()[child_index].Init(child_index, type, index, entry); | 897 children_arr()[child_index].Init(child_index, type, index, entry); |
897 entry->retainers_arr()[retainer_index] = children_arr() + child_index; | 898 entry->retainers_arr()[retainer_index] = children_arr() + child_index; |
898 } | 899 } |
899 | 900 |
900 | 901 |
901 void HeapEntry::SetUnidirElementReference( | 902 void HeapEntry::SetUnidirElementReference( |
902 int child_index, int index, HeapEntry* entry) { | 903 int child_index, int index, HeapEntry* entry) { |
903 children_arr()[child_index].Init(child_index, index, entry); | 904 children_arr()[child_index].Init(child_index, index, entry); |
904 } | 905 } |
905 | 906 |
906 | 907 |
907 int HeapEntry::ReachableSize() { | 908 int HeapEntry::RetainedSize(bool exact) { |
908 if (calculated_data_index_ == kNoCalculatedData) { | 909 if (exact && (retained_size_ & kExactRetainedSizeTag) == 0) { |
909 calculated_data_index_ = snapshot_->AddCalculatedData(); | 910 CalculateExactRetainedSize(); |
910 } | 911 } |
911 return snapshot_->GetCalculatedData( | 912 return retained_size_ & (~kExactRetainedSizeTag); |
912 calculated_data_index_).ReachableSize(this); | |
913 } | |
914 | |
915 | |
916 int HeapEntry::RetainedSize() { | |
917 if (calculated_data_index_ == kNoCalculatedData) { | |
918 calculated_data_index_ = snapshot_->AddCalculatedData(); | |
919 } | |
920 return snapshot_->GetCalculatedData( | |
921 calculated_data_index_).RetainedSize(this); | |
922 } | 913 } |
923 | 914 |
924 | 915 |
925 List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() { | 916 List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() { |
926 if (calculated_data_index_ == kNoCalculatedData) { | 917 return snapshot_->GetRetainingPaths(this); |
927 calculated_data_index_ = snapshot_->AddCalculatedData(); | |
928 } | |
929 return snapshot_->GetCalculatedData( | |
930 calculated_data_index_).GetRetainingPaths(this); | |
931 } | 918 } |
932 | 919 |
933 | 920 |
934 template<class Visitor> | 921 template<class Visitor> |
935 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { | 922 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { |
936 List<HeapEntry*> list(10); | 923 List<HeapEntry*> list(10); |
937 list.Add(this); | 924 list.Add(this); |
938 this->paint_reachable(); | 925 this->paint_reachable(); |
939 visitor->Apply(this); | 926 visitor->Apply(this); |
940 while (!list.is_empty()) { | 927 while (!list.is_empty()) { |
(...skipping 17 matching lines...) Expand all Loading... |
958 void Apply(HeapEntry* entry) { } | 945 void Apply(HeapEntry* entry) { } |
959 }; | 946 }; |
960 | 947 |
961 void HeapEntry::PaintAllReachable() { | 948 void HeapEntry::PaintAllReachable() { |
962 NullClass null; | 949 NullClass null; |
963 ApplyAndPaintAllReachable(&null); | 950 ApplyAndPaintAllReachable(&null); |
964 } | 951 } |
965 | 952 |
966 | 953 |
967 void HeapEntry::Print(int max_depth, int indent) { | 954 void HeapEntry::Print(int max_depth, int indent) { |
968 OS::Print("%6d %6d %6d [%llu] ", | 955 OS::Print("%6d %6d [%llu] ", self_size(), RetainedSize(false), id_); |
969 self_size(), ReachableSize(), RetainedSize(), id_); | |
970 if (type() != kString) { | 956 if (type() != kString) { |
971 OS::Print("%s %.40s\n", TypeAsString(), name_); | 957 OS::Print("%s %.40s\n", TypeAsString(), name_); |
972 } else { | 958 } else { |
973 OS::Print("\""); | 959 OS::Print("\""); |
974 const char* c = name_; | 960 const char* c = name_; |
975 while (*c && (c - name_) <= 40) { | 961 while (*c && (c - name_) <= 40) { |
976 if (*c != '\n') | 962 if (*c != '\n') |
977 OS::Print("%c", *c); | 963 OS::Print("%c", *c); |
978 else | 964 else |
979 OS::Print("\\n"); | 965 OS::Print("\\n"); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1029 | 1015 |
1030 int HeapEntry::EntriesSize(int entries_count, | 1016 int HeapEntry::EntriesSize(int entries_count, |
1031 int children_count, | 1017 int children_count, |
1032 int retainers_count) { | 1018 int retainers_count) { |
1033 return sizeof(HeapEntry) * entries_count // NOLINT | 1019 return sizeof(HeapEntry) * entries_count // NOLINT |
1034 + sizeof(HeapGraphEdge) * children_count // NOLINT | 1020 + sizeof(HeapGraphEdge) * children_count // NOLINT |
1035 + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT | 1021 + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT |
1036 } | 1022 } |
1037 | 1023 |
1038 | 1024 |
1039 static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) { | |
1040 delete *path_ptr; | |
1041 } | |
1042 | |
1043 void HeapEntryCalculatedData::Dispose() { | |
1044 if (retaining_paths_ != NULL) retaining_paths_->Iterate(DeleteHeapGraphPath); | |
1045 delete retaining_paths_; | |
1046 } | |
1047 | |
1048 | |
1049 int HeapEntryCalculatedData::ReachableSize(HeapEntry* entry) { | |
1050 if (reachable_size_ == kUnknownSize) CalculateSizes(entry); | |
1051 return reachable_size_; | |
1052 } | |
1053 | |
1054 | |
1055 int HeapEntryCalculatedData::RetainedSize(HeapEntry* entry) { | |
1056 if (retained_size_ == kUnknownSize) CalculateSizes(entry); | |
1057 return retained_size_; | |
1058 } | |
1059 | |
1060 | |
1061 class ReachableSizeCalculator { | |
1062 public: | |
1063 ReachableSizeCalculator() | |
1064 : reachable_size_(0) { | |
1065 } | |
1066 | |
1067 int reachable_size() const { return reachable_size_; } | |
1068 | |
1069 void Apply(HeapEntry* entry) { | |
1070 reachable_size_ += entry->self_size(); | |
1071 } | |
1072 | |
1073 private: | |
1074 int reachable_size_; | |
1075 }; | |
1076 | |
1077 class RetainedSizeCalculator { | 1025 class RetainedSizeCalculator { |
1078 public: | 1026 public: |
1079 RetainedSizeCalculator() | 1027 RetainedSizeCalculator() |
1080 : retained_size_(0) { | 1028 : retained_size_(0) { |
1081 } | 1029 } |
1082 | 1030 |
1083 int reained_size() const { return retained_size_; } | 1031 int reained_size() const { return retained_size_; } |
1084 | 1032 |
1085 void Apply(HeapEntry** entry_ptr) { | 1033 void Apply(HeapEntry** entry_ptr) { |
1086 if ((*entry_ptr)->painted_reachable()) { | 1034 if ((*entry_ptr)->painted_reachable()) { |
1087 retained_size_ += (*entry_ptr)->self_size(); | 1035 retained_size_ += (*entry_ptr)->self_size(); |
1088 } | 1036 } |
1089 } | 1037 } |
1090 | 1038 |
1091 private: | 1039 private: |
1092 int retained_size_; | 1040 int retained_size_; |
1093 }; | 1041 }; |
1094 | 1042 |
1095 void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) { | 1043 void HeapEntry::CalculateExactRetainedSize() { |
1096 // To calculate retained size, first we paint all reachable nodes in | 1044 // To calculate retained size, first we paint all reachable nodes in |
1097 // one color (and calculate reachable size as a byproduct), then we | 1045 // one color, then we paint (or re-paint) all nodes reachable from |
1098 // paint (or re-paint) all nodes reachable from other nodes with a | 1046 // other nodes with a different color. Then we sum up self sizes of |
1099 // different color. Then we consider only nodes painted with the | 1047 // nodes painted with the first color. |
1100 // first color for calculating the retained size. | 1048 snapshot()->ClearPaint(); |
1101 entry->snapshot()->ClearPaint(); | 1049 PaintAllReachable(); |
1102 ReachableSizeCalculator rch_size_calc; | |
1103 entry->ApplyAndPaintAllReachable(&rch_size_calc); | |
1104 reachable_size_ = rch_size_calc.reachable_size(); | |
1105 | 1050 |
1106 List<HeapEntry*> list(10); | 1051 List<HeapEntry*> list(10); |
1107 HeapEntry* root = entry->snapshot()->root(); | 1052 HeapEntry* root = snapshot()->root(); |
1108 if (entry != root) { | 1053 if (this != root) { |
1109 list.Add(root); | 1054 list.Add(root); |
1110 root->paint_reachable_from_others(); | 1055 root->paint_reachable_from_others(); |
1111 } | 1056 } |
1112 while (!list.is_empty()) { | 1057 while (!list.is_empty()) { |
1113 HeapEntry* curr = list.RemoveLast(); | 1058 HeapEntry* curr = list.RemoveLast(); |
1114 Vector<HeapGraphEdge> children = curr->children(); | 1059 Vector<HeapGraphEdge> children = curr->children(); |
1115 for (int i = 0; i < children.length(); ++i) { | 1060 for (int i = 0; i < children.length(); ++i) { |
1116 if (children[i].type() == HeapGraphEdge::kShortcut) continue; | 1061 if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
1117 HeapEntry* child = children[i].to(); | 1062 HeapEntry* child = children[i].to(); |
1118 if (child != entry && child->not_painted_reachable_from_others()) { | 1063 if (child != this && child->not_painted_reachable_from_others()) { |
1119 list.Add(child); | 1064 list.Add(child); |
1120 child->paint_reachable_from_others(); | 1065 child->paint_reachable_from_others(); |
1121 } | 1066 } |
1122 } | 1067 } |
1123 } | 1068 } |
1124 | 1069 |
1125 RetainedSizeCalculator ret_size_calc; | 1070 RetainedSizeCalculator ret_size_calc; |
1126 entry->snapshot()->IterateEntries(&ret_size_calc); | 1071 snapshot()->IterateEntries(&ret_size_calc); |
1127 retained_size_ = ret_size_calc.reained_size(); | 1072 retained_size_ = ret_size_calc.reained_size(); |
| 1073 ASSERT((retained_size_ & kExactRetainedSizeTag) == 0); |
| 1074 retained_size_ |= kExactRetainedSizeTag; |
1128 } | 1075 } |
1129 | 1076 |
1130 | 1077 |
1131 class CachedHeapGraphPath { | 1078 class CachedHeapGraphPath { |
1132 public: | 1079 public: |
1133 CachedHeapGraphPath() | 1080 CachedHeapGraphPath() |
1134 : nodes_(NodesMatch) { } | 1081 : nodes_(NodesMatch) { } |
1135 CachedHeapGraphPath(const CachedHeapGraphPath& src) | 1082 CachedHeapGraphPath(const CachedHeapGraphPath& src) |
1136 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), | 1083 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), |
1137 path_(src.path_.length() + 1) { | 1084 path_(src.path_.length() + 1) { |
(...skipping 17 matching lines...) Expand all Loading... |
1155 static uint32_t Hash(HeapEntry* entry) { | 1102 static uint32_t Hash(HeapEntry* entry) { |
1156 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry)); | 1103 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry)); |
1157 } | 1104 } |
1158 static bool NodesMatch(void* key1, void* key2) { return key1 == key2; } | 1105 static bool NodesMatch(void* key1, void* key2) { return key1 == key2; } |
1159 | 1106 |
1160 HashMap nodes_; | 1107 HashMap nodes_; |
1161 List<HeapGraphEdge*> path_; | 1108 List<HeapGraphEdge*> path_; |
1162 }; | 1109 }; |
1163 | 1110 |
1164 | 1111 |
1165 List<HeapGraphPath*>* HeapEntryCalculatedData::GetRetainingPaths( | 1112 List<HeapGraphPath*>* HeapEntry::CalculateRetainingPaths() { |
1166 HeapEntry* entry) { | 1113 List<HeapGraphPath*>* retaining_paths = new List<HeapGraphPath*>(4); |
1167 if (retaining_paths_ == NULL) retaining_paths_ = new List<HeapGraphPath*>(4); | 1114 CachedHeapGraphPath path; |
1168 if (retaining_paths_->length() == 0 && entry->retainers().length() != 0) { | 1115 FindRetainingPaths(&path, retaining_paths); |
1169 CachedHeapGraphPath path; | 1116 return retaining_paths; |
1170 FindRetainingPaths(entry, &path); | |
1171 } | |
1172 return retaining_paths_; | |
1173 } | 1117 } |
1174 | 1118 |
1175 | 1119 |
1176 void HeapEntryCalculatedData::FindRetainingPaths( | 1120 void HeapEntry::FindRetainingPaths(CachedHeapGraphPath* prev_path, |
1177 HeapEntry* entry, | 1121 List<HeapGraphPath*>* retaining_paths) { |
1178 CachedHeapGraphPath* prev_path) { | 1122 Vector<HeapGraphEdge*> rets = retainers(); |
1179 Vector<HeapGraphEdge*> retainers = entry->retainers(); | 1123 for (int i = 0; i < rets.length(); ++i) { |
1180 for (int i = 0; i < retainers.length(); ++i) { | 1124 HeapGraphEdge* ret_edge = rets[i]; |
1181 HeapGraphEdge* ret_edge = retainers[i]; | |
1182 if (prev_path->ContainsNode(ret_edge->From())) continue; | 1125 if (prev_path->ContainsNode(ret_edge->From())) continue; |
1183 if (ret_edge->From() != entry->snapshot()->root()) { | 1126 if (ret_edge->From() != snapshot()->root()) { |
1184 CachedHeapGraphPath path(*prev_path); | 1127 CachedHeapGraphPath path(*prev_path); |
1185 path.Add(ret_edge); | 1128 path.Add(ret_edge); |
1186 FindRetainingPaths(ret_edge->From(), &path); | 1129 ret_edge->From()->FindRetainingPaths(&path, retaining_paths); |
1187 } else { | 1130 } else { |
1188 HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path()); | 1131 HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path()); |
1189 ret_path->Set(0, ret_edge); | 1132 ret_path->Set(0, ret_edge); |
1190 retaining_paths_->Add(ret_path); | 1133 retaining_paths->Add(ret_path); |
1191 } | 1134 } |
1192 } | 1135 } |
1193 } | 1136 } |
1194 | 1137 |
1195 | 1138 |
1196 HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path) | 1139 HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path) |
1197 : path_(path.length() + 1) { | 1140 : path_(path.length() + 1) { |
1198 Add(NULL); | 1141 Add(NULL); |
1199 for (int i = path.length() - 1; i >= 0; --i) { | 1142 for (int i = path.length() - 1; i >= 0; --i) { |
1200 Add(path[i]); | 1143 Add(path[i]); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1240 | 1183 |
1241 | 1184 |
1242 // It is very important to keep objects that form a heap snapshot | 1185 // It is very important to keep objects that form a heap snapshot |
1243 // as small as possible. | 1186 // as small as possible. |
1244 namespace { // Avoid littering the global namespace. | 1187 namespace { // Avoid littering the global namespace. |
1245 | 1188 |
1246 template <size_t ptr_size> struct SnapshotSizeConstants; | 1189 template <size_t ptr_size> struct SnapshotSizeConstants; |
1247 | 1190 |
1248 template <> struct SnapshotSizeConstants<4> { | 1191 template <> struct SnapshotSizeConstants<4> { |
1249 static const int kExpectedHeapGraphEdgeSize = 12; | 1192 static const int kExpectedHeapGraphEdgeSize = 12; |
1250 static const int kExpectedHeapEntrySize = 32; | 1193 static const int kExpectedHeapEntrySize = 36; |
1251 }; | 1194 }; |
1252 | 1195 |
1253 template <> struct SnapshotSizeConstants<8> { | 1196 template <> struct SnapshotSizeConstants<8> { |
1254 static const int kExpectedHeapGraphEdgeSize = 24; | 1197 static const int kExpectedHeapGraphEdgeSize = 24; |
1255 static const int kExpectedHeapEntrySize = 40; | 1198 static const int kExpectedHeapEntrySize = 48; |
1256 }; | 1199 }; |
1257 | 1200 |
1258 } // namespace | 1201 } // namespace |
1259 | 1202 |
1260 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, | 1203 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
1261 HeapSnapshot::Type type, | 1204 HeapSnapshot::Type type, |
1262 const char* title, | 1205 const char* title, |
1263 unsigned uid) | 1206 unsigned uid) |
1264 : collection_(collection), | 1207 : collection_(collection), |
1265 type_(type), | 1208 type_(type), |
1266 title_(title), | 1209 title_(title), |
1267 uid_(uid), | 1210 uid_(uid), |
1268 root_entry_(NULL), | 1211 root_entry_(NULL), |
1269 gc_roots_entry_(NULL), | 1212 gc_roots_entry_(NULL), |
1270 raw_entries_(NULL), | 1213 raw_entries_(NULL), |
1271 entries_sorted_(false) { | 1214 entries_sorted_(false), |
| 1215 retaining_paths_(HeapEntry::Match) { |
1272 STATIC_ASSERT( | 1216 STATIC_ASSERT( |
1273 sizeof(HeapGraphEdge) == | 1217 sizeof(HeapGraphEdge) == |
1274 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOL
INT | 1218 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOL
INT |
1275 STATIC_ASSERT( | 1219 STATIC_ASSERT( |
1276 sizeof(HeapEntry) == | 1220 sizeof(HeapEntry) == |
1277 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT | 1221 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT |
1278 } | 1222 } |
1279 | 1223 |
1280 | 1224 |
1281 static void DisposeCalculatedData(HeapEntryCalculatedData* cdata) { | 1225 static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) { |
1282 cdata->Dispose(); | 1226 delete *path_ptr; |
1283 } | 1227 } |
1284 | 1228 |
1285 HeapSnapshot::~HeapSnapshot() { | 1229 HeapSnapshot::~HeapSnapshot() { |
1286 DeleteArray(raw_entries_); | 1230 DeleteArray(raw_entries_); |
1287 calculated_data_.Iterate(DisposeCalculatedData); | 1231 for (HashMap::Entry* p = retaining_paths_.Start(); |
| 1232 p != NULL; |
| 1233 p = retaining_paths_.Next(p)) { |
| 1234 List<HeapGraphPath*>* list = |
| 1235 reinterpret_cast<List<HeapGraphPath*>*>(p->value); |
| 1236 list->Iterate(DeleteHeapGraphPath); |
| 1237 delete list; |
| 1238 } |
1288 } | 1239 } |
1289 | 1240 |
1290 | 1241 |
1291 void HeapSnapshot::AllocateEntries(int entries_count, | 1242 void HeapSnapshot::AllocateEntries(int entries_count, |
1292 int children_count, | 1243 int children_count, |
1293 int retainers_count) { | 1244 int retainers_count) { |
1294 ASSERT(raw_entries_ == NULL); | 1245 ASSERT(raw_entries_ == NULL); |
1295 raw_entries_ = NewArray<char>( | 1246 raw_entries_ = NewArray<char>( |
1296 HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); | 1247 HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); |
1297 #ifdef DEBUG | 1248 #ifdef DEBUG |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1393 | 1344 |
1394 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { | 1345 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
1395 (*entry_ptr)->clear_paint(); | 1346 (*entry_ptr)->clear_paint(); |
1396 } | 1347 } |
1397 | 1348 |
1398 void HeapSnapshot::ClearPaint() { | 1349 void HeapSnapshot::ClearPaint() { |
1399 entries_.Iterate(HeapEntryClearPaint); | 1350 entries_.Iterate(HeapEntryClearPaint); |
1400 } | 1351 } |
1401 | 1352 |
1402 | 1353 |
1403 int HeapSnapshot::AddCalculatedData() { | |
1404 calculated_data_.Add(HeapEntryCalculatedData()); | |
1405 return calculated_data_.length() - 1; | |
1406 } | |
1407 | |
1408 | |
1409 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, | 1354 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
1410 HeapEntry::Type type, | 1355 HeapEntry::Type type, |
1411 const char* name, | 1356 const char* name, |
1412 int children_count, | 1357 int children_count, |
1413 int retainers_count) { | 1358 int retainers_count) { |
1414 return AddEntry(type, | 1359 return AddEntry(type, |
1415 name, | 1360 name, |
1416 collection_->GetObjectId(object->address()), | 1361 collection_->GetObjectId(object->address()), |
1417 object->Size(), | 1362 object->Size(), |
1418 children_count, | 1363 children_count, |
1419 retainers_count); | 1364 retainers_count); |
1420 } | 1365 } |
1421 | 1366 |
1422 | 1367 |
1423 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, | 1368 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
1424 const char* name, | 1369 const char* name, |
1425 uint64_t id, | 1370 uint64_t id, |
1426 int size, | 1371 int size, |
1427 int children_count, | 1372 int children_count, |
1428 int retainers_count) { | 1373 int retainers_count) { |
1429 HeapEntry* entry = GetNextEntryToInit(); | 1374 HeapEntry* entry = GetNextEntryToInit(); |
1430 entry->Init(this, type, name, id, size, children_count, retainers_count); | 1375 entry->Init(this, type, name, id, size, children_count, retainers_count); |
1431 return entry; | 1376 return entry; |
1432 } | 1377 } |
1433 | 1378 |
1434 | 1379 |
| 1380 void HeapSnapshot::FillReversePostorderIndexes(Vector<HeapEntry*>* entries) { |
| 1381 ClearPaint(); |
| 1382 int current_entry = 0; |
| 1383 List<HeapEntry*> nodes_to_visit; |
| 1384 nodes_to_visit.Add(root()); |
| 1385 root()->paint_reachable(); |
| 1386 while (!nodes_to_visit.is_empty()) { |
| 1387 HeapEntry* entry = nodes_to_visit.last(); |
| 1388 Vector<HeapGraphEdge> children = entry->children(); |
| 1389 bool has_new_edges = false; |
| 1390 for (int i = 0; i < children.length(); ++i) { |
| 1391 if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
| 1392 HeapEntry* child = children[i].to(); |
| 1393 if (!child->painted_reachable()) { |
| 1394 nodes_to_visit.Add(child); |
| 1395 child->paint_reachable(); |
| 1396 has_new_edges = true; |
| 1397 } |
| 1398 } |
| 1399 if (!has_new_edges) { |
| 1400 entry->set_ordered_index(current_entry); |
| 1401 entries->at(current_entry++) = entry; |
| 1402 nodes_to_visit.RemoveLast(); |
| 1403 } |
| 1404 } |
| 1405 entries->Truncate(current_entry); |
| 1406 } |
| 1407 |
| 1408 |
| 1409 static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) { |
| 1410 int finger1 = i1, finger2 = i2; |
| 1411 while (finger1 != finger2) { |
| 1412 while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index(); |
| 1413 while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index(); |
| 1414 } |
| 1415 return finger1; |
| 1416 } |
| 1417 |
| 1418 // The algorithm is based on the article: |
| 1419 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
| 1420 // Softw. Pract. Exper. 4 (2001), pp. 1–10. |
| 1421 void HeapSnapshot::BuildDominatorTree(const Vector<HeapEntry*>& entries, |
| 1422 Vector<HeapEntry*>* dominators) { |
| 1423 if (entries.length() == 0) return; |
| 1424 const int root_index = entries.length() - 1; |
| 1425 for (int i = 0; i < root_index; ++i) dominators->at(i) = NULL; |
| 1426 dominators->at(root_index) = entries[root_index]; |
| 1427 bool changed = true; |
| 1428 while (changed) { |
| 1429 changed = false; |
| 1430 for (int i = root_index - 1; i >= 0; --i) { |
| 1431 HeapEntry* new_idom = NULL; |
| 1432 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
| 1433 int j = 0; |
| 1434 for (; j < rets.length(); ++j) { |
| 1435 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; |
| 1436 HeapEntry* ret = rets[j]->From(); |
| 1437 if (dominators->at(ret->ordered_index()) != NULL) { |
| 1438 new_idom = ret; |
| 1439 break; |
| 1440 } |
| 1441 } |
| 1442 for (++j; j < rets.length(); ++j) { |
| 1443 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; |
| 1444 HeapEntry* ret = rets[j]->From(); |
| 1445 if (dominators->at(ret->ordered_index()) != NULL) { |
| 1446 new_idom = entries[Intersect(ret->ordered_index(), |
| 1447 new_idom->ordered_index(), |
| 1448 *dominators)]; |
| 1449 } |
| 1450 } |
| 1451 if (new_idom != NULL && dominators->at(i) != new_idom) { |
| 1452 dominators->at(i) = new_idom; |
| 1453 changed = true; |
| 1454 } |
| 1455 } |
| 1456 } |
| 1457 } |
| 1458 |
| 1459 |
| 1460 void HeapSnapshot::SetEntriesDominators() { |
| 1461 // This array is used for maintaining reverse postorder of nodes. |
| 1462 ScopedVector<HeapEntry*> ordered_entries(entries_.length()); |
| 1463 FillReversePostorderIndexes(&ordered_entries); |
| 1464 ScopedVector<HeapEntry*> dominators(ordered_entries.length()); |
| 1465 BuildDominatorTree(ordered_entries, &dominators); |
| 1466 for (int i = 0; i < ordered_entries.length(); ++i) { |
| 1467 ASSERT(dominators[i] != NULL); |
| 1468 ordered_entries[i]->set_dominator(dominators[i]); |
| 1469 } |
| 1470 // For nodes unreachable from root, set dominator to itself. |
| 1471 for (int i = 0; i < entries_.length(); ++i) { |
| 1472 HeapEntry* entry = entries_[i]; |
| 1473 if (entry->dominator() == NULL) entry->set_dominator(entry); |
| 1474 } |
| 1475 } |
| 1476 |
| 1477 |
| 1478 void HeapSnapshot::ApproximateRetainedSizes() { |
| 1479 SetEntriesDominators(); |
| 1480 // As for the dominators tree we only know parent nodes, not |
| 1481 // children, to sum up total sizes we traverse the tree level by |
| 1482 // level upwards, starting from leaves. |
| 1483 for (int i = 0; i < entries_.length(); ++i) { |
| 1484 HeapEntry* entry = entries_[i]; |
| 1485 entry->set_retained_size(entry->self_size()); |
| 1486 entry->set_leaf(); |
| 1487 } |
| 1488 while (true) { |
| 1489 bool onlyLeaves = true; |
| 1490 for (int i = 0; i < entries_.length(); ++i) { |
| 1491 HeapEntry *entry = entries_[i], *dominator = entry->dominator(); |
| 1492 if (!entry->is_processed() && dominator != entry) { |
| 1493 dominator->set_non_leaf(); |
| 1494 onlyLeaves = false; |
| 1495 } |
| 1496 } |
| 1497 if (onlyLeaves) break; |
| 1498 |
| 1499 for (int i = 0; i < entries_.length(); ++i) { |
| 1500 HeapEntry *entry = entries_[i], *dominator = entry->dominator(); |
| 1501 if (entry->is_leaf() && dominator != entry) { |
| 1502 dominator->add_retained_size(entry->retained_size()); |
| 1503 } |
| 1504 } |
| 1505 |
| 1506 // Mark all current leaves as processed, reset non-leaves back to leaves. |
| 1507 for (int i = 0; i < entries_.length(); ++i) { |
| 1508 HeapEntry* entry = entries_[i]; |
| 1509 if (entry->is_leaf()) |
| 1510 entry->set_processed(); |
| 1511 else if (entry->is_non_leaf()) |
| 1512 entry->set_leaf(); |
| 1513 } |
| 1514 } |
| 1515 } |
| 1516 |
| 1517 |
1435 HeapEntry* HeapSnapshot::GetNextEntryToInit() { | 1518 HeapEntry* HeapSnapshot::GetNextEntryToInit() { |
1436 if (entries_.length() > 0) { | 1519 if (entries_.length() > 0) { |
1437 HeapEntry* last_entry = entries_.last(); | 1520 HeapEntry* last_entry = entries_.last(); |
1438 entries_.Add(reinterpret_cast<HeapEntry*>( | 1521 entries_.Add(reinterpret_cast<HeapEntry*>( |
1439 reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); | 1522 reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); |
1440 } else { | 1523 } else { |
1441 entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); | 1524 entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); |
1442 } | 1525 } |
1443 ASSERT(reinterpret_cast<char*>(entries_.last()) < | 1526 ASSERT(reinterpret_cast<char*>(entries_.last()) < |
1444 (raw_entries_ + raw_entries_size_)); | 1527 (raw_entries_ + raw_entries_size_)); |
1445 return entries_.last(); | 1528 return entries_.last(); |
1446 } | 1529 } |
1447 | 1530 |
1448 | 1531 |
1449 HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { | 1532 HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { |
1450 return collection_->CompareSnapshots(this, snapshot); | 1533 return collection_->CompareSnapshots(this, snapshot); |
1451 } | 1534 } |
1452 | 1535 |
1453 | 1536 |
| 1537 List<HeapGraphPath*>* HeapSnapshot::GetRetainingPaths(HeapEntry* entry) { |
| 1538 HashMap::Entry* p = |
| 1539 retaining_paths_.Lookup(entry, HeapEntry::Hash(entry), true); |
| 1540 if (p->value == NULL) { |
| 1541 p->value = entry->CalculateRetainingPaths(); |
| 1542 } |
| 1543 return reinterpret_cast<List<HeapGraphPath*>*>(p->value); |
| 1544 } |
| 1545 |
| 1546 |
1454 template<class T> | 1547 template<class T> |
1455 static int SortByIds(const T* entry1_ptr, | 1548 static int SortByIds(const T* entry1_ptr, |
1456 const T* entry2_ptr) { | 1549 const T* entry2_ptr) { |
1457 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; | 1550 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
1458 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; | 1551 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
1459 } | 1552 } |
1460 | 1553 |
1461 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { | 1554 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
1462 if (!entries_sorted_) { | 1555 if (!entries_sorted_) { |
1463 entries_.Sort(SortByIds); | 1556 entries_.Sort(SortByIds); |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1889 | 1982 |
1890 // Pass 2. Fill references. | 1983 // Pass 2. Fill references. |
1891 SnapshotFiller filler(snapshot_, &entries_); | 1984 SnapshotFiller filler(snapshot_, &entries_); |
1892 filler_ = &filler; | 1985 filler_ = &filler; |
1893 iterator.reset(); | 1986 iterator.reset(); |
1894 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 1987 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
1895 ExtractReferences(obj); | 1988 ExtractReferences(obj); |
1896 } | 1989 } |
1897 SetRootGcRootsReference(); | 1990 SetRootGcRootsReference(); |
1898 Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG); | 1991 Heap::IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| 1992 |
| 1993 snapshot_->ApproximateRetainedSizes(); |
1899 } | 1994 } |
1900 | 1995 |
1901 | 1996 |
1902 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { | 1997 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { |
1903 if (!obj->IsHeapObject()) return NULL; | 1998 if (!obj->IsHeapObject()) return NULL; |
1904 HeapObject* object = HeapObject::cast(obj); | 1999 HeapObject* object = HeapObject::cast(obj); |
1905 HeapEntry* entry = entries_.Map(object); | 2000 HeapEntry* entry = entries_.Map(object); |
1906 // A new entry. | 2001 // A new entry. |
1907 if (entry == NULL) entry = filler_->AddEntry(object); | 2002 if (entry == NULL) entry = filler_->AddEntry(object); |
1908 return entry; | 2003 return entry; |
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2464 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 2559 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
2465 writer_->AddCharacter('\n'); | 2560 writer_->AddCharacter('\n'); |
2466 writer_->AddCharacter(','); | 2561 writer_->AddCharacter(','); |
2467 writer_->AddNumber(entry->type()); | 2562 writer_->AddNumber(entry->type()); |
2468 writer_->AddCharacter(','); | 2563 writer_->AddCharacter(','); |
2469 writer_->AddNumber(GetStringId(entry->name())); | 2564 writer_->AddNumber(GetStringId(entry->name())); |
2470 writer_->AddCharacter(','); | 2565 writer_->AddCharacter(','); |
2471 writer_->AddNumber(entry->id()); | 2566 writer_->AddNumber(entry->id()); |
2472 writer_->AddCharacter(','); | 2567 writer_->AddCharacter(','); |
2473 writer_->AddNumber(entry->self_size()); | 2568 writer_->AddNumber(entry->self_size()); |
| 2569 writer_->AddCharacter(','); |
| 2570 writer_->AddNumber(entry->RetainedSize(false)); |
| 2571 writer_->AddCharacter(','); |
| 2572 writer_->AddNumber(GetNodeId(entry->dominator())); |
2474 Vector<HeapGraphEdge> children = entry->children(); | 2573 Vector<HeapGraphEdge> children = entry->children(); |
2475 writer_->AddCharacter(','); | 2574 writer_->AddCharacter(','); |
2476 writer_->AddNumber(children.length()); | 2575 writer_->AddNumber(children.length()); |
2477 for (int i = 0; i < children.length(); ++i) { | 2576 for (int i = 0; i < children.length(); ++i) { |
2478 SerializeEdge(&children[i]); | 2577 SerializeEdge(&children[i]); |
2479 if (writer_->aborted()) return; | 2578 if (writer_->aborted()) return; |
2480 } | 2579 } |
2481 } | 2580 } |
2482 | 2581 |
2483 | 2582 |
2484 void HeapSnapshotJSONSerializer::SerializeNodes() { | 2583 void HeapSnapshotJSONSerializer::SerializeNodes() { |
2485 // The first (zero) item of nodes array is an object describing node | 2584 // The first (zero) item of nodes array is an object describing node |
2486 // serialization layout. We use a set of macros to improve | 2585 // serialization layout. We use a set of macros to improve |
2487 // readability. | 2586 // readability. |
2488 #define JSON_A(s) "["s"]" | 2587 #define JSON_A(s) "["s"]" |
2489 #define JSON_O(s) "{"s"}" | 2588 #define JSON_O(s) "{"s"}" |
2490 #define JSON_S(s) "\""s"\"" | 2589 #define JSON_S(s) "\""s"\"" |
2491 writer_->AddString(JSON_O( | 2590 writer_->AddString(JSON_O( |
2492 JSON_S("fields") ":" JSON_A( | 2591 JSON_S("fields") ":" JSON_A( |
2493 JSON_S("type") | 2592 JSON_S("type") |
2494 "," JSON_S("name") | 2593 "," JSON_S("name") |
2495 "," JSON_S("id") | 2594 "," JSON_S("id") |
2496 "," JSON_S("self_size") | 2595 "," JSON_S("self_size") |
| 2596 "," JSON_S("retained_size") |
| 2597 "," JSON_S("dominator") |
2497 "," JSON_S("children_count") | 2598 "," JSON_S("children_count") |
2498 "," JSON_S("children")) | 2599 "," JSON_S("children")) |
2499 "," JSON_S("types") ":" JSON_A( | 2600 "," JSON_S("types") ":" JSON_A( |
2500 JSON_A( | 2601 JSON_A( |
2501 JSON_S("hidden") | 2602 JSON_S("hidden") |
2502 "," JSON_S("array") | 2603 "," JSON_S("array") |
2503 "," JSON_S("string") | 2604 "," JSON_S("string") |
2504 "," JSON_S("object") | 2605 "," JSON_S("object") |
2505 "," JSON_S("code") | 2606 "," JSON_S("code") |
2506 "," JSON_S("closure") | 2607 "," JSON_S("closure") |
2507 "," JSON_S("regexp") | 2608 "," JSON_S("regexp") |
2508 "," JSON_S("number")) | 2609 "," JSON_S("number")) |
2509 "," JSON_S("string") | 2610 "," JSON_S("string") |
2510 "," JSON_S("number") | 2611 "," JSON_S("number") |
2511 "," JSON_S("number") | 2612 "," JSON_S("number") |
2512 "," JSON_S("number") | 2613 "," JSON_S("number") |
| 2614 "," JSON_S("number") |
| 2615 "," JSON_S("number") |
2513 "," JSON_O( | 2616 "," JSON_O( |
2514 JSON_S("fields") ":" JSON_A( | 2617 JSON_S("fields") ":" JSON_A( |
2515 JSON_S("type") | 2618 JSON_S("type") |
2516 "," JSON_S("name_or_index") | 2619 "," JSON_S("name_or_index") |
2517 "," JSON_S("to_node")) | 2620 "," JSON_S("to_node")) |
2518 "," JSON_S("types") ":" JSON_A( | 2621 "," JSON_S("types") ":" JSON_A( |
2519 JSON_A( | 2622 JSON_A( |
2520 JSON_S("context") | 2623 JSON_S("context") |
2521 "," JSON_S("element") | 2624 "," JSON_S("element") |
2522 "," JSON_S("property") | 2625 "," JSON_S("property") |
2523 "," JSON_S("internal") | 2626 "," JSON_S("internal") |
2524 "," JSON_S("hidden") | 2627 "," JSON_S("hidden") |
2525 "," JSON_S("shortcut")) | 2628 "," JSON_S("shortcut")) |
2526 "," JSON_S("string_or_number") | 2629 "," JSON_S("string_or_number") |
2527 "," JSON_S("node")))))); | 2630 "," JSON_S("node")))))); |
2528 #undef JSON_S | 2631 #undef JSON_S |
2529 #undef JSON_O | 2632 #undef JSON_O |
2530 #undef JSON_A | 2633 #undef JSON_A |
2531 | 2634 |
2532 const int node_fields_count = 5; // type,name,id,self_size,children_count. | 2635 const int node_fields_count = 7; |
| 2636 // type,name,id,self_size,retained_size,dominator,children_count. |
2533 const int edge_fields_count = 3; // type,name|index,to_node. | 2637 const int edge_fields_count = 3; // type,name|index,to_node. |
2534 List<HashMap::Entry*> sorted_nodes; | 2638 List<HashMap::Entry*> sorted_nodes; |
2535 SortHashMap(&nodes_, &sorted_nodes); | 2639 SortHashMap(&nodes_, &sorted_nodes); |
2536 // Rewrite node ids, so they refer to actual array positions. | 2640 // Rewrite node ids, so they refer to actual array positions. |
2537 if (sorted_nodes.length() > 1) { | 2641 if (sorted_nodes.length() > 1) { |
2538 // Nodes start from array index 1. | 2642 // Nodes start from array index 1. |
2539 int prev_value = 1; | 2643 int prev_value = 1; |
2540 sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value); | 2644 sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value); |
2541 for (int i = 1; i < sorted_nodes.length(); ++i) { | 2645 for (int i = 1; i < sorted_nodes.length(); ++i) { |
2542 HeapEntry* prev_heap_entry = | 2646 HeapEntry* prev_heap_entry = |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2651 void HeapSnapshotJSONSerializer::SortHashMap( | 2755 void HeapSnapshotJSONSerializer::SortHashMap( |
2652 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 2756 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
2653 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 2757 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
2654 sorted_entries->Add(p); | 2758 sorted_entries->Add(p); |
2655 sorted_entries->Sort(SortUsingEntryValue); | 2759 sorted_entries->Sort(SortUsingEntryValue); |
2656 } | 2760 } |
2657 | 2761 |
2658 } } // namespace v8::internal | 2762 } } // namespace v8::internal |
2659 | 2763 |
2660 #endif // ENABLE_LOGGING_AND_PROFILING | 2764 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |