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 3393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3404 } | 3404 } |
3405 | 3405 |
3406 | 3406 |
3407 void HeapIterator::reset() { | 3407 void HeapIterator::reset() { |
3408 // Restart the iterator. | 3408 // Restart the iterator. |
3409 Shutdown(); | 3409 Shutdown(); |
3410 Init(); | 3410 Init(); |
3411 } | 3411 } |
3412 | 3412 |
3413 | 3413 |
| 3414 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 3415 namespace { |
| 3416 |
| 3417 // JSConstructorProfile is responsible for gathering and logging |
| 3418 // "constructor profile" of JS object allocated on heap. |
| 3419 // It is run during garbage collection cycle, thus it doesn't need |
| 3420 // to use handles. |
| 3421 class JSConstructorProfile BASE_EMBEDDED { |
| 3422 public: |
| 3423 JSConstructorProfile() : zscope_(DELETE_ON_EXIT) {} |
| 3424 void CollectStats(JSObject* obj); |
| 3425 void PrintStats(); |
| 3426 // Used by ZoneSplayTree::ForEach. |
| 3427 void Call(String* name, const NumberAndSizeInfo& number_and_size); |
| 3428 private: |
| 3429 struct TreeConfig { |
| 3430 typedef String* Key; |
| 3431 typedef NumberAndSizeInfo Value; |
| 3432 static const Key kNoKey; |
| 3433 static const Value kNoValue; |
| 3434 // Strings are unique, so it is sufficient to compare their pointers. |
| 3435 static int Compare(const Key& a, const Key& b) { |
| 3436 return a == b ? 0 : (a < b ? -1 : 1); |
| 3437 } |
| 3438 }; |
| 3439 |
| 3440 typedef ZoneSplayTree<TreeConfig> JSObjectsInfoTree; |
| 3441 static int CalculateJSObjectNetworkSize(JSObject* obj); |
| 3442 |
| 3443 ZoneScope zscope_; |
| 3444 JSObjectsInfoTree js_objects_info_tree_; |
| 3445 }; |
| 3446 |
| 3447 const JSConstructorProfile::TreeConfig::Key |
| 3448 JSConstructorProfile::TreeConfig::kNoKey = NULL; |
| 3449 const JSConstructorProfile::TreeConfig::Value |
| 3450 JSConstructorProfile::TreeConfig::kNoValue; |
| 3451 |
| 3452 |
| 3453 int JSConstructorProfile::CalculateJSObjectNetworkSize(JSObject* obj) { |
| 3454 int size = obj->Size(); |
| 3455 // If 'properties' and 'elements' are non-empty (thus, non-shared), |
| 3456 // take their size into account. |
| 3457 if (FixedArray::cast(obj->properties())->length() != 0) { |
| 3458 size += obj->properties()->Size(); |
| 3459 } |
| 3460 if (FixedArray::cast(obj->elements())->length() != 0) { |
| 3461 size += obj->elements()->Size(); |
| 3462 } |
| 3463 return size; |
| 3464 } |
| 3465 |
| 3466 |
| 3467 void JSConstructorProfile::Call(String* name, |
| 3468 const NumberAndSizeInfo& number_and_size) { |
| 3469 SmartPointer<char> s_name; |
| 3470 if (name != NULL) { |
| 3471 s_name = name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL); |
| 3472 } |
| 3473 LOG(HeapSampleJSConstructorEvent(*s_name, |
| 3474 number_and_size.number(), |
| 3475 number_and_size.bytes())); |
| 3476 } |
| 3477 |
| 3478 |
| 3479 void JSConstructorProfile::CollectStats(JSObject* obj) { |
| 3480 String* constructor_func = NULL; |
| 3481 if (obj->map()->constructor()->IsJSFunction()) { |
| 3482 JSFunction* constructor = JSFunction::cast(obj->map()->constructor()); |
| 3483 SharedFunctionInfo* sfi = constructor->shared(); |
| 3484 String* name = String::cast(sfi->name()); |
| 3485 constructor_func = name->length() > 0 ? name : sfi->inferred_name(); |
| 3486 } else if (obj->IsJSFunction()) { |
| 3487 constructor_func = Heap::function_class_symbol(); |
| 3488 } |
| 3489 JSObjectsInfoTree::Locator loc; |
| 3490 if (!js_objects_info_tree_.Find(constructor_func, &loc)) { |
| 3491 js_objects_info_tree_.Insert(constructor_func, &loc); |
| 3492 } |
| 3493 NumberAndSizeInfo number_and_size = loc.value(); |
| 3494 number_and_size.increment_number(1); |
| 3495 number_and_size.increment_bytes(CalculateJSObjectNetworkSize(obj)); |
| 3496 loc.set_value(number_and_size); |
| 3497 } |
| 3498 |
| 3499 |
| 3500 void JSConstructorProfile::PrintStats() { |
| 3501 js_objects_info_tree_.ForEach(this); |
| 3502 } |
| 3503 |
| 3504 } // namespace |
| 3505 #endif |
| 3506 |
| 3507 |
3414 // | 3508 // |
3415 // HeapProfiler class implementation. | 3509 // HeapProfiler class implementation. |
3416 // | 3510 // |
3417 #ifdef ENABLE_LOGGING_AND_PROFILING | 3511 #ifdef ENABLE_LOGGING_AND_PROFILING |
3418 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { | 3512 void HeapProfiler::CollectStats(HeapObject* obj, HistogramInfo* info) { |
3419 InstanceType type = obj->map()->instance_type(); | 3513 InstanceType type = obj->map()->instance_type(); |
3420 ASSERT(0 <= type && type <= LAST_TYPE); | 3514 ASSERT(0 <= type && type <= LAST_TYPE); |
3421 info[type].increment_number(1); | 3515 info[type].increment_number(1); |
3422 info[type].increment_bytes(obj->Size()); | 3516 info[type].increment_bytes(obj->Size()); |
3423 } | 3517 } |
3424 #endif | 3518 #endif |
3425 | 3519 |
3426 | 3520 |
3427 #ifdef ENABLE_LOGGING_AND_PROFILING | 3521 #ifdef ENABLE_LOGGING_AND_PROFILING |
3428 void HeapProfiler::WriteSample() { | 3522 void HeapProfiler::WriteSample() { |
3429 LOG(HeapSampleBeginEvent("Heap", "allocated")); | 3523 LOG(HeapSampleBeginEvent("Heap", "allocated")); |
3430 LOG(HeapSampleStats( | 3524 LOG(HeapSampleStats( |
3431 "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects())); | 3525 "Heap", "allocated", Heap::Capacity(), Heap::SizeOfObjects())); |
3432 | 3526 |
3433 HistogramInfo info[LAST_TYPE+1]; | 3527 HistogramInfo info[LAST_TYPE+1]; |
3434 #define DEF_TYPE_NAME(name) info[name].set_name(#name); | 3528 #define DEF_TYPE_NAME(name) info[name].set_name(#name); |
3435 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) | 3529 INSTANCE_TYPE_LIST(DEF_TYPE_NAME) |
3436 #undef DEF_TYPE_NAME | 3530 #undef DEF_TYPE_NAME |
3437 | 3531 |
| 3532 JSConstructorProfile js_cons_profile; |
3438 HeapIterator iterator; | 3533 HeapIterator iterator; |
3439 while (iterator.has_next()) { | 3534 while (iterator.has_next()) { |
3440 CollectStats(iterator.next(), info); | 3535 HeapObject* obj = iterator.next(); |
| 3536 CollectStats(obj, info); |
| 3537 if (obj->IsJSObject()) { |
| 3538 js_cons_profile.CollectStats(JSObject::cast(obj)); |
| 3539 } |
3441 } | 3540 } |
3442 | 3541 |
3443 // Lump all the string types together. | 3542 // Lump all the string types together. |
3444 int string_number = 0; | 3543 int string_number = 0; |
3445 int string_bytes = 0; | 3544 int string_bytes = 0; |
3446 #define INCREMENT_SIZE(type, size, name, camel_name) \ | 3545 #define INCREMENT_SIZE(type, size, name, camel_name) \ |
3447 string_number += info[type].number(); \ | 3546 string_number += info[type].number(); \ |
3448 string_bytes += info[type].bytes(); | 3547 string_bytes += info[type].bytes(); |
3449 STRING_TYPE_LIST(INCREMENT_SIZE) | 3548 STRING_TYPE_LIST(INCREMENT_SIZE) |
3450 #undef INCREMENT_SIZE | 3549 #undef INCREMENT_SIZE |
3451 if (string_bytes > 0) { | 3550 if (string_bytes > 0) { |
3452 LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes)); | 3551 LOG(HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes)); |
3453 } | 3552 } |
3454 | 3553 |
3455 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { | 3554 for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) { |
3456 if (info[i].bytes() > 0) { | 3555 if (info[i].bytes() > 0) { |
3457 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(), | 3556 LOG(HeapSampleItemEvent(info[i].name(), info[i].number(), |
3458 info[i].bytes())); | 3557 info[i].bytes())); |
3459 } | 3558 } |
3460 } | 3559 } |
3461 | 3560 |
| 3561 js_cons_profile.PrintStats(); |
| 3562 |
3462 LOG(HeapSampleEndEvent("Heap", "allocated")); | 3563 LOG(HeapSampleEndEvent("Heap", "allocated")); |
3463 } | 3564 } |
3464 | 3565 |
3465 | 3566 |
3466 #endif | 3567 #endif |
3467 | 3568 |
3468 | 3569 |
3469 | 3570 |
3470 #ifdef DEBUG | 3571 #ifdef DEBUG |
3471 | 3572 |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3738 #ifdef DEBUG | 3839 #ifdef DEBUG |
3739 bool Heap::GarbageCollectionGreedyCheck() { | 3840 bool Heap::GarbageCollectionGreedyCheck() { |
3740 ASSERT(FLAG_gc_greedy); | 3841 ASSERT(FLAG_gc_greedy); |
3741 if (Bootstrapper::IsActive()) return true; | 3842 if (Bootstrapper::IsActive()) return true; |
3742 if (disallow_allocation_failure()) return true; | 3843 if (disallow_allocation_failure()) return true; |
3743 return CollectGarbage(0, NEW_SPACE); | 3844 return CollectGarbage(0, NEW_SPACE); |
3744 } | 3845 } |
3745 #endif | 3846 #endif |
3746 | 3847 |
3747 } } // namespace v8::internal | 3848 } } // namespace v8::internal |
OLD | NEW |