OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 Loading... |
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" |
31 #include "string-stream.h" | 33 #include "string-stream.h" |
32 | 34 |
33 namespace v8 { | 35 namespace v8 { |
34 namespace internal { | 36 namespace internal { |
35 | 37 |
36 | 38 |
37 #ifdef ENABLE_LOGGING_AND_PROFILING | 39 #ifdef ENABLE_LOGGING_AND_PROFILING |
38 namespace { | 40 namespace { |
39 | 41 |
40 // Clusterizer is a set of helper functions for converting | 42 // Clusterizer is a set of helper functions for converting |
(...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 void ConstructorHeapProfile::CollectStats(HeapObject* obj) { | 322 void ConstructorHeapProfile::CollectStats(HeapObject* obj) { |
321 Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false); | 323 Clusterizer::InsertIntoTree(&js_objects_info_tree_, obj, false); |
322 } | 324 } |
323 | 325 |
324 | 326 |
325 void ConstructorHeapProfile::PrintStats() { | 327 void ConstructorHeapProfile::PrintStats() { |
326 js_objects_info_tree_.ForEach(this); | 328 js_objects_info_tree_.ForEach(this); |
327 } | 329 } |
328 | 330 |
329 | 331 |
| 332 static const char* GetConstructorName(const char* name) { |
| 333 return name[0] != '\0' ? name : "(anonymous)"; |
| 334 } |
| 335 |
| 336 |
330 void JSObjectsCluster::Print(StringStream* accumulator) const { | 337 void JSObjectsCluster::Print(StringStream* accumulator) const { |
331 ASSERT(!is_null()); | 338 ASSERT(!is_null()); |
332 if (constructor_ == FromSpecialCase(ROOTS)) { | 339 if (constructor_ == FromSpecialCase(ROOTS)) { |
333 accumulator->Add("(roots)"); | 340 accumulator->Add("(roots)"); |
334 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) { | 341 } else if (constructor_ == FromSpecialCase(GLOBAL_PROPERTY)) { |
335 accumulator->Add("(global property)"); | 342 accumulator->Add("(global property)"); |
336 } else if (constructor_ == FromSpecialCase(SELF)) { | 343 } else if (constructor_ == FromSpecialCase(SELF)) { |
337 accumulator->Add("(self)"); | 344 accumulator->Add("(self)"); |
338 } else { | 345 } else { |
339 SmartPointer<char> s_name( | 346 SmartPointer<char> s_name( |
340 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); | 347 constructor_->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); |
341 accumulator->Add("%s", (*s_name)[0] != '\0' ? *s_name : "(anonymous)"); | 348 accumulator->Add("%s", GetConstructorName(*s_name)); |
342 if (instance_ != NULL) { | 349 if (instance_ != NULL) { |
343 accumulator->Add(":%p", static_cast<void*>(instance_)); | 350 accumulator->Add(":%p", static_cast<void*>(instance_)); |
344 } | 351 } |
345 } | 352 } |
346 } | 353 } |
347 | 354 |
348 | 355 |
349 void JSObjectsCluster::DebugPrint(StringStream* accumulator) const { | 356 void JSObjectsCluster::DebugPrint(StringStream* accumulator) const { |
350 if (!is_null()) { | 357 if (!is_null()) { |
351 Print(accumulator); | 358 Print(accumulator); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 // HeapProfiler class implementation. | 574 // HeapProfiler class implementation. |
568 // | 575 // |
569 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { | 576 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { |
570 InstanceType type = obj->map()->instance_type(); | 577 InstanceType type = obj->map()->instance_type(); |
571 ASSERT(0 <= type && type <= LAST_TYPE); | 578 ASSERT(0 <= type && type <= LAST_TYPE); |
572 info[type].increment_number(1); | 579 info[type].increment_number(1); |
573 info[type].increment_bytes(obj->Size()); | 580 info[type].increment_bytes(obj->Size()); |
574 } | 581 } |
575 | 582 |
576 | 583 |
| 584 static void StackWeakReferenceCallback(Persistent<Value> object, |
| 585 void* trace) { |
| 586 DeleteArray(static_cast<Address*>(trace)); |
| 587 object.Dispose(); |
| 588 } |
| 589 |
| 590 |
| 591 static void PrintProducerStackTrace(Object* obj, void* trace) { |
| 592 if (!obj->IsJSObject()) return; |
| 593 String* constructor = JSObject::cast(obj)->constructor_name(); |
| 594 SmartPointer<char> s_name( |
| 595 constructor->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)); |
| 596 LOG(HeapSampleJSProducerEvent(GetConstructorName(*s_name), |
| 597 reinterpret_cast<Address*>(trace))); |
| 598 } |
| 599 |
| 600 |
577 void HeapProfiler::WriteSample() { | 601 void HeapProfiler::WriteSample() { |
578 LOG(HeapSampleBeginEvent("Heap", "allocated")); | 602 LOG(HeapSampleBeginEvent("Heap", "allocated")); |
579 LOG(HeapSampleStats( | 603 LOG(HeapSampleStats( |
580 "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects())); | 604 "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects())); |
581 | 605 |
582 HistogramInfo info[LAST_TYPE+1]; | 606 HistogramInfo info[LAST_TYPE+1]; |
583 #define DEF_TYPE_NAME(name) info[name].set_name(#name); | 607 #define DEF_TYPE_NAME(name) info[name].set_name(#name); |
584 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) | 608 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) |
585 #undef DEF_TYPE_NAME | 609 #undef DEF_TYPE_NAME |
586 | 610 |
(...skipping 22 matching lines...) Expand all Loading... |
609 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { | 633 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { |
610 if (info[i].bytes() > 0) { | 634 if (info[i].bytes() > 0) { |
611 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(), | 635 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(), |
612 info[i].bytes())); | 636 info[i].bytes())); |
613 } | 637 } |
614 } | 638 } |
615 | 639 |
616 js_cons_profile.PrintStats(); | 640 js_cons_profile.PrintStats(); |
617 js_retainer_profile.PrintStats(); | 641 js_retainer_profile.PrintStats(); |
618 | 642 |
| 643 GlobalHandles::IterateWeakRoots(PrintProducerStackTrace, |
| 644 StackWeakReferenceCallback); |
| 645 |
619 LOG(HeapSampleEndEvent("Heap", "allocated")); | 646 LOG(HeapSampleEndEvent("Heap", "allocated")); |
620 } | 647 } |
621 | 648 |
622 | 649 |
| 650 bool ProducerHeapProfile::can_log_ = false; |
| 651 |
| 652 void ProducerHeapProfile::Setup() { |
| 653 can_log_ = true; |
| 654 } |
| 655 |
| 656 void ProducerHeapProfile::RecordJSObjectAllocation(Object* obj) { |
| 657 if (!can_log_ || !FLAG_log_producers) return; |
| 658 int framesCount = 0; |
| 659 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) { |
| 660 ++framesCount; |
| 661 } |
| 662 if (framesCount == 0) return; |
| 663 ++framesCount; // Reserve place for the terminator item. |
| 664 Vector<Address> stack(NewArray<Address>(framesCount), framesCount); |
| 665 int i = 0; |
| 666 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) { |
| 667 stack[i++] = it.frame()->pc(); |
| 668 } |
| 669 stack[i] = NULL; |
| 670 Handle<Object> handle = GlobalHandles::Create(obj); |
| 671 GlobalHandles::MakeWeak(handle.location(), |
| 672 static_cast<void*>(stack.start()), |
| 673 StackWeakReferenceCallback); |
| 674 } |
| 675 |
| 676 |
623 #endif // ENABLE_LOGGING_AND_PROFILING | 677 #endif // ENABLE_LOGGING_AND_PROFILING |
624 | 678 |
625 | 679 |
626 } } // namespace v8::internal | 680 } } // namespace v8::internal |
OLD | NEW |