src/share/vm/services/memSnapshot.hpp

Thu, 28 Jun 2012 17:03:16 -0400

author
zgu
date
Thu, 28 Jun 2012 17:03:16 -0400
changeset 3900
d2a62e0f25eb
child 3986
4acebbe310e1
permissions
-rw-r--r--

6995781: Native Memory Tracking (Phase 1)
7151532: DCmd for hotspot native memory tracking
Summary: Implementation of native memory tracking phase 1, which tracks VM native memory usage, and related DCmd
Reviewed-by: acorn, coleenp, fparain

zgu@3900 1 /*
zgu@3900 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
zgu@3900 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
zgu@3900 4 *
zgu@3900 5 * This code is free software; you can redistribute it and/or modify it
zgu@3900 6 * under the terms of the GNU General Public License version 2 only, as
zgu@3900 7 * published by the Free Software Foundation.
zgu@3900 8 *
zgu@3900 9 * This code is distributed in the hope that it will be useful, but WITHOUT
zgu@3900 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
zgu@3900 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
zgu@3900 12 * version 2 for more details (a copy is included in the LICENSE file that
zgu@3900 13 * accompanied this code).
zgu@3900 14 *
zgu@3900 15 * You should have received a copy of the GNU General Public License version
zgu@3900 16 * 2 along with this work; if not, write to the Free Software Foundation,
zgu@3900 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
zgu@3900 18 *
zgu@3900 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
zgu@3900 20 * or visit www.oracle.com if you need additional information or have any
zgu@3900 21 * questions.
zgu@3900 22 *
zgu@3900 23 */
zgu@3900 24
zgu@3900 25 #ifndef SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
zgu@3900 26 #define SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP
zgu@3900 27
zgu@3900 28 #include "memory/allocation.hpp"
zgu@3900 29 #include "runtime/mutex.hpp"
zgu@3900 30 #include "runtime/mutexLocker.hpp"
zgu@3900 31 #include "services/memBaseline.hpp"
zgu@3900 32 #include "services/memPtrArray.hpp"
zgu@3900 33
zgu@3900 34
zgu@3900 35 // Snapshot pointer array iterator
zgu@3900 36
zgu@3900 37 // The pointer array contains malloc-ed pointers
zgu@3900 38 class MemPointerIterator : public MemPointerArrayIteratorImpl {
zgu@3900 39 public:
zgu@3900 40 MemPointerIterator(MemPointerArray* arr):
zgu@3900 41 MemPointerArrayIteratorImpl(arr) {
zgu@3900 42 assert(arr != NULL, "null array");
zgu@3900 43 }
zgu@3900 44
zgu@3900 45 #ifdef ASSERT
zgu@3900 46 virtual bool is_dup_pointer(const MemPointer* ptr1,
zgu@3900 47 const MemPointer* ptr2) const {
zgu@3900 48 MemPointerRecord* p1 = (MemPointerRecord*)ptr1;
zgu@3900 49 MemPointerRecord* p2 = (MemPointerRecord*)ptr2;
zgu@3900 50
zgu@3900 51 if (p1->addr() != p2->addr()) return false;
zgu@3900 52 if ((p1->flags() & MemPointerRecord::tag_masks) !=
zgu@3900 53 (p2->flags() & MemPointerRecord::tag_masks)) {
zgu@3900 54 return false;
zgu@3900 55 }
zgu@3900 56 // we do see multiple commit/uncommit on the same memory, it is ok
zgu@3900 57 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
zgu@3900 58 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
zgu@3900 59 }
zgu@3900 60
zgu@3900 61 virtual bool insert(MemPointer* ptr) {
zgu@3900 62 if (_pos > 0) {
zgu@3900 63 MemPointer* p1 = (MemPointer*)ptr;
zgu@3900 64 MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
zgu@3900 65 assert(!is_dup_pointer(p1, p2),
zgu@3900 66 "dup pointer");
zgu@3900 67 }
zgu@3900 68 if (_pos < _array->length() -1) {
zgu@3900 69 MemPointer* p1 = (MemPointer*)ptr;
zgu@3900 70 MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
zgu@3900 71 assert(!is_dup_pointer(p1, p2),
zgu@3900 72 "dup pointer");
zgu@3900 73 }
zgu@3900 74 return _array->insert_at(ptr, _pos);
zgu@3900 75 }
zgu@3900 76
zgu@3900 77 virtual bool insert_after(MemPointer* ptr) {
zgu@3900 78 if (_pos > 0) {
zgu@3900 79 MemPointer* p1 = (MemPointer*)ptr;
zgu@3900 80 MemPointer* p2 = (MemPointer*)_array->at(_pos - 1);
zgu@3900 81 assert(!is_dup_pointer(p1, p2),
zgu@3900 82 "dup pointer");
zgu@3900 83 }
zgu@3900 84 if (_pos < _array->length() - 1) {
zgu@3900 85 MemPointer* p1 = (MemPointer*)ptr;
zgu@3900 86 MemPointer* p2 = (MemPointer*)_array->at(_pos + 1);
zgu@3900 87
zgu@3900 88 assert(!is_dup_pointer(p1, p2),
zgu@3900 89 "dup pointer");
zgu@3900 90 }
zgu@3900 91 if (_array->insert_at(ptr, _pos + 1)) {
zgu@3900 92 _pos ++;
zgu@3900 93 return true;
zgu@3900 94 }
zgu@3900 95 return false;
zgu@3900 96 }
zgu@3900 97 #endif
zgu@3900 98
zgu@3900 99 virtual MemPointer* locate(address addr) {
zgu@3900 100 MemPointer* cur = current();
zgu@3900 101 while (cur != NULL && cur->addr() < addr) {
zgu@3900 102 cur = next();
zgu@3900 103 }
zgu@3900 104 return cur;
zgu@3900 105 }
zgu@3900 106 };
zgu@3900 107
zgu@3900 108 class VMMemPointerIterator : public MemPointerIterator {
zgu@3900 109 public:
zgu@3900 110 VMMemPointerIterator(MemPointerArray* arr):
zgu@3900 111 MemPointerIterator(arr) {
zgu@3900 112 }
zgu@3900 113
zgu@3900 114 // locate an exiting record that contains specified address, or
zgu@3900 115 // the record, where the record with specified address, should
zgu@3900 116 // be inserted
zgu@3900 117 virtual MemPointer* locate(address addr) {
zgu@3900 118 VMMemRegion* cur = (VMMemRegion*)current();
zgu@3900 119 VMMemRegion* next_p;
zgu@3900 120
zgu@3900 121 while (cur != NULL) {
zgu@3900 122 if (cur->base() > addr) {
zgu@3900 123 return cur;
zgu@3900 124 } else {
zgu@3900 125 // find nearest existing range that has base address <= addr
zgu@3900 126 next_p = (VMMemRegion*)peek_next();
zgu@3900 127 if (next_p != NULL && next_p->base() <= addr) {
zgu@3900 128 cur = (VMMemRegion*)next();
zgu@3900 129 continue;
zgu@3900 130 }
zgu@3900 131 }
zgu@3900 132
zgu@3900 133 if (cur->is_reserve_record() &&
zgu@3900 134 cur->base() <= addr &&
zgu@3900 135 (cur->base() + cur->size() > addr)) {
zgu@3900 136 return cur;
zgu@3900 137 } else if (cur->is_commit_record() &&
zgu@3900 138 cur->base() <= addr &&
zgu@3900 139 (cur->base() + cur->committed_size() > addr)) {
zgu@3900 140 return cur;
zgu@3900 141 }
zgu@3900 142 cur = (VMMemRegion*)next();
zgu@3900 143 }
zgu@3900 144 return NULL;
zgu@3900 145 }
zgu@3900 146
zgu@3900 147 #ifdef ASSERT
zgu@3900 148 virtual bool is_dup_pointer(const MemPointer* ptr1,
zgu@3900 149 const MemPointer* ptr2) const {
zgu@3900 150 VMMemRegion* p1 = (VMMemRegion*)ptr1;
zgu@3900 151 VMMemRegion* p2 = (VMMemRegion*)ptr2;
zgu@3900 152
zgu@3900 153 if (p1->addr() != p2->addr()) return false;
zgu@3900 154 if ((p1->flags() & MemPointerRecord::tag_masks) !=
zgu@3900 155 (p2->flags() & MemPointerRecord::tag_masks)) {
zgu@3900 156 return false;
zgu@3900 157 }
zgu@3900 158 // we do see multiple commit/uncommit on the same memory, it is ok
zgu@3900 159 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc ||
zgu@3900 160 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release;
zgu@3900 161 }
zgu@3900 162 #endif
zgu@3900 163 };
zgu@3900 164
zgu@3900 165 class StagingWalker : public MemPointerArrayIterator {
zgu@3900 166 private:
zgu@3900 167 MemPointerArrayIteratorImpl _itr;
zgu@3900 168 bool _is_vm_record;
zgu@3900 169 bool _end_of_array;
zgu@3900 170 VMMemRegionEx _vm_record;
zgu@3900 171 MemPointerRecordEx _malloc_record;
zgu@3900 172
zgu@3900 173 public:
zgu@3900 174 StagingWalker(MemPointerArray* arr): _itr(arr) {
zgu@3900 175 _end_of_array = false;
zgu@3900 176 next();
zgu@3900 177 }
zgu@3900 178
zgu@3900 179 // return the pointer at current position
zgu@3900 180 MemPointer* current() const {
zgu@3900 181 if (_end_of_array) {
zgu@3900 182 return NULL;
zgu@3900 183 }
zgu@3900 184 if (is_vm_record()) {
zgu@3900 185 return (MemPointer*)&_vm_record;
zgu@3900 186 } else {
zgu@3900 187 return (MemPointer*)&_malloc_record;
zgu@3900 188 }
zgu@3900 189 }
zgu@3900 190
zgu@3900 191 // return the next pointer and advance current position
zgu@3900 192 MemPointer* next();
zgu@3900 193
zgu@3900 194 // type of 'current' record
zgu@3900 195 bool is_vm_record() const {
zgu@3900 196 return _is_vm_record;
zgu@3900 197 }
zgu@3900 198
zgu@3900 199 // return the next poinger without advancing current position
zgu@3900 200 MemPointer* peek_next() const {
zgu@3900 201 assert(false, "not supported");
zgu@3900 202 return NULL;
zgu@3900 203 }
zgu@3900 204
zgu@3900 205 MemPointer* peek_prev() const {
zgu@3900 206 assert(false, "not supported");
zgu@3900 207 return NULL;
zgu@3900 208 }
zgu@3900 209 // remove the pointer at current position
zgu@3900 210 void remove() {
zgu@3900 211 assert(false, "not supported");
zgu@3900 212 }
zgu@3900 213
zgu@3900 214 // insert the pointer at current position
zgu@3900 215 bool insert(MemPointer* ptr) {
zgu@3900 216 assert(false, "not supported");
zgu@3900 217 return false;
zgu@3900 218 }
zgu@3900 219
zgu@3900 220 bool insert_after(MemPointer* ptr) {
zgu@3900 221 assert(false, "not supported");
zgu@3900 222 return false;
zgu@3900 223 }
zgu@3900 224
zgu@3900 225 private:
zgu@3900 226 // consolidate all records referring to this vm region
zgu@3900 227 bool consolidate_vm_records(VMMemRegionEx* vm_rec);
zgu@3900 228 };
zgu@3900 229
zgu@3900 230 class MemBaseline;
zgu@3900 231
zgu@3900 232 class MemSnapshot : public CHeapObj<mtNMT> {
zgu@3900 233 private:
zgu@3900 234 // the following two arrays contain records of all known lived memory blocks
zgu@3900 235 // live malloc-ed memory pointers
zgu@3900 236 MemPointerArray* _alloc_ptrs;
zgu@3900 237 // live virtual memory pointers
zgu@3900 238 MemPointerArray* _vm_ptrs;
zgu@3900 239
zgu@3900 240 // stagging a generation's data, before
zgu@3900 241 // it can be prompted to snapshot
zgu@3900 242 MemPointerArray* _staging_area;
zgu@3900 243
zgu@3900 244 // the lock to protect this snapshot
zgu@3900 245 Monitor* _lock;
zgu@3900 246
zgu@3900 247 NOT_PRODUCT(size_t _untracked_count;)
zgu@3900 248 friend class MemBaseline;
zgu@3900 249
zgu@3900 250 public:
zgu@3900 251 MemSnapshot();
zgu@3900 252 virtual ~MemSnapshot();
zgu@3900 253
zgu@3900 254 // if we are running out of native memory
zgu@3900 255 bool out_of_memory() const {
zgu@3900 256 return (_alloc_ptrs == NULL || _staging_area == NULL ||
zgu@3900 257 _vm_ptrs == NULL || _lock == NULL ||
zgu@3900 258 _alloc_ptrs->out_of_memory() ||
zgu@3900 259 _staging_area->out_of_memory() ||
zgu@3900 260 _vm_ptrs->out_of_memory());
zgu@3900 261 }
zgu@3900 262
zgu@3900 263 // merge a per-thread memory recorder into staging area
zgu@3900 264 bool merge(MemRecorder* rec);
zgu@3900 265 // promote staged data to snapshot
zgu@3900 266 void promote();
zgu@3900 267
zgu@3900 268
zgu@3900 269 void wait(long timeout) {
zgu@3900 270 assert(_lock != NULL, "Just check");
zgu@3900 271 MonitorLockerEx locker(_lock);
zgu@3900 272 locker.wait(true, timeout);
zgu@3900 273 }
zgu@3900 274
zgu@3900 275 NOT_PRODUCT(void print_snapshot_stats(outputStream* st);)
zgu@3900 276 NOT_PRODUCT(void check_staging_data();)
zgu@3900 277 NOT_PRODUCT(void check_malloc_pointers();)
zgu@3900 278 NOT_PRODUCT(bool has_allocation_record(address addr);)
zgu@3900 279
zgu@3900 280 private:
zgu@3900 281 // copy pointer data from src to dest
zgu@3900 282 void copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src);
zgu@3900 283 };
zgu@3900 284
zgu@3900 285
zgu@3900 286 #endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP

mercurial