8046598: Scalable Native memory tracking development
Summary: Enhance scalability of native memory tracking
Reviewed-by: coleenp, ctornqvi, gtriantafill
/*
* 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<MallocSite, compare_malloc_size, ResourceObj::ARENA>
_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<MallocSite>* 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<ReservedMemoryRegion, compare_virtual_memory_base, ResourceObj::ARENA>
_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<ReservedMemoryRegion>* 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<VirtualMemoryAllocationSite, compare_allocation_site, ResourceObj::ARENA>
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<VirtualMemoryAllocationSite>* 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<MallocSite, compare_malloc_size, ResourceObj::ARENA>
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<MallocSite, compare_malloc_site, ResourceObj::ARENA>
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<VirtualMemoryAllocationSite, compare_virtual_memory_size, ResourceObj::ARENA>
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<VirtualMemoryAllocationSite, compare_virtual_memory_site, ResourceObj::ARENA>
tmp(arena());
tmp.add(&_virtual_memory_sites);
_virtual_memory_sites.set_head(tmp.head());
tmp.set_head(NULL);
_virtual_memory_sites_order = by_size;
}
}