zgu@3900: /* zgu@7074: * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. zgu@3900: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. zgu@3900: * zgu@3900: * This code is free software; you can redistribute it and/or modify it zgu@3900: * under the terms of the GNU General Public License version 2 only, as zgu@3900: * published by the Free Software Foundation. zgu@3900: * zgu@3900: * This code is distributed in the hope that it will be useful, but WITHOUT zgu@3900: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or zgu@3900: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License zgu@3900: * version 2 for more details (a copy is included in the LICENSE file that zgu@3900: * accompanied this code). zgu@3900: * zgu@3900: * You should have received a copy of the GNU General Public License version zgu@3900: * 2 along with this work; if not, write to the Free Software Foundation, zgu@3900: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. zgu@3900: * zgu@3900: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA zgu@3900: * or visit www.oracle.com if you need additional information or have any zgu@3900: * questions. zgu@3900: * zgu@3900: */ zgu@3900: #include "precompiled.hpp" zgu@7074: zgu@3900: #include "memory/allocation.hpp" zgu@4980: #include "runtime/safepoint.hpp" zgu@4980: #include "runtime/thread.inline.hpp" zgu@3900: #include "services/memBaseline.hpp" zgu@3900: #include "services/memTracker.hpp" zgu@3900: zgu@7074: /* zgu@7074: * Sizes are sorted in descenting order for reporting zgu@7074: */ zgu@7074: int compare_malloc_size(const MallocSite& s1, const MallocSite& s2) { zgu@7074: if (s1.size() == s2.size()) { zgu@7074: return 0; zgu@7074: } else if (s1.size() > s2.size()) { zgu@7074: return -1; zgu@7074: } else { zgu@7074: return 1; zgu@3900: } zgu@3900: } zgu@3900: zgu@7074: zgu@7074: int compare_virtual_memory_size(const VirtualMemoryAllocationSite& s1, zgu@7074: const VirtualMemoryAllocationSite& s2) { zgu@7074: if (s1.reserved() == s2.reserved()) { zgu@7074: return 0; zgu@7074: } else if (s1.reserved() > s2.reserved()) { zgu@7074: return -1; zgu@7074: } else { zgu@7074: return 1; zgu@7074: } zgu@3900: } zgu@3900: zgu@7074: // Sort into allocation site addresses order for baseline comparison zgu@7074: int compare_malloc_site(const MallocSite& s1, const MallocSite& s2) { zgu@7074: return s1.call_stack()->compare(*s2.call_stack()); zgu@7074: } zgu@7074: zgu@7074: zgu@7074: int compare_virtual_memory_site(const VirtualMemoryAllocationSite& s1, zgu@7074: const VirtualMemoryAllocationSite& s2) { zgu@7074: return s1.call_stack()->compare(*s2.call_stack()); zgu@7074: } zgu@7074: zgu@7074: /* zgu@7074: * Walker to walk malloc allocation site table zgu@7074: */ zgu@7074: class MallocAllocationSiteWalker : public MallocSiteWalker { zgu@7074: private: zgu@7080: SortedLinkedList _malloc_sites; zgu@7074: size_t _count; zgu@7074: zgu@7074: // Entries in MallocSiteTable with size = 0 and count = 0, zgu@7074: // when the malloc site is not longer there. zgu@7074: public: zgu@7080: MallocAllocationSiteWalker() : _count(0) { } zgu@7074: zgu@7074: inline size_t count() const { return _count; } zgu@7074: zgu@7074: LinkedList* malloc_sites() { zgu@7074: return &_malloc_sites; zgu@7074: } zgu@7074: zgu@7074: bool do_malloc_site(const MallocSite* site) { zgu@7074: if (site->size() >= MemBaseline::SIZE_THRESHOLD) { zgu@7074: if (_malloc_sites.add(*site) != NULL) { zgu@7074: _count++; zgu@7074: return true; zgu@7074: } else { zgu@7074: return false; // OOM zgu@7074: } zgu@4274: } else { zgu@7074: // malloc site does not meet threshold, ignore and continue zgu@7074: return true; zgu@7074: } zgu@7074: } zgu@7074: }; zgu@7074: zgu@7074: // Compare virtual memory region's base address zgu@7074: int compare_virtual_memory_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { zgu@7074: return r1.compare(r2); zgu@7074: } zgu@7074: zgu@7074: // Walk all virtual memory regions for baselining zgu@7074: class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { zgu@7074: private: zgu@7080: SortedLinkedList zgu@7074: _virtual_memory_regions; zgu@7074: size_t _count; zgu@7074: zgu@7074: public: zgu@7080: VirtualMemoryAllocationWalker() : _count(0) { } zgu@7074: zgu@7074: bool do_allocation_site(const ReservedMemoryRegion* rgn) { zgu@7074: if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) { zgu@7074: if (_virtual_memory_regions.add(*rgn) != NULL) { zgu@7074: _count ++; zgu@7074: return true; zgu@7074: } else { zgu@7074: return false; zgu@3900: } zgu@3900: } zgu@7074: return true; zgu@3900: } zgu@3900: zgu@7074: LinkedList* virtual_memory_allocations() { zgu@7074: return &_virtual_memory_regions; zgu@7074: } zgu@7074: }; zgu@7074: zgu@7074: zgu@7074: bool MemBaseline::baseline_summary() { zgu@7080: MallocMemorySummary::snapshot(&_malloc_memory_snapshot); zgu@7080: VirtualMemorySummary::snapshot(&_virtual_memory_snapshot); zgu@7074: return true; zgu@7074: } zgu@7074: zgu@7074: bool MemBaseline::baseline_allocation_sites() { zgu@7074: // Malloc allocation sites zgu@7080: MallocAllocationSiteWalker malloc_walker; zgu@7074: if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) { zgu@7074: return false; zgu@7074: } zgu@7074: zgu@7080: _malloc_sites.move(malloc_walker.malloc_sites()); zgu@7074: // The malloc sites are collected in size order zgu@7074: _malloc_sites_order = by_size; zgu@7074: zgu@7074: // Virtual memory allocation sites zgu@7080: VirtualMemoryAllocationWalker virtual_memory_walker; zgu@7074: if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) { zgu@7074: return false; zgu@7074: } zgu@7074: zgu@7074: // Virtual memory allocations are collected in call stack order zgu@7080: _virtual_memory_allocations.move(virtual_memory_walker.virtual_memory_allocations()); zgu@7074: zgu@7074: if (!aggregate_virtual_memory_allocation_sites()) { zgu@7074: return false; zgu@7074: } zgu@7074: // Virtual memory allocation sites are aggregrated in call stack order zgu@7074: _virtual_memory_sites_order = by_address; zgu@3900: zgu@3900: return true; zgu@3900: } zgu@3900: zgu@7074: bool MemBaseline::baseline(bool summaryOnly) { zgu@7074: reset(); zgu@4193: zgu@7074: _class_count = InstanceKlass::number_of_instance_classes(); zgu@4193: zgu@7074: if (!baseline_summary()) { zgu@4193: return false; zgu@4193: } zgu@4193: zgu@7074: _baseline_type = Summary_baselined; zgu@4193: zgu@7074: // baseline details zgu@7074: if (!summaryOnly && zgu@7074: MemTracker::tracking_level() == NMT_detail) { zgu@7074: baseline_allocation_sites(); zgu@7074: _baseline_type = Detail_baselined; zgu@4193: } zgu@4193: zgu@3900: return true; zgu@3900: } zgu@3900: zgu@7074: int compare_allocation_site(const VirtualMemoryAllocationSite& s1, zgu@7074: const VirtualMemoryAllocationSite& s2) { zgu@7074: return s1.call_stack()->compare(*s2.call_stack()); zgu@3900: } zgu@3900: zgu@7074: bool MemBaseline::aggregate_virtual_memory_allocation_sites() { zgu@7080: SortedLinkedList allocation_sites; zgu@3900: zgu@7074: VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); zgu@7074: const ReservedMemoryRegion* rgn; zgu@7074: VirtualMemoryAllocationSite* site; zgu@7074: while ((rgn = itr.next()) != NULL) { zgu@7074: VirtualMemoryAllocationSite tmp(*rgn->call_stack()); zgu@7074: site = allocation_sites.find(tmp); zgu@7074: if (site == NULL) { zgu@7074: LinkedListNode* node = zgu@7074: allocation_sites.add(tmp); zgu@7074: if (node == NULL) return false; zgu@7074: site = node->data(); zgu@3900: } zgu@7074: site->reserve_memory(rgn->size()); zgu@7074: site->commit_memory(rgn->committed_size()); zgu@3900: } zgu@7074: zgu@7080: _virtual_memory_sites.move(&allocation_sites); zgu@7074: return true; zgu@3900: } zgu@3900: zgu@7074: MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) { zgu@7080: assert(!_malloc_sites.is_empty(), "Not detail baseline"); zgu@7074: switch(order) { zgu@7074: case by_size: zgu@7074: malloc_sites_to_size_order(); zgu@7074: break; zgu@7074: case by_site: zgu@7074: malloc_sites_to_allocation_site_order(); zgu@7074: break; zgu@7074: case by_address: zgu@7074: default: zgu@7074: ShouldNotReachHere(); zgu@3900: } zgu@7074: return MallocSiteIterator(_malloc_sites.head()); zgu@3900: } zgu@3900: zgu@7074: VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) { zgu@7080: assert(!_virtual_memory_sites.is_empty(), "Not detail baseline"); zgu@7074: switch(order) { zgu@7074: case by_size: zgu@7074: virtual_memory_sites_to_size_order(); zgu@7074: break; zgu@7074: case by_site: zgu@7074: virtual_memory_sites_to_reservation_site_order(); zgu@7074: break; zgu@7074: case by_address: zgu@7074: default: zgu@7074: ShouldNotReachHere(); zgu@3900: } zgu@7074: return VirtualMemorySiteIterator(_virtual_memory_sites.head()); zgu@3900: } zgu@3900: zgu@3900: zgu@7074: // Sorting allocations sites in different orders zgu@7074: void MemBaseline::malloc_sites_to_size_order() { zgu@7074: if (_malloc_sites_order != by_size) { zgu@7080: SortedLinkedList tmp; zgu@7074: zgu@7074: // Add malloc sites to sorted linked list to sort into size order zgu@7074: tmp.move(&_malloc_sites); zgu@7074: _malloc_sites.set_head(tmp.head()); zgu@7074: tmp.set_head(NULL); zgu@7074: _malloc_sites_order = by_size; zgu@7074: } zgu@3900: } zgu@3900: zgu@7074: void MemBaseline::malloc_sites_to_allocation_site_order() { zgu@7074: if (_malloc_sites_order != by_site) { zgu@7080: SortedLinkedList tmp; zgu@7074: // Add malloc sites to sorted linked list to sort into site (address) order zgu@7074: tmp.move(&_malloc_sites); zgu@7074: _malloc_sites.set_head(tmp.head()); zgu@7074: tmp.set_head(NULL); zgu@7074: _malloc_sites_order = by_site; zgu@7074: } zgu@3900: } zgu@3900: zgu@7074: void MemBaseline::virtual_memory_sites_to_size_order() { zgu@7074: if (_virtual_memory_sites_order != by_size) { zgu@7080: SortedLinkedList tmp; zgu@7074: zgu@7074: tmp.move(&_virtual_memory_sites); zgu@7074: zgu@7074: _virtual_memory_sites.set_head(tmp.head()); zgu@7074: tmp.set_head(NULL); zgu@7074: _virtual_memory_sites_order = by_size; zgu@7074: } zgu@3900: } zgu@3900: zgu@7074: void MemBaseline::virtual_memory_sites_to_reservation_site_order() { zgu@7074: if (_virtual_memory_sites_order != by_size) { zgu@7080: SortedLinkedList tmp; zgu@3900: zgu@7080: tmp.move(&_virtual_memory_sites); zgu@7074: zgu@7074: _virtual_memory_sites.set_head(tmp.head()); zgu@7074: tmp.set_head(NULL); zgu@7074: zgu@7074: _virtual_memory_sites_order = by_size; zgu@7074: } zgu@3900: } zgu@3900: