/* * Copyright (c) 2012, 2014, 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 "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" #include "services/memBaseline.hpp" #include "services/memTracker.hpp" /* * Sizes are sorted in descenting order for reporting */ int compare_malloc_size(const MallocSite& s1, const MallocSite& s2) { if (s1.size() == s2.size()) { return 0; } else if (s1.size() > s2.size()) { return -1; } else { return 1; } } int compare_virtual_memory_size(const VirtualMemoryAllocationSite& s1, const VirtualMemoryAllocationSite& s2) { if (s1.reserved() == s2.reserved()) { return 0; } else if (s1.reserved() > s2.reserved()) { return -1; } else { return 1; } } // Sort into allocation site addresses order for baseline comparison int compare_malloc_site(const MallocSite& s1, const MallocSite& s2) { return s1.call_stack()->compare(*s2.call_stack()); } int compare_virtual_memory_site(const VirtualMemoryAllocationSite& s1, const VirtualMemoryAllocationSite& s2) { return s1.call_stack()->compare(*s2.call_stack()); } /* * Walker to walk malloc allocation site table */ class MallocAllocationSiteWalker : public MallocSiteWalker { private: SortedLinkedList _malloc_sites; size_t _count; // Entries in MallocSiteTable with size = 0 and count = 0, // when the malloc site is not longer there. public: MallocAllocationSiteWalker(Arena* arena) : _count(0), _malloc_sites(arena) { } inline size_t count() const { return _count; } LinkedList* malloc_sites() { return &_malloc_sites; } bool do_malloc_site(const MallocSite* site) { if (site->size() >= MemBaseline::SIZE_THRESHOLD) { if (_malloc_sites.add(*site) != NULL) { _count++; return true; } else { return false; // OOM } } else { // malloc site does not meet threshold, ignore and continue return true; } } }; // Compare virtual memory region's base address int compare_virtual_memory_base(const ReservedMemoryRegion& r1, const ReservedMemoryRegion& r2) { return r1.compare(r2); } // Walk all virtual memory regions for baselining class VirtualMemoryAllocationWalker : public VirtualMemoryWalker { private: SortedLinkedList _virtual_memory_regions; size_t _count; public: VirtualMemoryAllocationWalker(Arena* a) : _count(0), _virtual_memory_regions(a) { } bool do_allocation_site(const ReservedMemoryRegion* rgn) { if (rgn->size() >= MemBaseline::SIZE_THRESHOLD) { if (_virtual_memory_regions.add(*rgn) != NULL) { _count ++; return true; } else { return false; } } return true; } LinkedList* virtual_memory_allocations() { return &_virtual_memory_regions; } }; bool MemBaseline::baseline_summary() { assert(_malloc_memory_snapshot == NULL, "Malloc baseline not yet reset"); assert(_virtual_memory_snapshot == NULL, "Virtual baseline not yet reset"); _malloc_memory_snapshot = new (arena()) MallocMemorySnapshot(); _virtual_memory_snapshot = new (arena()) VirtualMemorySnapshot(); if (_malloc_memory_snapshot == NULL || _virtual_memory_snapshot == NULL) { return false; } MallocMemorySummary::snapshot(_malloc_memory_snapshot); VirtualMemorySummary::snapshot(_virtual_memory_snapshot); return true; } bool MemBaseline::baseline_allocation_sites() { assert(arena() != NULL, "Just check"); // Malloc allocation sites MallocAllocationSiteWalker malloc_walker(arena()); if (!MallocSiteTable::walk_malloc_site(&malloc_walker)) { return false; } _malloc_sites.set_head(malloc_walker.malloc_sites()->head()); // The malloc sites are collected in size order _malloc_sites_order = by_size; // Virtual memory allocation sites VirtualMemoryAllocationWalker virtual_memory_walker(arena()); if (!VirtualMemoryTracker::walk_virtual_memory(&virtual_memory_walker)) { return false; } // Virtual memory allocations are collected in call stack order _virtual_memory_allocations.set_head(virtual_memory_walker.virtual_memory_allocations()->head()); if (!aggregate_virtual_memory_allocation_sites()) { return false; } // Virtual memory allocation sites are aggregrated in call stack order _virtual_memory_sites_order = by_address; return true; } bool MemBaseline::baseline(bool summaryOnly) { if (arena() == NULL) { _arena = new (std::nothrow, mtNMT) Arena(mtNMT); if (arena() == NULL) return false; } reset(); _class_count = InstanceKlass::number_of_instance_classes(); if (!baseline_summary()) { return false; } _baseline_type = Summary_baselined; // baseline details if (!summaryOnly && MemTracker::tracking_level() == NMT_detail) { baseline_allocation_sites(); _baseline_type = Detail_baselined; } return true; } int compare_allocation_site(const VirtualMemoryAllocationSite& s1, const VirtualMemoryAllocationSite& s2) { return s1.call_stack()->compare(*s2.call_stack()); } bool MemBaseline::aggregate_virtual_memory_allocation_sites() { SortedLinkedList allocation_sites(arena()); VirtualMemoryAllocationIterator itr = virtual_memory_allocations(); const ReservedMemoryRegion* rgn; VirtualMemoryAllocationSite* site; while ((rgn = itr.next()) != NULL) { VirtualMemoryAllocationSite tmp(*rgn->call_stack()); site = allocation_sites.find(tmp); if (site == NULL) { LinkedListNode* node = allocation_sites.add(tmp); if (node == NULL) return false; site = node->data(); } site->reserve_memory(rgn->size()); site->commit_memory(rgn->committed_size()); } _virtual_memory_sites.set_head(allocation_sites.head()); return true; } MallocSiteIterator MemBaseline::malloc_sites(SortingOrder order) { assert(!_malloc_sites.is_empty(), "Detail baseline?"); switch(order) { case by_size: malloc_sites_to_size_order(); break; case by_site: malloc_sites_to_allocation_site_order(); break; case by_address: default: ShouldNotReachHere(); } return MallocSiteIterator(_malloc_sites.head()); } VirtualMemorySiteIterator MemBaseline::virtual_memory_sites(SortingOrder order) { assert(!_virtual_memory_sites.is_empty(), "Detail baseline?"); switch(order) { case by_size: virtual_memory_sites_to_size_order(); break; case by_site: virtual_memory_sites_to_reservation_site_order(); break; case by_address: default: ShouldNotReachHere(); } return VirtualMemorySiteIterator(_virtual_memory_sites.head()); } // Sorting allocations sites in different orders void MemBaseline::malloc_sites_to_size_order() { if (_malloc_sites_order != by_size) { SortedLinkedList tmp(arena()); // Add malloc sites to sorted linked list to sort into size order tmp.move(&_malloc_sites); _malloc_sites.set_head(tmp.head()); tmp.set_head(NULL); _malloc_sites_order = by_size; } } void MemBaseline::malloc_sites_to_allocation_site_order() { if (_malloc_sites_order != by_site) { SortedLinkedList tmp(arena()); // Add malloc sites to sorted linked list to sort into site (address) order tmp.move(&_malloc_sites); _malloc_sites.set_head(tmp.head()); tmp.set_head(NULL); _malloc_sites_order = by_site; } } void MemBaseline::virtual_memory_sites_to_size_order() { if (_virtual_memory_sites_order != by_size) { SortedLinkedList tmp(arena()); tmp.move(&_virtual_memory_sites); _virtual_memory_sites.set_head(tmp.head()); tmp.set_head(NULL); _virtual_memory_sites_order = by_size; } } void MemBaseline::virtual_memory_sites_to_reservation_site_order() { if (_virtual_memory_sites_order != by_size) { SortedLinkedList tmp(arena()); tmp.add(&_virtual_memory_sites); _virtual_memory_sites.set_head(tmp.head()); tmp.set_head(NULL); _virtual_memory_sites_order = by_size; } }