zgu@3900: /* zgu@3900: * Copyright (c) 2012, 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: zgu@3900: #ifndef SHARE_VM_SERVICES_MEM_RECORDER_HPP zgu@3900: #define SHARE_VM_SERVICES_MEM_RECORDER_HPP zgu@3900: zgu@3900: #include "memory/allocation.hpp" zgu@3900: #include "runtime/os.hpp" zgu@3900: #include "services/memPtrArray.hpp" zgu@3900: zgu@3900: class MemSnapshot; zgu@3900: class MemTracker; zgu@3900: class MemTrackWorker; zgu@3900: zgu@3900: // Fixed size memory pointer array implementation zgu@3900: template class FixedSizeMemPointerArray : zgu@3900: public MemPointerArray { zgu@3900: // This implementation is for memory recorder only zgu@3900: friend class MemRecorder; zgu@3900: zgu@3900: private: zgu@3900: E _data[SIZE]; zgu@3900: int _size; zgu@3900: zgu@3900: protected: zgu@3900: FixedSizeMemPointerArray(bool init_elements = false): zgu@3900: _size(0){ zgu@3900: if (init_elements) { zgu@3900: for (int index = 0; index < SIZE; index ++) { zgu@3900: ::new ((void*)&_data[index]) E(); zgu@3900: } zgu@3900: } zgu@3900: } zgu@3900: zgu@3900: void* operator new(size_t size, const std::nothrow_t& nothrow_constant) { zgu@3900: // the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder' zgu@3900: // to avoid recursion zgu@3900: return os::malloc(size, (mtNMT | otNMTRecorder)); zgu@3900: } zgu@3900: zgu@3900: void* operator new(size_t size) { zgu@3900: assert(false, "use nothrow version"); zgu@3900: return NULL; zgu@3900: } zgu@3900: zgu@3900: void operator delete(void* p) { zgu@3900: os::free(p, (mtNMT | otNMTRecorder)); zgu@3900: } zgu@3900: zgu@3900: // instance size zgu@3900: inline size_t instance_size() const { zgu@3900: return sizeof(FixedSizeMemPointerArray); zgu@3900: } zgu@3900: zgu@3994: NOT_PRODUCT(int capacity() const { return SIZE; }) zgu@3900: zgu@3900: public: zgu@3900: // implementation of public interface zgu@3900: bool out_of_memory() const { return false; } zgu@3900: bool is_empty() const { return _size == 0; } zgu@3900: bool is_full() { return length() >= SIZE; } zgu@3900: int length() const { return _size; } zgu@3900: zgu@3900: void clear() { zgu@3900: _size = 0; zgu@3900: } zgu@3900: zgu@3900: bool append(MemPointer* ptr) { zgu@3900: if (is_full()) return false; zgu@3900: _data[_size ++] = *(E*)ptr; zgu@3900: return true; zgu@3900: } zgu@3900: zgu@3900: virtual bool insert_at(MemPointer* p, int pos) { zgu@3900: assert(false, "append only"); zgu@3900: return false; zgu@3900: } zgu@3900: zgu@3900: virtual bool remove_at(int pos) { zgu@3900: assert(false, "not supported"); zgu@3900: return false; zgu@3900: } zgu@3900: zgu@3900: MemPointer* at(int index) const { zgu@3900: assert(index >= 0 && index < length(), zgu@3900: "parameter check"); zgu@3900: return ((E*)&_data[index]); zgu@3900: } zgu@3900: zgu@3900: void sort(FN_SORT fn) { zgu@3900: qsort((void*)_data, _size, sizeof(E), fn); zgu@3900: } zgu@3900: zgu@3900: bool shrink() { zgu@3900: return false; zgu@3900: } zgu@3900: }; zgu@3900: zgu@3900: zgu@3900: // This iterator requires pre-sorted MemPointerArray, which is sorted by: zgu@3900: // 1. address zgu@3900: // 2. allocation type zgu@3900: // 3. sequence number zgu@3900: // During the array walking, iterator collapses pointers with the same zgu@3900: // address and allocation type, and only returns the one with highest zgu@3900: // sequence number. zgu@3900: // zgu@3900: // This is read-only iterator, update methods are asserted. zgu@3900: class SequencedRecordIterator : public MemPointerArrayIterator { zgu@3900: private: zgu@3900: MemPointerArrayIteratorImpl _itr; zgu@3900: MemPointer* _cur; zgu@3900: zgu@3900: public: zgu@3900: SequencedRecordIterator(const MemPointerArray* arr): zgu@3900: _itr(const_cast(arr)) { zgu@3900: _cur = next_record(); zgu@3900: } zgu@3900: zgu@3900: SequencedRecordIterator(const SequencedRecordIterator& itr): zgu@3900: _itr(itr._itr) { zgu@3900: _cur = next_record(); zgu@3900: } zgu@3900: zgu@3900: // return the pointer at current position zgu@3900: virtual MemPointer* current() const { zgu@3900: return _cur; zgu@3900: }; zgu@3900: zgu@3900: // return the next pointer and advance current position zgu@3900: virtual MemPointer* next() { zgu@3900: _cur = next_record(); zgu@3900: return _cur; zgu@3900: } zgu@3900: zgu@3900: // return the next pointer without advancing current position zgu@3900: virtual MemPointer* peek_next() const { zgu@3900: assert(false, "not implemented"); zgu@3900: return NULL; zgu@3900: zgu@3900: } zgu@3900: // return the previous pointer without changing current position zgu@3900: virtual MemPointer* peek_prev() const { zgu@3900: assert(false, "not implemented"); zgu@3900: return NULL; zgu@3900: } zgu@3900: zgu@3900: // remove the pointer at current position zgu@3900: virtual void remove() { zgu@3900: assert(false, "read-only iterator"); zgu@3900: }; zgu@3900: // insert the pointer at current position zgu@3900: virtual bool insert(MemPointer* ptr) { zgu@3900: assert(false, "read-only iterator"); zgu@3900: return false; zgu@3900: } zgu@3900: zgu@3900: virtual bool insert_after(MemPointer* ptr) { zgu@3900: assert(false, "read-only iterator"); zgu@3900: return false; zgu@3900: } zgu@3900: private: zgu@3900: // collapse the 'same kind' of records, and return this 'kind' of zgu@3900: // record with highest sequence number zgu@3900: MemPointer* next_record(); zgu@3900: zgu@3900: // Test if the two records are the same kind: the same memory block and allocation zgu@3900: // type. zgu@3900: inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const { zgu@4193: assert(!p1->is_vm_pointer() && !p2->is_vm_pointer(), "malloc pointer only"); zgu@3900: return (p1->addr() == p2->addr() && zgu@3900: (p1->flags() &MemPointerRecord::tag_masks) == zgu@3900: (p2->flags() & MemPointerRecord::tag_masks)); zgu@3900: } zgu@3900: }; zgu@3900: zgu@3900: zgu@3900: zgu@3900: #define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512 zgu@3900: zgu@3900: class MemRecorder : public CHeapObj { zgu@3900: friend class MemSnapshot; zgu@3900: friend class MemTracker; zgu@3900: friend class MemTrackWorker; zgu@4400: friend class GenerationData; zgu@3900: zgu@3900: protected: zgu@3900: // the array that holds memory records zgu@3900: MemPointerArray* _pointer_records; zgu@3900: zgu@3900: private: zgu@3900: // used for linked list zgu@3900: MemRecorder* _next; zgu@3900: // active recorder can only record a certain generation data ctornqvi@4512: unsigned long _generation; zgu@3900: zgu@3900: protected: zgu@3900: _NOINLINE_ MemRecorder(); zgu@3900: ~MemRecorder(); zgu@3900: zgu@3900: // record a memory operation zgu@3900: bool record(address addr, MEMFLAGS flags, size_t size, address caller_pc = 0); zgu@3900: zgu@3900: // linked list support zgu@3900: inline void set_next(MemRecorder* rec) { zgu@3900: _next = rec; zgu@3900: } zgu@3900: zgu@3900: inline MemRecorder* next() const { zgu@3900: return _next; zgu@3900: } zgu@3900: zgu@3900: // if the recorder is full zgu@3900: inline bool is_full() const { zgu@3900: assert(_pointer_records != NULL, "just check"); zgu@3900: return _pointer_records->is_full(); zgu@3900: } zgu@3900: zgu@3900: // if running out of memory when initializing recorder's internal zgu@3900: // data zgu@3900: inline bool out_of_memory() const { zgu@3900: return (_pointer_records == NULL || zgu@3900: _pointer_records->out_of_memory()); zgu@3900: } zgu@3900: zgu@3900: inline void clear() { zgu@3900: assert(_pointer_records != NULL, "Just check"); zgu@3900: _pointer_records->clear(); zgu@3900: } zgu@3900: zgu@3900: SequencedRecordIterator pointer_itr(); zgu@3900: ctornqvi@4512: // return the generation of this recorder which it belongs to ctornqvi@4512: unsigned long get_generation() const { return _generation; } zgu@3935: protected: zgu@3900: // number of MemRecorder instance zgu@3935: static volatile jint _instance_count; zgu@3900: zgu@3900: private: zgu@3900: // sorting function, sort records into following order zgu@3900: // 1. memory address zgu@3900: // 2. allocation type zgu@3900: // 3. sequence number zgu@3900: static int sort_record_fn(const void* e1, const void* e2); zgu@3900: zgu@3900: debug_only(void check_dup_seq(jint seq) const;) ctornqvi@4512: void set_generation(); zgu@3900: }; zgu@3900: zgu@3900: #endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP