Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(90)

Side by Side Diff: src/profile-generator.cc

Issue 5154007: New heap profiler: implement fast retaining sizes approximation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698