Mercurial > hg > truffle
view src/share/vm/services/memBaseline.cpp @ 8733:9def4075da6d
8008079: G1: Add nextObject routine to CMBitMapRO and replace nextWord
Summary: Update the task local finger to the start of the next object when marking aborts, in order to avoid the redundant scanning of all 0's when the marking task restarts, if otherwise updating to the next word. In addition, reuse the routine nextObject() in routine iterate().
Reviewed-by: johnc, ysr
Contributed-by: tamao <tao.mao@oracle.com>
author | tamao |
---|---|
date | Tue, 05 Mar 2013 15:36:56 -0800 |
parents | 4102b59539ce |
children | fbca7eaeac2e |
line wrap: on
line source
/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ #include "precompiled.hpp" #include "memory/allocation.hpp" #include "services/memBaseline.hpp" #include "services/memTracker.hpp" MemType2Name MemBaseline::MemType2NameMap[NUMBER_OF_MEMORY_TYPE] = { {mtJavaHeap, "Java Heap"}, {mtClass, "Class"}, {mtThreadStack,"Thread Stack"}, {mtThread, "Thread"}, {mtCode, "Code"}, {mtGC, "GC"}, {mtCompiler, "Compiler"}, {mtInternal, "Internal"}, {mtOther, "Other"}, {mtSymbol, "Symbol"}, {mtNMT, "Memory Tracking"}, {mtChunk, "Pooled Free Chunks"}, {mtClassShared,"Shared spaces for classes"}, {mtTest, "Test"}, {mtNone, "Unknown"} // It can happen when type tagging records are lagging // behind }; MemBaseline::MemBaseline() { _baselined = false; for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { _malloc_data[index].set_type(MemType2NameMap[index]._flag); _vm_data[index].set_type(MemType2NameMap[index]._flag); _arena_data[index].set_type(MemType2NameMap[index]._flag); } _malloc_cs = NULL; _vm_cs = NULL; _vm_map = NULL; _number_of_classes = 0; _number_of_threads = 0; } void MemBaseline::clear() { if (_malloc_cs != NULL) { delete _malloc_cs; _malloc_cs = NULL; } if (_vm_cs != NULL) { delete _vm_cs; _vm_cs = NULL; } if (_vm_map != NULL) { delete _vm_map; _vm_map = NULL; } reset(); } void MemBaseline::reset() { _baselined = false; _total_vm_reserved = 0; _total_vm_committed = 0; _total_malloced = 0; _number_of_classes = 0; if (_malloc_cs != NULL) _malloc_cs->clear(); if (_vm_cs != NULL) _vm_cs->clear(); if (_vm_map != NULL) _vm_map->clear(); for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { _malloc_data[index].clear(); _vm_data[index].clear(); _arena_data[index].clear(); } } MemBaseline::~MemBaseline() { clear(); } // baseline malloc'd memory records, generate overall summary and summaries by // memory types bool MemBaseline::baseline_malloc_summary(const MemPointerArray* malloc_records) { MemPointerArrayIteratorImpl malloc_itr((MemPointerArray*)malloc_records); MemPointerRecord* malloc_ptr = (MemPointerRecord*)malloc_itr.current(); size_t used_arena_size = 0; int index; while (malloc_ptr != NULL) { index = flag2index(FLAGS_TO_MEMORY_TYPE(malloc_ptr->flags())); size_t size = malloc_ptr->size(); if (malloc_ptr->is_arena_memory_record()) { // We do have anonymous arenas, they are either used as value objects, // which are embedded inside other objects, or used as stack objects. _arena_data[index].inc(size); used_arena_size += size; } else { _total_malloced += size; _malloc_data[index].inc(size); if (malloc_ptr->is_arena_record()) { // see if arena memory record present MemPointerRecord* next_malloc_ptr = (MemPointerRecordEx*)malloc_itr.peek_next(); if (next_malloc_ptr->is_arena_memory_record()) { assert(next_malloc_ptr->is_memory_record_of_arena(malloc_ptr), "Arena records do not match"); size = next_malloc_ptr->size(); _arena_data[index].inc(size); used_arena_size += size; malloc_itr.next(); } } } malloc_ptr = (MemPointerRecordEx*)malloc_itr.next(); } // substract used arena size to get size of arena chunk in free list index = flag2index(mtChunk); _malloc_data[index].reduce(used_arena_size); // we really don't know how many chunks in free list, so just set to // 0 _malloc_data[index].overwrite_counter(0); return true; } // baseline mmap'd memory records, generate overall summary and summaries by // memory types bool MemBaseline::baseline_vm_summary(const MemPointerArray* vm_records) { MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records); VMMemRegion* vm_ptr = (VMMemRegion*)vm_itr.current(); int index; while (vm_ptr != NULL) { if (vm_ptr->is_reserved_region()) { index = flag2index(FLAGS_TO_MEMORY_TYPE(vm_ptr->flags())); // we use the number of thread stack to count threads if (IS_MEMORY_TYPE(vm_ptr->flags(), mtThreadStack)) { _number_of_threads ++; } _total_vm_reserved += vm_ptr->size(); _vm_data[index].inc(vm_ptr->size(), 0); } else { _total_vm_committed += vm_ptr->size(); _vm_data[index].inc(0, vm_ptr->size()); } vm_ptr = (VMMemRegion*)vm_itr.next(); } return true; } // baseline malloc'd memory by callsites, but only the callsites with memory allocation // over 1KB are stored. bool MemBaseline::baseline_malloc_details(const MemPointerArray* malloc_records) { assert(MemTracker::track_callsite(), "detail tracking is off"); MemPointerArrayIteratorImpl malloc_itr(const_cast<MemPointerArray*>(malloc_records)); MemPointerRecordEx* malloc_ptr = (MemPointerRecordEx*)malloc_itr.current(); MallocCallsitePointer malloc_callsite; // initailize malloc callsite array if (_malloc_cs == NULL) { _malloc_cs = new (std::nothrow) MemPointerArrayImpl<MallocCallsitePointer>(64); // out of native memory if (_malloc_cs == NULL || _malloc_cs->out_of_memory()) { return false; } } else { _malloc_cs->clear(); } MemPointerArray* malloc_data = const_cast<MemPointerArray*>(malloc_records); // sort into callsite pc order. Details are aggregated by callsites malloc_data->sort((FN_SORT)malloc_sort_by_pc); bool ret = true; // baseline memory that is totaled over 1 KB while (malloc_ptr != NULL) { if (!MemPointerRecord::is_arena_memory_record(malloc_ptr->flags())) { // skip thread stacks if (!IS_MEMORY_TYPE(malloc_ptr->flags(), mtThreadStack)) { if (malloc_callsite.addr() != malloc_ptr->pc()) { if ((malloc_callsite.amount()/K) > 0) { if (!_malloc_cs->append(&malloc_callsite)) { ret = false; break; } } malloc_callsite = MallocCallsitePointer(malloc_ptr->pc()); } malloc_callsite.inc(malloc_ptr->size()); } } malloc_ptr = (MemPointerRecordEx*)malloc_itr.next(); } // restore to address order. Snapshot malloc data is maintained in memory // address order. malloc_data->sort((FN_SORT)malloc_sort_by_addr); if (!ret) { return false; } // deal with last record if (malloc_callsite.addr() != 0 && (malloc_callsite.amount()/K) > 0) { if (!_malloc_cs->append(&malloc_callsite)) { return false; } } return true; } // baseline mmap'd memory by callsites bool MemBaseline::baseline_vm_details(const MemPointerArray* vm_records) { assert(MemTracker::track_callsite(), "detail tracking is off"); VMCallsitePointer vm_callsite; VMCallsitePointer* cur_callsite = NULL; MemPointerArrayIteratorImpl vm_itr((MemPointerArray*)vm_records); VMMemRegionEx* vm_ptr = (VMMemRegionEx*)vm_itr.current(); // initialize virtual memory map array if (_vm_map == NULL) { _vm_map = new (std::nothrow) MemPointerArrayImpl<VMMemRegionEx>(vm_records->length()); if (_vm_map == NULL || _vm_map->out_of_memory()) { return false; } } else { _vm_map->clear(); } // initialize virtual memory callsite array if (_vm_cs == NULL) { _vm_cs = new (std::nothrow) MemPointerArrayImpl<VMCallsitePointer>(64); if (_vm_cs == NULL || _vm_cs->out_of_memory()) { return false; } } else { _vm_cs->clear(); } // consolidate virtual memory data VMMemRegionEx* reserved_rec = NULL; VMMemRegionEx* committed_rec = NULL; // vm_ptr is coming in increasing base address order while (vm_ptr != NULL) { if (vm_ptr->is_reserved_region()) { // consolidate reserved memory regions for virtual memory map. // The criteria for consolidation is: // 1. two adjacent reserved memory regions // 2. belong to the same memory type // 3. reserved from the same callsite if (reserved_rec == NULL || reserved_rec->base() + reserved_rec->size() != vm_ptr->addr() || FLAGS_TO_MEMORY_TYPE(reserved_rec->flags()) != FLAGS_TO_MEMORY_TYPE(vm_ptr->flags()) || reserved_rec->pc() != vm_ptr->pc()) { if (!_vm_map->append(vm_ptr)) { return false; } // inserted reserved region, we need the pointer to the element in virtual // memory map array. reserved_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1); } else { reserved_rec->expand_region(vm_ptr->addr(), vm_ptr->size()); } if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) { return false; } vm_callsite = VMCallsitePointer(vm_ptr->pc()); cur_callsite = &vm_callsite; vm_callsite.inc(vm_ptr->size(), 0); } else { // consolidate committed memory regions for virtual memory map // The criterial is: // 1. two adjacent committed memory regions // 2. committed from the same callsite if (committed_rec == NULL || committed_rec->base() + committed_rec->size() != vm_ptr->addr() || committed_rec->pc() != vm_ptr->pc()) { if (!_vm_map->append(vm_ptr)) { return false; } committed_rec = (VMMemRegionEx*)_vm_map->at(_vm_map->length() - 1); } else { committed_rec->expand_region(vm_ptr->addr(), vm_ptr->size()); } vm_callsite.inc(0, vm_ptr->size()); } vm_ptr = (VMMemRegionEx*)vm_itr.next(); } // deal with last record if (cur_callsite != NULL && !_vm_cs->append(cur_callsite)) { return false; } // sort it into callsite pc order. Details are aggregated by callsites _vm_cs->sort((FN_SORT)bl_vm_sort_by_pc); // walk the array to consolidate record by pc MemPointerArrayIteratorImpl itr(_vm_cs); VMCallsitePointer* callsite_rec = (VMCallsitePointer*)itr.current(); VMCallsitePointer* next_rec = (VMCallsitePointer*)itr.next(); while (next_rec != NULL) { assert(callsite_rec != NULL, "Sanity check"); if (next_rec->addr() == callsite_rec->addr()) { callsite_rec->inc(next_rec->reserved_amount(), next_rec->committed_amount()); itr.remove(); next_rec = (VMCallsitePointer*)itr.current(); } else { callsite_rec = next_rec; next_rec = (VMCallsitePointer*)itr.next(); } } return true; } // baseline a snapshot. If summary_only = false, memory usages aggregated by // callsites are also baselined. bool MemBaseline::baseline(MemSnapshot& snapshot, bool summary_only) { MutexLockerEx snapshot_locker(snapshot._lock, true); reset(); _baselined = baseline_malloc_summary(snapshot._alloc_ptrs) && baseline_vm_summary(snapshot._vm_ptrs); _number_of_classes = snapshot.number_of_classes(); if (!summary_only && MemTracker::track_callsite() && _baselined) { _baselined = baseline_malloc_details(snapshot._alloc_ptrs) && baseline_vm_details(snapshot._vm_ptrs); } return _baselined; } int MemBaseline::flag2index(MEMFLAGS flag) const { for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { if (MemType2NameMap[index]._flag == flag) { return index; } } assert(false, "no type"); return -1; } const char* MemBaseline::type2name(MEMFLAGS type) { for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { if (MemType2NameMap[index]._flag == type) { return MemType2NameMap[index]._name; } } assert(false, err_msg("bad type %x", type)); return NULL; } MemBaseline& MemBaseline::operator=(const MemBaseline& other) { _total_malloced = other._total_malloced; _total_vm_reserved = other._total_vm_reserved; _total_vm_committed = other._total_vm_committed; _baselined = other._baselined; _number_of_classes = other._number_of_classes; for (int index = 0; index < NUMBER_OF_MEMORY_TYPE; index ++) { _malloc_data[index] = other._malloc_data[index]; _vm_data[index] = other._vm_data[index]; _arena_data[index] = other._arena_data[index]; } if (MemTracker::track_callsite()) { assert(_malloc_cs != NULL && _vm_cs != NULL, "out of memory"); assert(other._malloc_cs != NULL && other._vm_cs != NULL, "not properly baselined"); _malloc_cs->clear(); _vm_cs->clear(); int index; for (index = 0; index < other._malloc_cs->length(); index ++) { _malloc_cs->append(other._malloc_cs->at(index)); } for (index = 0; index < other._vm_cs->length(); index ++) { _vm_cs->append(other._vm_cs->at(index)); } } return *this; } /* compare functions for sorting */ // sort snapshot malloc'd records in callsite pc order int MemBaseline::malloc_sort_by_pc(const void* p1, const void* p2) { assert(MemTracker::track_callsite(),"Just check"); const MemPointerRecordEx* mp1 = (const MemPointerRecordEx*)p1; const MemPointerRecordEx* mp2 = (const MemPointerRecordEx*)p2; return UNSIGNED_COMPARE(mp1->pc(), mp2->pc()); } // sort baselined malloc'd records in size order int MemBaseline::bl_malloc_sort_by_size(const void* p1, const void* p2) { assert(MemTracker::is_on(), "Just check"); const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1; const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2; return UNSIGNED_COMPARE(mp2->amount(), mp1->amount()); } // sort baselined malloc'd records in callsite pc order int MemBaseline::bl_malloc_sort_by_pc(const void* p1, const void* p2) { assert(MemTracker::is_on(), "Just check"); const MallocCallsitePointer* mp1 = (const MallocCallsitePointer*)p1; const MallocCallsitePointer* mp2 = (const MallocCallsitePointer*)p2; return UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); } // sort baselined mmap'd records in size (reserved size) order int MemBaseline::bl_vm_sort_by_size(const void* p1, const void* p2) { assert(MemTracker::is_on(), "Just check"); const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1; const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2; return UNSIGNED_COMPARE(mp2->reserved_amount(), mp1->reserved_amount()); } // sort baselined mmap'd records in callsite pc order int MemBaseline::bl_vm_sort_by_pc(const void* p1, const void* p2) { assert(MemTracker::is_on(), "Just check"); const VMCallsitePointer* mp1 = (const VMCallsitePointer*)p1; const VMCallsitePointer* mp2 = (const VMCallsitePointer*)p2; return UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); } // sort snapshot malloc'd records in memory block address order int MemBaseline::malloc_sort_by_addr(const void* p1, const void* p2) { assert(MemTracker::is_on(), "Just check"); const MemPointerRecord* mp1 = (const MemPointerRecord*)p1; const MemPointerRecord* mp2 = (const MemPointerRecord*)p2; int delta = UNSIGNED_COMPARE(mp1->addr(), mp2->addr()); assert(delta != 0, "dup pointer"); return delta; }