Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 1065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 OS::Print("\\n"); | 1076 OS::Print("\\n"); |
| 1077 ++c; | 1077 ++c; |
| 1078 } | 1078 } |
| 1079 OS::Print("\"\n"); | 1079 OS::Print("\"\n"); |
| 1080 } | 1080 } |
| 1081 if (--max_depth == 0) return; | 1081 if (--max_depth == 0) return; |
| 1082 Vector<HeapGraphEdge> ch = children(); | 1082 Vector<HeapGraphEdge> ch = children(); |
| 1083 for (int i = 0; i < ch.length(); ++i) { | 1083 for (int i = 0; i < ch.length(); ++i) { |
| 1084 HeapGraphEdge& edge = ch[i]; | 1084 HeapGraphEdge& edge = ch[i]; |
| 1085 const char* edge_prefix = ""; | 1085 const char* edge_prefix = ""; |
| 1086 ScopedVector<char> index(64); | 1086 EmbeddedVector<char, 64> index; |
| 1087 const char* edge_name = index.start(); | 1087 const char* edge_name = index.start(); |
| 1088 switch (edge.type()) { | 1088 switch (edge.type()) { |
| 1089 case HeapGraphEdge::kContextVariable: | 1089 case HeapGraphEdge::kContextVariable: |
| 1090 edge_prefix = "#"; | 1090 edge_prefix = "#"; |
| 1091 edge_name = edge.name(); | 1091 edge_name = edge.name(); |
| 1092 break; | 1092 break; |
| 1093 case HeapGraphEdge::kElement: | 1093 case HeapGraphEdge::kElement: |
| 1094 OS::SNPrintF(index, "%d", edge.index()); | 1094 OS::SNPrintF(index, "%d", edge.index()); |
| 1095 break; | 1095 break; |
| 1096 case HeapGraphEdge::kInternal: | 1096 case HeapGraphEdge::kInternal: |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1157 void Apply(HeapEntry** entry_ptr) { | 1157 void Apply(HeapEntry** entry_ptr) { |
| 1158 if ((*entry_ptr)->painted_reachable()) { | 1158 if ((*entry_ptr)->painted_reachable()) { |
| 1159 retained_size_ += (*entry_ptr)->self_size(); | 1159 retained_size_ += (*entry_ptr)->self_size(); |
| 1160 } | 1160 } |
| 1161 } | 1161 } |
| 1162 | 1162 |
| 1163 private: | 1163 private: |
| 1164 int retained_size_; | 1164 int retained_size_; |
| 1165 }; | 1165 }; |
| 1166 | 1166 |
| 1167 | |
| 1167 void HeapEntry::CalculateExactRetainedSize() { | 1168 void HeapEntry::CalculateExactRetainedSize() { |
| 1168 // To calculate retained size, first we paint all reachable nodes in | 1169 // To calculate retained size, first we paint all reachable nodes in |
| 1169 // one color, then we paint (or re-paint) all nodes reachable from | 1170 // one color, then we paint (or re-paint) all nodes reachable from |
| 1170 // other nodes with a different color. Then we sum up self sizes of | 1171 // other nodes with a different color. Then we sum up self sizes of |
| 1171 // nodes painted with the first color. | 1172 // nodes painted with the first color. |
| 1172 snapshot()->ClearPaint(); | 1173 snapshot()->ClearPaint(); |
| 1173 PaintAllReachable(); | 1174 PaintAllReachable(); |
| 1174 | 1175 |
| 1175 List<HeapEntry*> list(10); | 1176 List<HeapEntry*> list(10); |
| 1176 HeapEntry* root = snapshot()->root(); | 1177 HeapEntry* root = snapshot()->root(); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1236 sizeof(HeapGraphEdge) == | 1237 sizeof(HeapGraphEdge) == |
| 1237 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); | 1238 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); |
| 1238 STATIC_ASSERT( | 1239 STATIC_ASSERT( |
| 1239 sizeof(HeapEntry) == | 1240 sizeof(HeapEntry) == |
| 1240 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); | 1241 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); |
| 1241 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { | 1242 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { |
| 1242 gc_subroot_entries_[i] = NULL; | 1243 gc_subroot_entries_[i] = NULL; |
| 1243 } | 1244 } |
| 1244 } | 1245 } |
| 1245 | 1246 |
| 1247 | |
| 1246 HeapSnapshot::~HeapSnapshot() { | 1248 HeapSnapshot::~HeapSnapshot() { |
| 1247 DeleteArray(raw_entries_); | 1249 DeleteArray(raw_entries_); |
| 1248 } | 1250 } |
| 1249 | 1251 |
| 1250 | 1252 |
| 1251 void HeapSnapshot::Delete() { | 1253 void HeapSnapshot::Delete() { |
| 1252 collection_->RemoveSnapshot(this); | 1254 collection_->RemoveSnapshot(this); |
| 1253 delete this; | 1255 delete this; |
| 1254 } | 1256 } |
| 1255 | 1257 |
| 1256 | 1258 |
| 1257 void HeapSnapshot::AllocateEntries(int entries_count, | 1259 void HeapSnapshot::AllocateEntries(int entries_count, |
| 1258 int children_count, | 1260 int children_count, |
| 1259 int retainers_count) { | 1261 int retainers_count) { |
| 1260 ASSERT(raw_entries_ == NULL); | 1262 ASSERT(raw_entries_ == NULL); |
| 1261 raw_entries_size_ = | 1263 raw_entries_size_ = |
| 1262 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); | 1264 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); |
| 1263 raw_entries_ = NewArray<char>(raw_entries_size_); | 1265 raw_entries_ = NewArray<char>(raw_entries_size_); |
| 1264 } | 1266 } |
| 1265 | 1267 |
| 1266 | 1268 |
| 1267 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { | 1269 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
| 1268 (*entry_ptr)->clear_paint(); | 1270 (*entry_ptr)->clear_paint(); |
| 1269 } | 1271 } |
| 1270 | 1272 |
| 1273 | |
| 1271 void HeapSnapshot::ClearPaint() { | 1274 void HeapSnapshot::ClearPaint() { |
| 1272 entries_.Iterate(HeapEntryClearPaint); | 1275 entries_.Iterate(HeapEntryClearPaint); |
| 1273 } | 1276 } |
| 1274 | 1277 |
| 1275 | 1278 |
| 1276 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { | 1279 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
| 1277 ASSERT(root_entry_ == NULL); | 1280 ASSERT(root_entry_ == NULL); |
| 1278 return (root_entry_ = AddEntry(HeapEntry::kObject, | 1281 return (root_entry_ = AddEntry(HeapEntry::kObject, |
| 1279 "", | 1282 "", |
| 1280 HeapObjectsMap::kInternalRootObjectId, | 1283 HeapObjectsMap::kInternalRootObjectId, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1366 } | 1369 } |
| 1367 | 1370 |
| 1368 | 1371 |
| 1369 template<class T> | 1372 template<class T> |
| 1370 static int SortByIds(const T* entry1_ptr, | 1373 static int SortByIds(const T* entry1_ptr, |
| 1371 const T* entry2_ptr) { | 1374 const T* entry2_ptr) { |
| 1372 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; | 1375 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
| 1373 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; | 1376 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
| 1374 } | 1377 } |
| 1375 | 1378 |
| 1379 | |
| 1376 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { | 1380 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
| 1377 if (!entries_sorted_) { | 1381 if (!entries_sorted_) { |
| 1378 entries_.Sort(SortByIds); | 1382 entries_.Sort(SortByIds); |
| 1379 entries_sorted_ = true; | 1383 entries_sorted_ = true; |
| 1380 } | 1384 } |
| 1381 return &entries_; | 1385 return &entries_; |
| 1382 } | 1386 } |
| 1383 | 1387 |
| 1384 | 1388 |
| 1385 void HeapSnapshot::Print(int max_depth) { | 1389 void HeapSnapshot::Print(int max_depth) { |
| (...skipping 1970 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3356 dominator != entry; | 3360 dominator != entry; |
| 3357 entry = dominator, dominator = entry->dominator()) { | 3361 entry = dominator, dominator = entry->dominator()) { |
| 3358 dominator->add_retained_size(entry_size); | 3362 dominator->add_retained_size(entry_size); |
| 3359 } | 3363 } |
| 3360 if (!ProgressReport()) return false; | 3364 if (!ProgressReport()) return false; |
| 3361 } | 3365 } |
| 3362 return true; | 3366 return true; |
| 3363 } | 3367 } |
| 3364 | 3368 |
| 3365 | 3369 |
| 3370 template<int bytes> struct MaxDecimalDigitsIn; | |
| 3371 template<> struct MaxDecimalDigitsIn<4> { | |
| 3372 static const int kSigned = 11; | |
| 3373 static const int kUnsigned = 10; | |
| 3374 }; | |
| 3375 template<> struct MaxDecimalDigitsIn<8> { | |
| 3376 static const int kSigned = 20; | |
| 3377 static const int kUnsigned = 20; | |
| 3378 }; | |
| 3379 | |
| 3380 | |
| 3366 class OutputStreamWriter { | 3381 class OutputStreamWriter { |
| 3367 public: | 3382 public: |
| 3368 explicit OutputStreamWriter(v8::OutputStream* stream) | 3383 explicit OutputStreamWriter(v8::OutputStream* stream) |
| 3369 : stream_(stream), | 3384 : stream_(stream), |
| 3370 chunk_size_(stream->GetChunkSize()), | 3385 chunk_size_(stream->GetChunkSize()), |
| 3371 chunk_(chunk_size_), | 3386 chunk_(chunk_size_), |
| 3372 chunk_pos_(0), | 3387 chunk_pos_(0), |
| 3373 aborted_(false) { | 3388 aborted_(false) { |
| 3374 ASSERT(chunk_size_ > 0); | 3389 ASSERT(chunk_size_ > 0); |
| 3375 } | 3390 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 3405 ASSERT(chunk_pos_ < chunk_size_); | 3420 ASSERT(chunk_pos_ < chunk_size_); |
| 3406 if (chunk_pos_ != 0) { | 3421 if (chunk_pos_ != 0) { |
| 3407 WriteChunk(); | 3422 WriteChunk(); |
| 3408 } | 3423 } |
| 3409 stream_->EndOfStream(); | 3424 stream_->EndOfStream(); |
| 3410 } | 3425 } |
| 3411 | 3426 |
| 3412 private: | 3427 private: |
| 3413 template<typename T> | 3428 template<typename T> |
| 3414 void AddNumberImpl(T n, const char* format) { | 3429 void AddNumberImpl(T n, const char* format) { |
| 3415 ScopedVector<char> buffer(32); | 3430 // Buffer for long long value plus trailing \0 |
| 3416 int result = OS::SNPrintF(buffer, format, n); | 3431 static const int kMaxNumberSize = |
| 3417 USE(result); | 3432 MaxDecimalDigitsIn<sizeof(long long)>::kUnsigned + 1; // NOLINT |
|
mnaganov (inactive)
2012/02/21 14:21:54
I will change "long long" to "T" (and update the c
| |
| 3418 ASSERT(result != -1); | 3433 if (chunk_size_ - chunk_pos_ >= kMaxNumberSize) { |
| 3419 AddString(buffer.start()); | 3434 int result = OS::SNPrintF( |
| 3435 chunk_.SubVector(chunk_pos_, chunk_size_), format, n); | |
| 3436 ASSERT(result != -1); | |
| 3437 chunk_pos_ += result; | |
| 3438 MaybeWriteChunk(); | |
| 3439 } else { | |
| 3440 EmbeddedVector<char, kMaxNumberSize> buffer; | |
| 3441 int result = OS::SNPrintF(buffer, format, n); | |
| 3442 USE(result); | |
| 3443 ASSERT(result != -1); | |
| 3444 AddString(buffer.start()); | |
| 3445 } | |
| 3420 } | 3446 } |
| 3421 void MaybeWriteChunk() { | 3447 void MaybeWriteChunk() { |
| 3422 ASSERT(chunk_pos_ <= chunk_size_); | 3448 ASSERT(chunk_pos_ <= chunk_size_); |
| 3423 if (chunk_pos_ == chunk_size_) { | 3449 if (chunk_pos_ == chunk_size_) { |
| 3424 WriteChunk(); | 3450 WriteChunk(); |
| 3425 chunk_pos_ = 0; | |
| 3426 } | 3451 } |
| 3427 } | 3452 } |
| 3428 void WriteChunk() { | 3453 void WriteChunk() { |
| 3429 if (aborted_) return; | 3454 if (aborted_) return; |
| 3430 if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) == | 3455 if (stream_->WriteAsciiChunk(chunk_.start(), chunk_pos_) == |
| 3431 v8::OutputStream::kAbort) aborted_ = true; | 3456 v8::OutputStream::kAbort) aborted_ = true; |
| 3457 chunk_pos_ = 0; | |
| 3432 } | 3458 } |
| 3433 | 3459 |
| 3434 v8::OutputStream* stream_; | 3460 v8::OutputStream* stream_; |
| 3435 int chunk_size_; | 3461 int chunk_size_; |
| 3436 ScopedVector<char> chunk_; | 3462 ScopedVector<char> chunk_; |
| 3437 int chunk_pos_; | 3463 int chunk_pos_; |
| 3438 bool aborted_; | 3464 bool aborted_; |
| 3439 }; | 3465 }; |
| 3440 | 3466 |
| 3467 | |
| 3441 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { | 3468 void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) { |
| 3442 ASSERT(writer_ == NULL); | 3469 ASSERT(writer_ == NULL); |
| 3443 writer_ = new OutputStreamWriter(stream); | 3470 writer_ = new OutputStreamWriter(stream); |
| 3444 | 3471 |
| 3445 HeapSnapshot* original_snapshot = NULL; | 3472 HeapSnapshot* original_snapshot = NULL; |
| 3446 if (snapshot_->raw_entries_size() >= | 3473 if (snapshot_->raw_entries_size() >= |
| 3447 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { | 3474 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { |
| 3448 // The snapshot is too big. Serialize a fake snapshot. | 3475 // The snapshot is too big. Serialize a fake snapshot. |
| 3449 original_snapshot = snapshot_; | 3476 original_snapshot = snapshot_; |
| 3450 snapshot_ = CreateFakeSnapshot(); | 3477 snapshot_ = CreateFakeSnapshot(); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3536 HashMap::Entry* cache_entry = strings_.Lookup( | 3563 HashMap::Entry* cache_entry = strings_.Lookup( |
| 3537 const_cast<char*>(s), ObjectHash(s), true); | 3564 const_cast<char*>(s), ObjectHash(s), true); |
| 3538 if (cache_entry->value == NULL) { | 3565 if (cache_entry->value == NULL) { |
| 3539 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); | 3566 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); |
| 3540 } | 3567 } |
| 3541 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); | 3568 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); |
| 3542 } | 3569 } |
| 3543 | 3570 |
| 3544 | 3571 |
| 3545 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { | 3572 void HeapSnapshotJSONSerializer::SerializeEdge(HeapGraphEdge* edge) { |
| 3546 writer_->AddCharacter(','); | 3573 // The buffer needs space for 3 ints, 3 commas and \0 |
| 3547 writer_->AddNumber(edge->type()); | 3574 static const int kBufferSize = |
| 3548 writer_->AddCharacter(','); | 3575 MaxDecimalDigitsIn<sizeof(int)>::kSigned * 3 + 3 + 1; // NOLINT |
| 3549 if (edge->type() == HeapGraphEdge::kElement | 3576 EmbeddedVector<char, kBufferSize> buffer; |
| 3577 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement | |
| 3550 || edge->type() == HeapGraphEdge::kHidden | 3578 || edge->type() == HeapGraphEdge::kHidden |
| 3551 || edge->type() == HeapGraphEdge::kWeak) { | 3579 || edge->type() == HeapGraphEdge::kWeak |
| 3552 writer_->AddNumber(edge->index()); | 3580 ? edge->index() : GetStringId(edge->name()); |
| 3553 } else { | 3581 int result = OS::SNPrintF(buffer, ",%d,%d,%d", |
| 3554 writer_->AddNumber(GetStringId(edge->name())); | 3582 edge->type(), edge_name_or_index, GetNodeId(edge->to())); |
| 3555 } | 3583 USE(result); |
| 3556 writer_->AddCharacter(','); | 3584 ASSERT(result != -1); |
| 3557 writer_->AddNumber(GetNodeId(edge->to())); | 3585 writer_->AddString(buffer.start()); |
| 3558 } | 3586 } |
| 3559 | 3587 |
| 3560 | 3588 |
| 3561 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 3589 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
| 3562 writer_->AddCharacter('\n'); | 3590 // The buffer needs space for 7 ints, 7 commas, \n and \0 |
| 3563 writer_->AddCharacter(','); | 3591 static const int kBufferSize = |
| 3564 writer_->AddNumber(entry->type()); | 3592 MaxDecimalDigitsIn<sizeof(int)>::kSigned * 7 + 7 + 1 + 1; // NOLINT |
| 3565 writer_->AddCharacter(','); | 3593 EmbeddedVector<char, kBufferSize> buffer; |
| 3566 writer_->AddNumber(GetStringId(entry->name())); | |
| 3567 writer_->AddCharacter(','); | |
| 3568 writer_->AddNumber(entry->id()); | |
| 3569 writer_->AddCharacter(','); | |
| 3570 writer_->AddNumber(entry->self_size()); | |
| 3571 writer_->AddCharacter(','); | |
| 3572 writer_->AddNumber(entry->RetainedSize(false)); | |
| 3573 writer_->AddCharacter(','); | |
| 3574 writer_->AddNumber(GetNodeId(entry->dominator())); | |
| 3575 Vector<HeapGraphEdge> children = entry->children(); | 3594 Vector<HeapGraphEdge> children = entry->children(); |
| 3576 writer_->AddCharacter(','); | 3595 int result = OS::SNPrintF(buffer, "\n,%d,%d,%d,%d,%d,%d,%d", |
| 3577 writer_->AddNumber(children.length()); | 3596 entry->type(), |
| 3597 GetStringId(entry->name()), | |
| 3598 entry->id(), | |
| 3599 entry->self_size(), | |
| 3600 entry->RetainedSize(false), | |
| 3601 GetNodeId(entry->dominator()), | |
| 3602 children.length()); | |
| 3603 USE(result); | |
| 3604 ASSERT(result != -1); | |
| 3605 writer_->AddString(buffer.start()); | |
| 3578 for (int i = 0; i < children.length(); ++i) { | 3606 for (int i = 0; i < children.length(); ++i) { |
| 3579 SerializeEdge(&children[i]); | 3607 SerializeEdge(&children[i]); |
| 3580 if (writer_->aborted()) return; | 3608 if (writer_->aborted()) return; |
| 3581 } | 3609 } |
| 3582 } | 3610 } |
| 3583 | 3611 |
| 3584 | 3612 |
| 3585 void HeapSnapshotJSONSerializer::SerializeNodes() { | 3613 void HeapSnapshotJSONSerializer::SerializeNodes() { |
| 3586 // The first (zero) item of nodes array is an object describing node | 3614 // The first (zero) item of nodes array is an object describing node |
| 3587 // serialization layout. We use a set of macros to improve | 3615 // serialization layout. We use a set of macros to improve |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3758 | 3786 |
| 3759 | 3787 |
| 3760 void HeapSnapshotJSONSerializer::SortHashMap( | 3788 void HeapSnapshotJSONSerializer::SortHashMap( |
| 3761 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 3789 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
| 3762 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 3790 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
| 3763 sorted_entries->Add(p); | 3791 sorted_entries->Add(p); |
| 3764 sorted_entries->Sort(SortUsingEntryValue); | 3792 sorted_entries->Sort(SortUsingEntryValue); |
| 3765 } | 3793 } |
| 3766 | 3794 |
| 3767 } } // namespace v8::internal | 3795 } } // namespace v8::internal |
| OLD | NEW |