memSnapshot.hpp revision 3949
3863N/A/*
3863N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
3863N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3863N/A *
3863N/A * This code is free software; you can redistribute it and/or modify it
3863N/A * under the terms of the GNU General Public License version 2 only, as
3863N/A * published by the Free Software Foundation.
3863N/A *
3863N/A * This code is distributed in the hope that it will be useful, but WITHOUT
3863N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3863N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3863N/A * version 2 for more details (a copy is included in the LICENSE file that
3863N/A * accompanied this code).
3863N/A *
3863N/A * You should have received a copy of the GNU General Public License version
3863N/A * 2 along with this work; if not, write to the Free Software Foundation,
3863N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3863N/A *
3863N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3863N/A * or visit www.oracle.com if you need additional information or have any
3863N/A * questions.
3863N/A *
3863N/A */
3863N/A
3863N/A#ifndef SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
3863N/A#define SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
3863N/A
3863N/A#include "memory/allocation.hpp"
3863N/A#include "runtime/mutex.hpp"
3863N/A#include "runtime/mutexLocker.hpp"
3863N/A#include "services/memBaseline.hpp"
3863N/A#include "services/memPtrArray.hpp"
3863N/A
3863N/A
3863N/A// Snapshot pointer array iterator
3863N/A
3863N/A// The pointer array contains malloc-ed pointers
3863N/Aclass MemPointerIterator : public MemPointerArrayIteratorImpl {
3863N/A public:
3863N/A MemPointerIterator(MemPointerArray* arr):
3863N/A MemPointerArrayIteratorImpl(arr) {
3863N/A assert(arr != NULL, "null array");
3863N/A }
3863N/A
3863N/A#ifdef ASSERT
3863N/A virtual bool is_dup_pointer(const MemPointer* ptr1,
3863N/A const MemPointer* ptr2) const {
3863N/A MemPointerRecord* p1 = (MemPointerRecord*)ptr1;
3863N/A MemPointerRecord* p2 = (MemPointerRecord*)ptr2;
3863N/A
3863N/A if (p1->addr() != p2->addr()) return false;
3863N/A if ((p1->flags() & MemPointerRecord::tag_masks) !=
3863N/A (p2->flags() & MemPointerRecord::tag_masks)) {
3863N/A return false;
3863N/A }
3863N/A // we do see multiple commit/uncommit on the same memory, it is ok
3863N/A return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
3863N/A (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
3863N/A }
3863N/A
3863N/A virtual bool insert(MemPointer* ptr) {
3863N/A if (_pos > 0) {
3863N/A MemPointer* p1 = (MemPointer*)ptr;
3863N/A MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
3863N/A assert(!is_dup_pointer(p1, p2),
3949N/A err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
3863N/A }
3863N/A if (_pos < _array->length() -1) {
3863N/A MemPointer* p1 = (MemPointer*)ptr;
3863N/A MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
3863N/A assert(!is_dup_pointer(p1, p2),
3949N/A err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
3863N/A }
3863N/A return _array->insert_at(ptr, _pos);
3863N/A }
3863N/A
3863N/A virtual bool insert_after(MemPointer* ptr) {
3863N/A if (_pos > 0) {
3863N/A MemPointer* p1 = (MemPointer*)ptr;
3863N/A MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
3863N/A assert(!is_dup_pointer(p1, p2),
3949N/A err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
3863N/A }
3863N/A if (_pos < _array->length() - 1) {
3863N/A MemPointer* p1 = (MemPointer*)ptr;
3863N/A MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
3863N/A
3863N/A assert(!is_dup_pointer(p1, p2),
3949N/A err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags()));
3863N/A }
3863N/A if (_array->insert_at(ptr, _pos + 1)) {
3863N/A _pos ++;
3863N/A return true;
3863N/A }
3863N/A return false;
3863N/A }
3863N/A#endif
3863N/A
3863N/A virtual MemPointer* locate(address addr) {
3863N/A MemPointer* cur = current();
3863N/A while (cur != NULL && cur->addr() < addr) {
3863N/A cur = next();
3863N/A }
3863N/A return cur;
3863N/A }
3863N/A};
3863N/A
3863N/Aclass VMMemPointerIterator : public MemPointerIterator {
3863N/A public:
3863N/A VMMemPointerIterator(MemPointerArray* arr):
3863N/A MemPointerIterator(arr) {
3863N/A }
3863N/A
3863N/A // locate an exiting record that contains specified address, or
3863N/A // the record, where the record with specified address, should
3863N/A // be inserted
3863N/A virtual MemPointer* locate(address addr) {
3863N/A VMMemRegion* cur = (VMMemRegion*)current();
3863N/A VMMemRegion* next_p;
3863N/A
3863N/A while (cur != NULL) {
3863N/A if (cur->base() > addr) {
3863N/A return cur;
3863N/A } else {
3863N/A // find nearest existing range that has base address <= addr
3863N/A next_p = (VMMemRegion*)peek_next();
3863N/A if (next_p != NULL && next_p->base() <= addr) {
3863N/A cur = (VMMemRegion*)next();
3863N/A continue;
3863N/A }
3863N/A }
3863N/A
3863N/A if (cur->is_reserve_record() &&
3863N/A cur->base() <= addr &&
3863N/A (cur->base() + cur->size() > addr)) {
3863N/A return cur;
3863N/A } else if (cur->is_commit_record() &&
3863N/A cur->base() <= addr &&
3863N/A (cur->base() + cur->committed_size() > addr)) {
3863N/A return cur;
3863N/A }
3863N/A cur = (VMMemRegion*)next();
3863N/A }
3863N/A return NULL;
3863N/A }
3863N/A
3863N/A#ifdef ASSERT
3863N/A virtual bool is_dup_pointer(const MemPointer* ptr1,
3863N/A const MemPointer* ptr2) const {
3863N/A VMMemRegion* p1 = (VMMemRegion*)ptr1;
3863N/A VMMemRegion* p2 = (VMMemRegion*)ptr2;
3863N/A
3863N/A if (p1->addr() != p2->addr()) return false;
3863N/A if ((p1->flags() & MemPointerRecord::tag_masks) !=
3863N/A (p2->flags() & MemPointerRecord::tag_masks)) {
3863N/A return false;
3863N/A }
3863N/A // we do see multiple commit/uncommit on the same memory, it is ok
3863N/A return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
3863N/A (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
3863N/A }
3863N/A#endif
3863N/A};
3863N/A
3863N/Aclass StagingWalker : public MemPointerArrayIterator {
3863N/A private:
3863N/A MemPointerArrayIteratorImpl _itr;
3863N/A bool _is_vm_record;
3863N/A bool _end_of_array;
3863N/A VMMemRegionEx _vm_record;
3863N/A MemPointerRecordEx _malloc_record;
3863N/A
3863N/A public:
3863N/A StagingWalker(MemPointerArray* arr): _itr(arr) {
3863N/A _end_of_array = false;
3863N/A next();
3863N/A }
3863N/A
3863N/A // return the pointer at current position
3863N/A MemPointer* current() const {
3863N/A if (_end_of_array) {
3863N/A return NULL;
3863N/A }
3863N/A if (is_vm_record()) {
3863N/A return (MemPointer*)&_vm_record;
3863N/A } else {
3863N/A return (MemPointer*)&_malloc_record;
3863N/A }
3863N/A }
3863N/A
3863N/A // return the next pointer and advance current position
3863N/A MemPointer* next();
3863N/A
3863N/A // type of 'current' record
3863N/A bool is_vm_record() const {
3863N/A return _is_vm_record;
3863N/A }
3863N/A
3863N/A // return the next poinger without advancing current position
3863N/A MemPointer* peek_next() const {
3863N/A assert(false, "not supported");
3863N/A return NULL;
3863N/A }
3863N/A
3863N/A MemPointer* peek_prev() const {
3863N/A assert(false, "not supported");
3863N/A return NULL;
3863N/A }
3863N/A // remove the pointer at current position
3863N/A void remove() {
3863N/A assert(false, "not supported");
3863N/A }
3863N/A
3863N/A // insert the pointer at current position
3863N/A bool insert(MemPointer* ptr) {
3863N/A assert(false, "not supported");
3863N/A return false;
3863N/A }
3863N/A
3863N/A bool insert_after(MemPointer* ptr) {
3863N/A assert(false, "not supported");
3863N/A return false;
3863N/A }
3863N/A
3863N/A private:
3863N/A // consolidate all records referring to this vm region
3863N/A bool consolidate_vm_records(VMMemRegionEx* vm_rec);
3863N/A};
3863N/A
3863N/Aclass MemBaseline;
3863N/A
3863N/Aclass MemSnapshot : public CHeapObj<mtNMT> {
3863N/A private:
3863N/A // the following two arrays contain records of all known lived memory blocks
3863N/A // live malloc-ed memory pointers
3863N/A MemPointerArray* _alloc_ptrs;
3863N/A // live virtual memory pointers
3863N/A MemPointerArray* _vm_ptrs;
3863N/A
3863N/A // stagging a generation's data, before
3863N/A // it can be prompted to snapshot
3863N/A MemPointerArray* _staging_area;
3863N/A
3863N/A // the lock to protect this snapshot
3863N/A Monitor* _lock;
3863N/A
3863N/A NOT_PRODUCT(size_t _untracked_count;)
3863N/A friend class MemBaseline;
3863N/A
3863N/A public:
3863N/A MemSnapshot();
3863N/A virtual ~MemSnapshot();
3863N/A
3863N/A // if we are running out of native memory
3863N/A bool out_of_memory() const {
3863N/A return (_alloc_ptrs == NULL || _staging_area == NULL ||
3863N/A _vm_ptrs == NULL || _lock == NULL ||
3863N/A _alloc_ptrs->out_of_memory() ||
3863N/A _staging_area->out_of_memory() ||
3863N/A _vm_ptrs->out_of_memory());
3863N/A }
3863N/A
3863N/A // merge a per-thread memory recorder into staging area
3863N/A bool merge(MemRecorder* rec);
3863N/A // promote staged data to snapshot
3863N/A void promote();
3863N/A
3863N/A
3863N/A void wait(long timeout) {
3863N/A assert(_lock != NULL, "Just check");
3863N/A MonitorLockerEx locker(_lock);
3863N/A locker.wait(true, timeout);
3863N/A }
3863N/A
3863N/A NOT_PRODUCT(void print_snapshot_stats(outputStream* st);)
3863N/A NOT_PRODUCT(void check_staging_data();)
3863N/A NOT_PRODUCT(void check_malloc_pointers();)
3863N/A NOT_PRODUCT(bool has_allocation_record(address addr);)
3863N/A
3863N/A private:
3863N/A // copy pointer data from src to dest
3863N/A void copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src);
3863N/A};
3863N/A
3863N/A
3863N/A#endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP