1 /* 2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP 26 #define SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP 27 28 #include "memory/allocation.hpp" 29 #include "runtime/mutex.hpp" 30 #include "runtime/mutexLocker.hpp" 31 #include "services/memBaseline.hpp" 32 #include "services/memPtrArray.hpp" 33 34 35 // Snapshot pointer array iterator 36 37 // The pointer array contains malloc-ed pointers 38 class MemPointerIterator : public MemPointerArrayIteratorImpl { 39 public: 40 MemPointerIterator(MemPointerArray* arr): 41 MemPointerArrayIteratorImpl(arr) { 42 assert(arr != NULL, "null array"); 43 } 44 45 #ifdef ASSERT 46 virtual bool is_dup_pointer(const MemPointer* ptr1, 47 const MemPointer* ptr2) const { 48 MemPointerRecord* p1 = (MemPointerRecord*)ptr1; 49 MemPointerRecord* p2 = (MemPointerRecord*)ptr2; 50 51 if (p1->addr() != p2->addr()) return false; 52 if ((p1->flags() & MemPointerRecord::tag_masks) != 53 (p2->flags() & MemPointerRecord::tag_masks)) { 54 return false; 55 } 56 // we do see multiple commit/uncommit on the same memory, it is ok 57 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || 58 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; 59 } 60 61 virtual bool insert(MemPointer* ptr) { 62 if (_pos > 0) { 63 MemPointer* p1 = (MemPointer*)ptr; 64 MemPointer* p2 = (MemPointer*)_array->at(_pos - 1); 65 assert(!is_dup_pointer(p1, p2), 66 err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); 67 } 68 if (_pos < _array->length() -1) { 69 MemPointer* p1 = (MemPointer*)ptr; 70 MemPointer* p2 = (MemPointer*)_array->at(_pos + 1); 71 assert(!is_dup_pointer(p1, p2), 72 err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); 73 } 74 return _array->insert_at(ptr, _pos); 75 } 76 77 virtual bool insert_after(MemPointer* ptr) { 78 if (_pos > 0) { 79 MemPointer* p1 = (MemPointer*)ptr; 80 MemPointer* p2 = (MemPointer*)_array->at(_pos - 1); 81 assert(!is_dup_pointer(p1, p2), 82 err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); 83 } 84 if (_pos < _array->length() - 1) { 85 MemPointer* p1 = (MemPointer*)ptr; 86 MemPointer* p2 = (MemPointer*)_array->at(_pos + 1); 87 88 assert(!is_dup_pointer(p1, p2), 89 err_msg("duplicated pointer, flag = [%x]", (unsigned int)((MemPointerRecord*)p1)->flags())); 90 } 91 if (_array->insert_at(ptr, _pos + 1)) { 92 _pos ++; 93 return true; 94 } 95 return false; 96 } 97 #endif 98 99 virtual MemPointer* locate(address addr) { 100 MemPointer* cur = current(); 101 while (cur != NULL && cur->addr() < addr) { 102 cur = next(); 103 } 104 return cur; 105 } 106 }; 107 108 class VMMemPointerIterator : public MemPointerIterator { 109 public: 110 VMMemPointerIterator(MemPointerArray* arr): 111 MemPointerIterator(arr) { 112 } 113 114 // locate an existing reserved memory region that contains specified address, 115 // or the reserved region just above this address, where the incoming 116 // reserved region should be inserted. 117 virtual MemPointer* locate(address addr) { 118 reset(); 119 VMMemRegion* reg = (VMMemRegion*)current(); 120 while (reg != NULL) { 121 if (reg->is_reserved_region()) { 122 if (reg->contains_address(addr) || addr < reg->base()) { 123 return reg; 124 } 125 } 126 reg = (VMMemRegion*)next(); 127 } 128 return NULL; 129 } 130 131 // following methods update virtual memory in the context 132 // of 'current' position, which is properly positioned by 133 // callers via locate method. 134 bool add_reserved_region(MemPointerRecord* rec); 135 bool add_committed_region(MemPointerRecord* rec); 136 bool remove_uncommitted_region(MemPointerRecord* rec); 137 bool remove_released_region(MemPointerRecord* rec); 138 139 // split a reserved region to create a new memory region with specified base and size 140 bool split_reserved_region(VMMemRegion* rgn, address new_rgn_addr, size_t new_rgn_size); 141 private: 142 bool insert_record(MemPointerRecord* rec); 143 bool insert_record_after(MemPointerRecord* rec); 144 145 bool insert_reserved_region(MemPointerRecord* rec); 146 147 // reset current position 148 inline void reset() { _pos = 0; } 149 #ifdef ASSERT 150 virtual bool is_dup_pointer(const MemPointer* ptr1, 151 const MemPointer* ptr2) const { 152 VMMemRegion* p1 = (VMMemRegion*)ptr1; 153 VMMemRegion* p2 = (VMMemRegion*)ptr2; 154 155 if (p1->addr() != p2->addr()) return false; 156 if ((p1->flags() & MemPointerRecord::tag_masks) != 157 (p2->flags() & MemPointerRecord::tag_masks)) { 158 return false; 159 } 160 // we do see multiple commit/uncommit on the same memory, it is ok 161 return (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_alloc || 162 (p1->flags() & MemPointerRecord::tag_masks) == MemPointerRecord::tag_release; 163 } 164 #endif 165 }; 166 167 class MallocRecordIterator : public MemPointerArrayIterator { 168 protected: 169 MemPointerArrayIteratorImpl _itr; 170 171 public: 172 MallocRecordIterator(MemPointerArray* arr) : _itr(arr) { 173 } 174 175 virtual MemPointer* current() const { 176 MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); 177 assert(cur == NULL || !cur->is_vm_pointer(), "seek error"); 178 MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); 179 if (next == NULL || next->addr() != cur->addr()) { 180 return cur; 181 } else { 182 assert(!cur->is_vm_pointer(), "Sanity check"); 183 assert(cur->is_allocation_record() && next->is_deallocation_record(), 184 "sorting order"); 185 assert(cur->seq() != next->seq(), "Sanity check"); 186 return cur->seq() > next->seq() ? cur : next; 187 } 188 } 189 190 virtual MemPointer* next() { 191 MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); 192 assert(cur == NULL || !cur->is_vm_pointer(), "Sanity check"); 193 MemPointerRecord* next = (MemPointerRecord*)_itr.next(); 194 if (next == NULL) { 195 return NULL; 196 } 197 if (cur->addr() == next->addr()) { 198 next = (MemPointerRecord*)_itr.next(); 199 } 200 return current(); 201 } 202 203 MemPointer* peek_next() const { ShouldNotReachHere(); return NULL; } 204 MemPointer* peek_prev() const { ShouldNotReachHere(); return NULL; } 205 void remove() { ShouldNotReachHere(); } 206 bool insert(MemPointer* ptr) { ShouldNotReachHere(); return false; } 207 bool insert_after(MemPointer* ptr) { ShouldNotReachHere(); return false; } 208 }; 209 210 // collapse duplicated records. Eliminating duplicated records here, is much 211 // cheaper than during promotion phase. However, it does have limitation - it 212 // can only eliminate duplicated records within the generation, there are 213 // still chances seeing duplicated records during promotion. 214 // We want to use the record with higher sequence number, because it has 215 // more accurate callsite pc. 216 class VMRecordIterator : public MallocRecordIterator { 217 public: 218 VMRecordIterator(MemPointerArray* arr) : MallocRecordIterator(arr) { 219 MemPointerRecord* cur = (MemPointerRecord*)_itr.current(); 220 MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); 221 while (next != NULL) { 222 assert(cur != NULL, "Sanity check"); 223 assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(), 224 "pre-sort order"); 225 226 if (is_duplicated_record(cur, next)) { 227 _itr.next(); 228 next = (MemPointerRecord*)_itr.peek_next(); 229 } else { 230 break; 231 } 232 } 233 } 234 235 virtual MemPointer* current() const { 236 return _itr.current(); 237 } 238 239 // get next record, but skip the duplicated records 240 virtual MemPointer* next() { 241 MemPointerRecord* cur = (MemPointerRecord*)_itr.next(); 242 MemPointerRecord* next = (MemPointerRecord*)_itr.peek_next(); 243 while (next != NULL) { 244 assert(cur != NULL, "Sanity check"); 245 assert(((SeqMemPointerRecord*)next)->seq() > ((SeqMemPointerRecord*)cur)->seq(), 246 "pre-sort order"); 247 248 if (is_duplicated_record(cur, next)) { 249 _itr.next(); 250 cur = next; 251 next = (MemPointerRecord*)_itr.peek_next(); 252 } else { 253 break; 254 } 255 } 256 return cur; 257 } 258 259 private: 260 bool is_duplicated_record(MemPointerRecord* p1, MemPointerRecord* p2) const { 261 bool ret = (p1->addr() == p2->addr() && p1->size() == p2->size() && p1->flags() == p2->flags()); 262 assert(!(ret && FLAGS_TO_MEMORY_TYPE(p1->flags()) == mtThreadStack), "dup on stack record"); 263 return ret; 264 } 265 }; 266 267 class StagingArea : public _ValueObj { 268 private: 269 MemPointerArray* _malloc_data; 270 MemPointerArray* _vm_data; 271 272 public: 273 StagingArea() : _malloc_data(NULL), _vm_data(NULL) { 274 init(); 275 } 276 277 ~StagingArea() { 278 if (_malloc_data != NULL) delete _malloc_data; 279 if (_vm_data != NULL) delete _vm_data; 280 } 281 282 MallocRecordIterator malloc_record_walker() { 283 return MallocRecordIterator(malloc_data()); 284 } 285 286 VMRecordIterator virtual_memory_record_walker(); 287 288 bool init(); 289 void clear() { 290 assert(_malloc_data != NULL && _vm_data != NULL, "Just check"); 291 _malloc_data->shrink(); 292 _malloc_data->clear(); 293 _vm_data->clear(); 294 } 295 296 inline MemPointerArray* malloc_data() { return _malloc_data; } 297 inline MemPointerArray* vm_data() { return _vm_data; } 298 }; 299 300 class MemBaseline; 301 class MemSnapshot : public CHeapObj<mtNMT> { 302 private: 303 // the following two arrays contain records of all known lived memory blocks 304 // live malloc-ed memory pointers 305 MemPointerArray* _alloc_ptrs; 306 // live virtual memory pointers 307 MemPointerArray* _vm_ptrs; 308 309 StagingArea _staging_area; 310 311 // the lock to protect this snapshot 312 Monitor* _lock; 313 314 NOT_PRODUCT(size_t _untracked_count;) 315 friend class MemBaseline; 316 317 public: 318 MemSnapshot(); 319 virtual ~MemSnapshot(); 320 321 // if we are running out of native memory 322 bool out_of_memory() { 323 return (_alloc_ptrs == NULL || 324 _staging_area.malloc_data() == NULL || 325 _staging_area.vm_data() == NULL || 326 _vm_ptrs == NULL || _lock == NULL || 327 _alloc_ptrs->out_of_memory() || 328 _vm_ptrs->out_of_memory()); 329 } 330 331 // merge a per-thread memory recorder into staging area 332 bool merge(MemRecorder* rec); 333 // promote staged data to snapshot 334 bool promote(); 335 336 337 void wait(long timeout) { 338 assert(_lock != NULL, "Just check"); 339 MonitorLockerEx locker(_lock); 340 locker.wait(true, timeout); 341 } 342 343 NOT_PRODUCT(void print_snapshot_stats(outputStream* st);) 344 NOT_PRODUCT(void check_staging_data();) 345 NOT_PRODUCT(void check_malloc_pointers();) 346 NOT_PRODUCT(bool has_allocation_record(address addr);) 347 // dump all virtual memory pointers in snapshot 348 DEBUG_ONLY( void dump_all_vm_pointers();) 349 350 private: 351 // copy pointer data from src to dest 352 void copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src); 353 354 bool promote_malloc_records(MemPointerArrayIterator* itr); 355 bool promote_virtual_memory_records(MemPointerArrayIterator* itr); 356 }; 357 358 #endif // SHARE_VM_SERVICES_MEM_SNAPSHOT_HPP