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

Side by Side Diff: src/heap-profiler.cc

Issue 7247018: Remove obsolete aggregating and non-working producers heap profilers. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 6 months 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 2009-2010 the V8 project authors. All rights reserved. 1 // Copyright 2009-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 10 matching lines...) Expand all
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8.h" 28 #include "v8.h"
29 29
30 #include "heap-profiler.h" 30 #include "heap-profiler.h"
31 #include "frames-inl.h"
32 #include "global-handles.h"
33 #include "profile-generator.h" 31 #include "profile-generator.h"
34 #include "string-stream.h"
35 32
36 namespace v8 { 33 namespace v8 {
37 namespace internal { 34 namespace internal {
38 35
39 36
40 #ifdef ENABLE_LOGGING_AND_PROFILING 37 #ifdef ENABLE_LOGGING_AND_PROFILING
41 namespace {
42
43 // Clusterizer is a set of helper functions for converting
44 // object references into clusters.
45 class Clusterizer : public AllStatic {
46 public:
47 static JSObjectsCluster Clusterize(HeapObject* obj) {
48 return Clusterize(obj, true);
49 }
50 static void InsertIntoTree(JSObjectsClusterTree* tree,
51 HeapObject* obj, bool fine_grain);
52 static void InsertReferenceIntoTree(JSObjectsClusterTree* tree,
53 const JSObjectsCluster& cluster) {
54 InsertIntoTree(tree, cluster, 0);
55 }
56
57 private:
58 static JSObjectsCluster Clusterize(HeapObject* obj, bool fine_grain);
59 static int CalculateNetworkSize(JSObject* obj);
60 static int GetObjectSize(HeapObject* obj) {
61 return obj->IsJSObject() ?
62 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size();
63 }
64 static void InsertIntoTree(JSObjectsClusterTree* tree,
65 const JSObjectsCluster& cluster, int size);
66 };
67
68
69 JSObjectsCluster Clusterizer::Clusterize(HeapObject* obj, bool fine_grain) {
70 if (obj->IsJSObject()) {
71 JSObject* js_obj = JSObject::cast(obj);
72 String* constructor = GetConstructorNameForHeapProfile(
73 JSObject::cast(js_obj));
74 // Differentiate Object and Array instances.
75 if (fine_grain && (constructor == HEAP->Object_symbol() ||
76 constructor == HEAP->Array_symbol())) {
77 return JSObjectsCluster(constructor, obj);
78 } else {
79 return JSObjectsCluster(constructor);
80 }
81 } else if (obj->IsString()) {
82 return JSObjectsCluster(HEAP->String_symbol());
83 } else if (obj->IsJSGlobalPropertyCell()) {
84 return JSObjectsCluster(JSObjectsCluster::GLOBAL_PROPERTY);
85 } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) {
86 return JSObjectsCluster(JSObjectsCluster::CODE);
87 }
88 return JSObjectsCluster();
89 }
90
91
92 void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
93 HeapObject* obj, bool fine_grain) {
94 JSObjectsCluster cluster = Clusterize(obj, fine_grain);
95 if (cluster.is_null()) return;
96 InsertIntoTree(tree, cluster, GetObjectSize(obj));
97 }
98
99
100 void Clusterizer::InsertIntoTree(JSObjectsClusterTree* tree,
101 const JSObjectsCluster& cluster, int size) {
102 JSObjectsClusterTree::Locator loc;
103 tree->Insert(cluster, &loc);
104 NumberAndSizeInfo number_and_size = loc.value();
105 number_and_size.increment_number(1);
106 number_and_size.increment_bytes(size);
107 loc.set_value(number_and_size);
108 }
109
110
111 int Clusterizer::CalculateNetworkSize(JSObject* obj) {
112 int size = obj->Size();
113 // If 'properties' and 'elements' are non-empty (thus, non-shared),
114 // take their size into account.
115 if (obj->properties() != HEAP->empty_fixed_array()) {
116 size += obj->properties()->Size();
117 }
118 if (obj->elements() != HEAP->empty_fixed_array()) {
119 size += obj->elements()->Size();
120 }
121 // For functions, also account non-empty context and literals sizes.
122 if (obj->IsJSFunction()) {
123 JSFunction* f = JSFunction::cast(obj);
124 if (f->unchecked_context()->IsContext()) {
125 size += f->context()->Size();
126 }
127 if (f->literals()->length() != 0) {
128 size += f->literals()->Size();
129 }
130 }
131 return size;
132 }
133
134
135 // A helper class for recording back references.
136 class ReferencesExtractor : public ObjectVisitor {
137 public:
138 ReferencesExtractor(const JSObjectsCluster& cluster,
139 RetainerHeapProfile* profile)
140 : cluster_(cluster),
141 profile_(profile),
142 inside_array_(false) {
143 }
144
145 void VisitPointer(Object** o) {
146 if ((*o)->IsFixedArray() && !inside_array_) {
147 // Traverse one level deep for data members that are fixed arrays.
148 // This covers the case of 'elements' and 'properties' of JSObject,
149 // and function contexts.
150 inside_array_ = true;
151 FixedArray::cast(*o)->Iterate(this);
152 inside_array_ = false;
153 } else if ((*o)->IsHeapObject()) {
154 profile_->StoreReference(cluster_, HeapObject::cast(*o));
155 }
156 }
157
158 void VisitPointers(Object** start, Object** end) {
159 for (Object** p = start; p < end; p++) VisitPointer(p);
160 }
161
162 private:
163 const JSObjectsCluster& cluster_;
164 RetainerHeapProfile* profile_;
165 bool inside_array_;
166 };
167
168
169 // A printer interface implementation for the Retainers profile.
170 class RetainersPrinter : public RetainerHeapProfile::Printer {
171 public:
172 void PrintRetainers(const JSObjectsCluster& cluster,
173 const StringStream& retainers) {
174 HeapStringAllocator allocator;
175 StringStream stream(&allocator);
176 cluster.Print(&stream);
177 LOG(ISOLATE,
178 HeapSampleJSRetainersEvent(
179 *(stream.ToCString()), *(retainers.ToCString())));
180 }
181 };
182
183
184 // Visitor for printing a cluster tree.
185 class ClusterTreePrinter BASE_EMBEDDED {
186 public:
187 explicit ClusterTreePrinter(StringStream* stream) : stream_(stream) {}
188 void Call(const JSObjectsCluster& cluster,
189 const NumberAndSizeInfo& number_and_size) {
190 Print(stream_, cluster, number_and_size);
191 }
192 static void Print(StringStream* stream,
193 const JSObjectsCluster& cluster,
194 const NumberAndSizeInfo& number_and_size);
195
196 private:
197 StringStream* stream_;
198 };
199
200
201 void ClusterTreePrinter::Print(StringStream* stream,
202 const JSObjectsCluster& cluster,
203 const NumberAndSizeInfo& number_and_size) {
204 stream->Put(',');
205 cluster.Print(stream);
206 stream->Add(";%d", number_and_size.number());
207 }
208
209
210 // Visitor for printing a retainer tree.
211 class SimpleRetainerTreePrinter BASE_EMBEDDED {
212 public:
213 explicit SimpleRetainerTreePrinter(RetainerHeapProfile::Printer* printer)
214 : printer_(printer) {}
215 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
216
217 private:
218 RetainerHeapProfile::Printer* printer_;
219 };
220
221
222 void SimpleRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
223 JSObjectsClusterTree* tree) {
224 HeapStringAllocator allocator;
225 StringStream stream(&allocator);
226 ClusterTreePrinter retainers_printer(&stream);
227 tree->ForEach(&retainers_printer);
228 printer_->PrintRetainers(cluster, stream);
229 }
230
231
232 // Visitor for aggregating references count of equivalent clusters.
233 class RetainersAggregator BASE_EMBEDDED {
234 public:
235 RetainersAggregator(ClustersCoarser* coarser, JSObjectsClusterTree* dest_tree)
236 : coarser_(coarser), dest_tree_(dest_tree) {}
237 void Call(const JSObjectsCluster& cluster,
238 const NumberAndSizeInfo& number_and_size);
239
240 private:
241 ClustersCoarser* coarser_;
242 JSObjectsClusterTree* dest_tree_;
243 };
244
245
246 void RetainersAggregator::Call(const JSObjectsCluster& cluster,
247 const NumberAndSizeInfo& number_and_size) {
248 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
249 if (eq.is_null()) eq = cluster;
250 JSObjectsClusterTree::Locator loc;
251 dest_tree_->Insert(eq, &loc);
252 NumberAndSizeInfo aggregated_number = loc.value();
253 aggregated_number.increment_number(number_and_size.number());
254 loc.set_value(aggregated_number);
255 }
256
257
258 // Visitor for printing retainers tree. Aggregates equivalent retainer clusters.
259 class AggregatingRetainerTreePrinter BASE_EMBEDDED {
260 public:
261 AggregatingRetainerTreePrinter(ClustersCoarser* coarser,
262 RetainerHeapProfile::Printer* printer)
263 : coarser_(coarser), printer_(printer) {}
264 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
265
266 private:
267 ClustersCoarser* coarser_;
268 RetainerHeapProfile::Printer* printer_;
269 };
270
271
272 void AggregatingRetainerTreePrinter::Call(const JSObjectsCluster& cluster,
273 JSObjectsClusterTree* tree) {
274 if (!coarser_->GetCoarseEquivalent(cluster).is_null()) return;
275 JSObjectsClusterTree dest_tree_;
276 RetainersAggregator retainers_aggregator(coarser_, &dest_tree_);
277 tree->ForEach(&retainers_aggregator);
278 HeapStringAllocator allocator;
279 StringStream stream(&allocator);
280 ClusterTreePrinter retainers_printer(&stream);
281 dest_tree_.ForEach(&retainers_printer);
282 printer_->PrintRetainers(cluster, stream);
283 }
284
285 } // namespace
286
287
288 // A helper class for building a retainers tree, that aggregates
289 // all equivalent clusters.
290 class RetainerTreeAggregator {
291 public:
292 explicit RetainerTreeAggregator(ClustersCoarser* coarser)
293 : coarser_(coarser) {}
294 void Process(JSObjectsRetainerTree* input_tree) {
295 input_tree->ForEach(this);
296 }
297 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree);
298 JSObjectsRetainerTree& output_tree() { return output_tree_; }
299
300 private:
301 ClustersCoarser* coarser_;
302 JSObjectsRetainerTree output_tree_;
303 };
304
305
306 void RetainerTreeAggregator::Call(const JSObjectsCluster& cluster,
307 JSObjectsClusterTree* tree) {
308 JSObjectsCluster eq = coarser_->GetCoarseEquivalent(cluster);
309 if (eq.is_null()) return;
310 JSObjectsRetainerTree::Locator loc;
311 if (output_tree_.Insert(eq, &loc)) {
312 loc.set_value(new JSObjectsClusterTree());
313 }
314 RetainersAggregator retainers_aggregator(coarser_, loc.value());
315 tree->ForEach(&retainers_aggregator);
316 }
317
318
319 HeapProfiler::HeapProfiler() 38 HeapProfiler::HeapProfiler()
320 : snapshots_(new HeapSnapshotsCollection()), 39 : snapshots_(new HeapSnapshotsCollection()),
321 next_snapshot_uid_(1) { 40 next_snapshot_uid_(1) {
322 } 41 }
323 42
324 43
325 HeapProfiler::~HeapProfiler() { 44 HeapProfiler::~HeapProfiler() {
326 delete snapshots_; 45 delete snapshots_;
327 } 46 }
328 47
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 HeapSnapshot* result = 121 HeapSnapshot* result =
403 snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++); 122 snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
404 bool generation_completed = true; 123 bool generation_completed = true;
405 switch (s_type) { 124 switch (s_type) {
406 case HeapSnapshot::kFull: { 125 case HeapSnapshot::kFull: {
407 HEAP->CollectAllGarbage(true); 126 HEAP->CollectAllGarbage(true);
408 HeapSnapshotGenerator generator(result, control); 127 HeapSnapshotGenerator generator(result, control);
409 generation_completed = generator.GenerateSnapshot(); 128 generation_completed = generator.GenerateSnapshot();
410 break; 129 break;
411 } 130 }
412 case HeapSnapshot::kAggregated: {
413 HEAP->CollectAllGarbage(true);
414 AggregatedHeapSnapshot agg_snapshot;
415 AggregatedHeapSnapshotGenerator generator(&agg_snapshot);
416 generator.GenerateSnapshot();
417 generator.FillHeapSnapshot(result);
418 break;
419 }
420 default: 131 default:
421 UNREACHABLE(); 132 UNREACHABLE();
422 } 133 }
423 if (!generation_completed) { 134 if (!generation_completed) {
424 delete result; 135 delete result;
425 result = NULL; 136 result = NULL;
426 } 137 }
427 snapshots_->SnapshotGenerationFinished(result); 138 snapshots_->SnapshotGenerationFinished(result);
428 return result; 139 return result;
429 } 140 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 HeapProfiler* profiler = Isolate::Current()->heap_profiler(); 172 HeapProfiler* profiler = Isolate::Current()->heap_profiler();
462 ASSERT(profiler != NULL); 173 ASSERT(profiler != NULL);
463 profiler->ResetSnapshots(); 174 profiler->ResetSnapshots();
464 } 175 }
465 176
466 177
467 void HeapProfiler::ObjectMoveEvent(Address from, Address to) { 178 void HeapProfiler::ObjectMoveEvent(Address from, Address to) {
468 snapshots_->ObjectMoveEvent(from, to); 179 snapshots_->ObjectMoveEvent(from, to);
469 } 180 }
470 181
471
472 const JSObjectsClusterTreeConfig::Key JSObjectsClusterTreeConfig::kNoKey;
473 const JSObjectsClusterTreeConfig::Value JSObjectsClusterTreeConfig::kNoValue;
474
475
476 ConstructorHeapProfile::ConstructorHeapProfile()
477 : zscope_(Isolate::Current(), DELETE_ON_EXIT) {
478 }
479
480
481 void ConstructorHeapProfile::Call(const JSObjectsCluster& cluster,
482 const NumberAndSizeInfo& number_and_size) {
483 HeapStringAllocator allocator;
484 StringStream stream(&allocator);
485 cluster.Print(&stream);
486 LOG(ISOLATE,
487 HeapSampleJSConstructorEvent(*(stream.ToCString()),
488 number_and_size.number(),
489 number_and_size.bytes()));
490 }
491
492
493 void ConstructorHeapProfile::CollectStats(HeapObject* obj) {
494 Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false);
495 }
496
497
498 void ConstructorHeapProfile::PrintStats() {
499 js_objects_info_tree_.ForEach(this);
500 }
501
502
503 static const char* GetConstructorName(const char* name) {
504 return name[0] != '\0' ? name : "(anonymous)";
505 }
506
507
508 const char* JSObjectsCluster::GetSpecialCaseName() const {
509 if (constructor_ == FromSpecialCase(ROOTS)) {
510 return "(roots)";
511 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) {
512 return "(global property)";
513 } else if (constructor_ == FromSpecialCase(CODE)) {
514 return "(code)";
515 } else if (constructor_ == FromSpecialCase(SELF)) {
516 return "(self)";
517 }
518 return NULL;
519 }
520
521
522 void JSObjectsCluster::Print(StringStream* accumulator) const {
523 ASSERT(!is_null());
524 const char* special_case_name = GetSpecialCaseName();
525 if (special_case_name != NULL) {
526 accumulator->Add(special_case_name);
527 } else {
528 SmartPointer<char> s_name(
529 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
530 accumulator->Add("%s", GetConstructorName(*s_name));
531 if (instance_ != NULL) {
532 accumulator->Add(":%p", static_cast<void*>(instance_));
533 }
534 }
535 }
536
537
538 void JSObjectsCluster::DebugPrint(StringStream* accumulator) const {
539 if (!is_null()) {
540 Print(accumulator);
541 } else {
542 accumulator->Add("(null cluster)");
543 }
544 }
545
546
547 inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
548 const JSObjectsCluster& cluster_)
549 : cluster(cluster_), refs(kInitialBackrefsListCapacity) {
550 }
551
552
553 inline ClustersCoarser::ClusterBackRefs::ClusterBackRefs(
554 const ClustersCoarser::ClusterBackRefs& src)
555 : cluster(src.cluster), refs(src.refs.capacity()) {
556 refs.AddAll(src.refs);
557 }
558
559
560 inline ClustersCoarser::ClusterBackRefs&
561 ClustersCoarser::ClusterBackRefs::operator=(
562 const ClustersCoarser::ClusterBackRefs& src) {
563 if (this == &src) return *this;
564 cluster = src.cluster;
565 refs.Clear();
566 refs.AddAll(src.refs);
567 return *this;
568 }
569
570
571 inline int ClustersCoarser::ClusterBackRefs::Compare(
572 const ClustersCoarser::ClusterBackRefs& a,
573 const ClustersCoarser::ClusterBackRefs& b) {
574 int cmp = JSObjectsCluster::CompareConstructors(a.cluster, b.cluster);
575 if (cmp != 0) return cmp;
576 if (a.refs.length() < b.refs.length()) return -1;
577 if (a.refs.length() > b.refs.length()) return 1;
578 for (int i = 0; i < a.refs.length(); ++i) {
579 int cmp = JSObjectsCluster::Compare(a.refs[i], b.refs[i]);
580 if (cmp != 0) return cmp;
581 }
582 return 0;
583 }
584
585
586 ClustersCoarser::ClustersCoarser()
587 : zscope_(Isolate::Current(), DELETE_ON_EXIT),
588 sim_list_(ClustersCoarser::kInitialSimilarityListCapacity),
589 current_pair_(NULL),
590 current_set_(NULL),
591 self_(NULL) {
592 }
593
594
595 void ClustersCoarser::Call(const JSObjectsCluster& cluster,
596 JSObjectsClusterTree* tree) {
597 if (!cluster.can_be_coarsed()) return;
598 ClusterBackRefs pair(cluster);
599 ASSERT(current_pair_ == NULL);
600 current_pair_ = &pair;
601 current_set_ = new JSObjectsRetainerTree();
602 self_ = &cluster;
603 tree->ForEach(this);
604 sim_list_.Add(pair);
605 current_pair_ = NULL;
606 current_set_ = NULL;
607 self_ = NULL;
608 }
609
610
611 void ClustersCoarser::Call(const JSObjectsCluster& cluster,
612 const NumberAndSizeInfo& number_and_size) {
613 ASSERT(current_pair_ != NULL);
614 ASSERT(current_set_ != NULL);
615 ASSERT(self_ != NULL);
616 JSObjectsRetainerTree::Locator loc;
617 if (JSObjectsCluster::Compare(*self_, cluster) == 0) {
618 current_pair_->refs.Add(JSObjectsCluster(JSObjectsCluster::SELF));
619 return;
620 }
621 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
622 if (!eq.is_null()) {
623 if (current_set_->Find(eq, &loc)) return;
624 current_pair_->refs.Add(eq);
625 current_set_->Insert(eq, &loc);
626 } else {
627 current_pair_->refs.Add(cluster);
628 }
629 }
630
631
632 void ClustersCoarser::Process(JSObjectsRetainerTree* tree) {
633 int last_eq_clusters = -1;
634 for (int i = 0; i < kMaxPassesCount; ++i) {
635 sim_list_.Clear();
636 const int curr_eq_clusters = DoProcess(tree);
637 // If no new cluster equivalents discovered, abort processing.
638 if (last_eq_clusters == curr_eq_clusters) break;
639 last_eq_clusters = curr_eq_clusters;
640 }
641 }
642
643
644 int ClustersCoarser::DoProcess(JSObjectsRetainerTree* tree) {
645 tree->ForEach(this);
646 sim_list_.Iterate(ClusterBackRefs::SortRefsIterator);
647 sim_list_.Sort(ClusterBackRefsCmp);
648 return FillEqualityTree();
649 }
650
651
652 JSObjectsCluster ClustersCoarser::GetCoarseEquivalent(
653 const JSObjectsCluster& cluster) {
654 if (!cluster.can_be_coarsed()) return JSObjectsCluster();
655 EqualityTree::Locator loc;
656 return eq_tree_.Find(cluster, &loc) ? loc.value() : JSObjectsCluster();
657 }
658
659
660 bool ClustersCoarser::HasAnEquivalent(const JSObjectsCluster& cluster) {
661 // Return true for coarsible clusters that have a non-identical equivalent.
662 if (!cluster.can_be_coarsed()) return false;
663 JSObjectsCluster eq = GetCoarseEquivalent(cluster);
664 return !eq.is_null() && JSObjectsCluster::Compare(cluster, eq) != 0;
665 }
666
667
668 int ClustersCoarser::FillEqualityTree() {
669 int eq_clusters_count = 0;
670 int eq_to = 0;
671 bool first_added = false;
672 for (int i = 1; i < sim_list_.length(); ++i) {
673 if (ClusterBackRefs::Compare(sim_list_[i], sim_list_[eq_to]) == 0) {
674 EqualityTree::Locator loc;
675 if (!first_added) {
676 // Add self-equivalence, if we have more than one item in this
677 // equivalence class.
678 eq_tree_.Insert(sim_list_[eq_to].cluster, &loc);
679 loc.set_value(sim_list_[eq_to].cluster);
680 first_added = true;
681 }
682 eq_tree_.Insert(sim_list_[i].cluster, &loc);
683 loc.set_value(sim_list_[eq_to].cluster);
684 ++eq_clusters_count;
685 } else {
686 eq_to = i;
687 first_added = false;
688 }
689 }
690 return eq_clusters_count;
691 }
692
693
694 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoKey;
695 const JSObjectsCluster ClustersCoarser::ClusterEqualityConfig::kNoValue;
696 const JSObjectsRetainerTreeConfig::Key JSObjectsRetainerTreeConfig::kNoKey;
697 const JSObjectsRetainerTreeConfig::Value JSObjectsRetainerTreeConfig::kNoValue =
698 NULL;
699
700
701 RetainerHeapProfile::RetainerHeapProfile()
702 : zscope_(Isolate::Current(), DELETE_ON_EXIT),
703 aggregator_(NULL) {
704 JSObjectsCluster roots(JSObjectsCluster::ROOTS);
705 ReferencesExtractor extractor(roots, this);
706 HEAP->IterateRoots(&extractor, VISIT_ONLY_STRONG);
707 }
708
709
710 RetainerHeapProfile::~RetainerHeapProfile() {
711 delete aggregator_;
712 }
713
714
715 void RetainerHeapProfile::StoreReference(const JSObjectsCluster& cluster,
716 HeapObject* ref) {
717 JSObjectsCluster ref_cluster = Clusterizer::Clusterize(ref);
718 if (ref_cluster.is_null()) return;
719 JSObjectsRetainerTree::Locator ref_loc;
720 if (retainers_tree_.Insert(ref_cluster, &ref_loc)) {
721 ref_loc.set_value(new JSObjectsClusterTree());
722 }
723 JSObjectsClusterTree* referenced_by = ref_loc.value();
724 Clusterizer::InsertReferenceIntoTree(referenced_by, cluster);
725 }
726
727
728 void RetainerHeapProfile::CollectStats(HeapObject* obj) {
729 const JSObjectsCluster cluster = Clusterizer::Clusterize(obj);
730 if (cluster.is_null()) return;
731 ReferencesExtractor extractor(cluster, this);
732 obj->Iterate(&extractor);
733 }
734
735
736 void RetainerHeapProfile::CoarseAndAggregate() {
737 coarser_.Process(&retainers_tree_);
738 ASSERT(aggregator_ == NULL);
739 aggregator_ = new RetainerTreeAggregator(&coarser_);
740 aggregator_->Process(&retainers_tree_);
741 }
742
743
744 void RetainerHeapProfile::DebugPrintStats(
745 RetainerHeapProfile::Printer* printer) {
746 // Print clusters that have no equivalents, aggregating their retainers.
747 AggregatingRetainerTreePrinter agg_printer(&coarser_, printer);
748 retainers_tree_.ForEach(&agg_printer);
749 // Print clusters that have equivalents.
750 SimpleRetainerTreePrinter s_printer(printer);
751 aggregator_->output_tree().ForEach(&s_printer);
752 }
753
754
755 void RetainerHeapProfile::PrintStats() {
756 RetainersPrinter printer;
757 DebugPrintStats(&printer);
758 }
759
760
761 //
762 // HeapProfiler class implementation.
763 //
764 static void StackWeakReferenceCallback(Persistent<Value> object,
765 void* trace) {
766 DeleteArray(static_cast<Address*>(trace));
767 object.Dispose();
768 }
769
770
771 static void PrintProducerStackTrace(Object* obj, void* trace) {
772 if (!obj->IsJSObject()) return;
773 String* constructor = GetConstructorNameForHeapProfile(JSObject::cast(obj));
774 SmartPointer<char> s_name(
775 constructor->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL));
776 LOG(ISOLATE,
777 HeapSampleJSProducerEvent(GetConstructorName(*s_name),
778 reinterpret_cast<Address*>(trace)));
779 }
780
781
782 void HeapProfiler::WriteSample() {
783 Isolate* isolate = Isolate::Current();
784 LOG(isolate, HeapSampleBeginEvent("Heap", "allocated"));
785 LOG(isolate,
786 HeapSampleStats(
787 "Heap", "allocated", HEAP->CommittedMemory(), HEAP->SizeOfObjects()));
788
789 AggregatedHeapSnapshot snapshot;
790 AggregatedHeapSnapshotGenerator generator(&snapshot);
791 generator.GenerateSnapshot();
792
793 HistogramInfo* info = snapshot.info();
794 for (int i = FIRST_NONSTRING_TYPE;
795 i <= AggregatedHeapSnapshotGenerator::kAllStringsType;
796 ++i) {
797 if (info[i].bytes() > 0) {
798 LOG(isolate,
799 HeapSampleItemEvent(info[i].name(), info[i].number(),
800 info[i].bytes()));
801 }
802 }
803
804 snapshot.js_cons_profile()->PrintStats();
805 snapshot.js_retainer_profile()->PrintStats();
806
807 isolate->global_handles()->IterateWeakRoots(PrintProducerStackTrace,
808 StackWeakReferenceCallback);
809
810 LOG(isolate, HeapSampleEndEvent("Heap", "allocated"));
811 }
812
813
814 AggregatedHeapSnapshot::AggregatedHeapSnapshot()
815 : info_(NewArray<HistogramInfo>(
816 AggregatedHeapSnapshotGenerator::kAllStringsType + 1)) {
817 #define DEF_TYPE_NAME(name) info_[name].set_name(#name);
818 INSTANCE_TYPE_LIST(DEF_TYPE_NAME);
819 #undef DEF_TYPE_NAME
820 info_[AggregatedHeapSnapshotGenerator::kAllStringsType].set_name(
821 "STRING_TYPE");
822 }
823
824
825 AggregatedHeapSnapshot::~AggregatedHeapSnapshot() {
826 DeleteArray(info_);
827 }
828
829
830 AggregatedHeapSnapshotGenerator::AggregatedHeapSnapshotGenerator(
831 AggregatedHeapSnapshot* agg_snapshot)
832 : agg_snapshot_(agg_snapshot) {
833 }
834
835
836 void AggregatedHeapSnapshotGenerator::CalculateStringsStats() {
837 HistogramInfo* info = agg_snapshot_->info();
838 HistogramInfo& strings = info[kAllStringsType];
839 // Lump all the string types together.
840 #define INCREMENT_SIZE(type, size, name, camel_name) \
841 strings.increment_number(info[type].number()); \
842 strings.increment_bytes(info[type].bytes());
843 STRING_TYPE_LIST(INCREMENT_SIZE);
844 #undef INCREMENT_SIZE
845 }
846
847
848 void AggregatedHeapSnapshotGenerator::CollectStats(HeapObject* obj) {
849 InstanceType type = obj->map()->instance_type();
850 ASSERT(0 <= type && type <= LAST_TYPE);
851 agg_snapshot_->info()[type].increment_number(1);
852 agg_snapshot_->info()[type].increment_bytes(obj->Size());
853 }
854
855
856 void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
857 HeapIterator iterator(HeapIterator::kFilterUnreachable);
858 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
859 CollectStats(obj);
860 agg_snapshot_->js_cons_profile()->CollectStats(obj);
861 agg_snapshot_->js_retainer_profile()->CollectStats(obj);
862 }
863 CalculateStringsStats();
864 agg_snapshot_->js_retainer_profile()->CoarseAndAggregate();
865 }
866
867
868 class CountingConstructorHeapProfileIterator {
869 public:
870 CountingConstructorHeapProfileIterator()
871 : entities_count_(0), children_count_(0) {
872 }
873
874 void Call(const JSObjectsCluster& cluster,
875 const NumberAndSizeInfo& number_and_size) {
876 ++entities_count_;
877 children_count_ += number_and_size.number();
878 }
879
880 int entities_count() { return entities_count_; }
881 int children_count() { return children_count_; }
882
883 private:
884 int entities_count_;
885 int children_count_;
886 };
887
888
889 static HeapEntry* AddEntryFromAggregatedSnapshot(HeapSnapshot* snapshot,
890 int* root_child_index,
891 HeapEntry::Type type,
892 const char* name,
893 int count,
894 int size,
895 int children_count,
896 int retainers_count) {
897 HeapEntry* entry = snapshot->AddEntry(
898 type, name, count, size, children_count, retainers_count);
899 ASSERT(entry != NULL);
900 snapshot->root()->SetUnidirElementReference(*root_child_index,
901 *root_child_index + 1,
902 entry);
903 *root_child_index = *root_child_index + 1;
904 return entry;
905 }
906
907
908 class AllocatingConstructorHeapProfileIterator {
909 public:
910 AllocatingConstructorHeapProfileIterator(HeapSnapshot* snapshot,
911 int* root_child_index)
912 : snapshot_(snapshot),
913 root_child_index_(root_child_index) {
914 }
915
916 void Call(const JSObjectsCluster& cluster,
917 const NumberAndSizeInfo& number_and_size) {
918 const char* name = cluster.GetSpecialCaseName();
919 if (name == NULL) {
920 name = snapshot_->collection()->names()->GetFunctionName(
921 cluster.constructor());
922 }
923 AddEntryFromAggregatedSnapshot(snapshot_,
924 root_child_index_,
925 HeapEntry::kObject,
926 name,
927 number_and_size.number(),
928 number_and_size.bytes(),
929 0,
930 0);
931 }
932
933 private:
934 HeapSnapshot* snapshot_;
935 int* root_child_index_;
936 };
937
938
939 static HeapObject* ClusterAsHeapObject(const JSObjectsCluster& cluster) {
940 return cluster.can_be_coarsed() ?
941 reinterpret_cast<HeapObject*>(cluster.instance()) : cluster.constructor();
942 }
943
944
945 static JSObjectsCluster HeapObjectAsCluster(HeapObject* object) {
946 if (object->IsString()) {
947 return JSObjectsCluster(String::cast(object));
948 } else {
949 JSObject* js_obj = JSObject::cast(object);
950 String* constructor = GetConstructorNameForHeapProfile(
951 JSObject::cast(js_obj));
952 return JSObjectsCluster(constructor, object);
953 }
954 }
955
956
957 class CountingRetainersIterator {
958 public:
959 CountingRetainersIterator(const JSObjectsCluster& child_cluster,
960 HeapEntriesAllocator* allocator,
961 HeapEntriesMap* map)
962 : child_(ClusterAsHeapObject(child_cluster)),
963 allocator_(allocator),
964 map_(map) {
965 if (map_->Map(child_) == NULL)
966 map_->Pair(child_, allocator_, HeapEntriesMap::kHeapEntryPlaceholder);
967 }
968
969 void Call(const JSObjectsCluster& cluster,
970 const NumberAndSizeInfo& number_and_size) {
971 if (map_->Map(ClusterAsHeapObject(cluster)) == NULL)
972 map_->Pair(ClusterAsHeapObject(cluster),
973 allocator_,
974 HeapEntriesMap::kHeapEntryPlaceholder);
975 map_->CountReference(ClusterAsHeapObject(cluster), child_);
976 }
977
978 private:
979 HeapObject* child_;
980 HeapEntriesAllocator* allocator_;
981 HeapEntriesMap* map_;
982 };
983
984
985 class AllocatingRetainersIterator {
986 public:
987 AllocatingRetainersIterator(const JSObjectsCluster& child_cluster,
988 HeapEntriesAllocator*,
989 HeapEntriesMap* map)
990 : child_(ClusterAsHeapObject(child_cluster)), map_(map) {
991 child_entry_ = map_->Map(child_);
992 ASSERT(child_entry_ != NULL);
993 }
994
995 void Call(const JSObjectsCluster& cluster,
996 const NumberAndSizeInfo& number_and_size) {
997 int child_index, retainer_index;
998 map_->CountReference(ClusterAsHeapObject(cluster),
999 child_,
1000 &child_index,
1001 &retainer_index);
1002 map_->Map(ClusterAsHeapObject(cluster))->SetIndexedReference(
1003 HeapGraphEdge::kElement,
1004 child_index,
1005 number_and_size.number(),
1006 child_entry_,
1007 retainer_index);
1008 }
1009
1010 private:
1011 HeapObject* child_;
1012 HeapEntriesMap* map_;
1013 HeapEntry* child_entry_;
1014 };
1015
1016
1017 template<class RetainersIterator>
1018 class AggregatingRetainerTreeIterator {
1019 public:
1020 explicit AggregatingRetainerTreeIterator(ClustersCoarser* coarser,
1021 HeapEntriesAllocator* allocator,
1022 HeapEntriesMap* map)
1023 : coarser_(coarser), allocator_(allocator), map_(map) {
1024 }
1025
1026 void Call(const JSObjectsCluster& cluster, JSObjectsClusterTree* tree) {
1027 if (coarser_ != NULL &&
1028 !coarser_->GetCoarseEquivalent(cluster).is_null()) return;
1029 JSObjectsClusterTree* tree_to_iterate = tree;
1030 ZoneScope zs(Isolate::Current(), DELETE_ON_EXIT);
1031 JSObjectsClusterTree dest_tree_;
1032 if (coarser_ != NULL) {
1033 RetainersAggregator retainers_aggregator(coarser_, &dest_tree_);
1034 tree->ForEach(&retainers_aggregator);
1035 tree_to_iterate = &dest_tree_;
1036 }
1037 RetainersIterator iterator(cluster, allocator_, map_);
1038 tree_to_iterate->ForEach(&iterator);
1039 }
1040
1041 private:
1042 ClustersCoarser* coarser_;
1043 HeapEntriesAllocator* allocator_;
1044 HeapEntriesMap* map_;
1045 };
1046
1047
1048 class AggregatedRetainerTreeAllocator : public HeapEntriesAllocator {
1049 public:
1050 AggregatedRetainerTreeAllocator(HeapSnapshot* snapshot,
1051 int* root_child_index)
1052 : snapshot_(snapshot), root_child_index_(root_child_index) {
1053 }
1054 ~AggregatedRetainerTreeAllocator() { }
1055
1056 HeapEntry* AllocateEntry(
1057 HeapThing ptr, int children_count, int retainers_count) {
1058 HeapObject* obj = reinterpret_cast<HeapObject*>(ptr);
1059 JSObjectsCluster cluster = HeapObjectAsCluster(obj);
1060 const char* name = cluster.GetSpecialCaseName();
1061 if (name == NULL) {
1062 name = snapshot_->collection()->names()->GetFunctionName(
1063 cluster.constructor());
1064 }
1065 return AddEntryFromAggregatedSnapshot(
1066 snapshot_, root_child_index_, HeapEntry::kObject, name,
1067 0, 0, children_count, retainers_count);
1068 }
1069
1070 private:
1071 HeapSnapshot* snapshot_;
1072 int* root_child_index_;
1073 };
1074
1075
1076 template<class Iterator>
1077 void AggregatedHeapSnapshotGenerator::IterateRetainers(
1078 HeapEntriesAllocator* allocator, HeapEntriesMap* entries_map) {
1079 RetainerHeapProfile* p = agg_snapshot_->js_retainer_profile();
1080 AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_1(
1081 p->coarser(), allocator, entries_map);
1082 p->retainers_tree()->ForEach(&agg_ret_iter_1);
1083 AggregatingRetainerTreeIterator<Iterator> agg_ret_iter_2(
1084 NULL, allocator, entries_map);
1085 p->aggregator()->output_tree().ForEach(&agg_ret_iter_2);
1086 }
1087
1088
1089 void AggregatedHeapSnapshotGenerator::FillHeapSnapshot(HeapSnapshot* snapshot) {
1090 // Count the number of entities.
1091 int histogram_entities_count = 0;
1092 int histogram_children_count = 0;
1093 int histogram_retainers_count = 0;
1094 for (int i = FIRST_NONSTRING_TYPE; i <= kAllStringsType; ++i) {
1095 if (agg_snapshot_->info()[i].bytes() > 0) {
1096 ++histogram_entities_count;
1097 }
1098 }
1099 CountingConstructorHeapProfileIterator counting_cons_iter;
1100 agg_snapshot_->js_cons_profile()->ForEach(&counting_cons_iter);
1101 histogram_entities_count += counting_cons_iter.entities_count();
1102 HeapEntriesMap entries_map;
1103 int root_child_index = 0;
1104 AggregatedRetainerTreeAllocator allocator(snapshot, &root_child_index);
1105 IterateRetainers<CountingRetainersIterator>(&allocator, &entries_map);
1106 histogram_entities_count += entries_map.entries_count();
1107 histogram_children_count += entries_map.total_children_count();
1108 histogram_retainers_count += entries_map.total_retainers_count();
1109
1110 // Root entry references all other entries.
1111 histogram_children_count += histogram_entities_count;
1112 int root_children_count = histogram_entities_count;
1113 ++histogram_entities_count;
1114
1115 // Allocate and fill entries in the snapshot, allocate references.
1116 snapshot->AllocateEntries(histogram_entities_count,
1117 histogram_children_count,
1118 histogram_retainers_count);
1119 snapshot->AddRootEntry(root_children_count);
1120 for (int i = FIRST_NONSTRING_TYPE; i <= kAllStringsType; ++i) {
1121 if (agg_snapshot_->info()[i].bytes() > 0) {
1122 AddEntryFromAggregatedSnapshot(snapshot,
1123 &root_child_index,
1124 HeapEntry::kHidden,
1125 agg_snapshot_->info()[i].name(),
1126 agg_snapshot_->info()[i].number(),
1127 agg_snapshot_->info()[i].bytes(),
1128 0,
1129 0);
1130 }
1131 }
1132 AllocatingConstructorHeapProfileIterator alloc_cons_iter(
1133 snapshot, &root_child_index);
1134 agg_snapshot_->js_cons_profile()->ForEach(&alloc_cons_iter);
1135 entries_map.AllocateEntries();
1136
1137 // Fill up references.
1138 IterateRetainers<AllocatingRetainersIterator>(&allocator, &entries_map);
1139
1140 snapshot->SetDominatorsToSelf();
1141 }
1142
1143
1144 void ProducerHeapProfile::Setup() {
1145 can_log_ = true;
1146 }
1147
1148 void ProducerHeapProfile::DoRecordJSObjectAllocation(Object* obj) {
1149 ASSERT(FLAG_log_producers);
1150 if (!can_log_) return;
1151 int framesCount = 0;
1152 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
1153 ++framesCount;
1154 }
1155 if (framesCount == 0) return;
1156 ++framesCount; // Reserve place for the terminator item.
1157 Vector<Address> stack(NewArray<Address>(framesCount), framesCount);
1158 int i = 0;
1159 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) {
1160 stack[i++] = it.frame()->pc();
1161 }
1162 stack[i] = NULL;
1163 Handle<Object> handle = isolate_->global_handles()->Create(obj);
1164 isolate_->global_handles()->MakeWeak(handle.location(),
1165 static_cast<void*>(stack.start()),
1166 StackWeakReferenceCallback);
1167 }
1168
1169
1170 #endif // ENABLE_LOGGING_AND_PROFILING 182 #endif // ENABLE_LOGGING_AND_PROFILING
1171 183
1172 184
1173 } } // namespace v8::internal 185 } } // namespace v8::internal
OLDNEW
« src/api.cc ('K') | « src/heap-profiler.h ('k') | src/isolate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698