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 |