comparison src/share/vm/services/memTracker.hpp @ 10986:1f4355cee9a2

8013651: NMT: reserve/release sequence id's in incorrect order due to race Summary: Fixed NMT race condition for realloc, uncommit and release Reviewed-by: coleenp, ccheung
author zgu
date Tue, 18 Jun 2013 08:44:08 -0400
parents 35f8765422b9
children 5f7a4367c787
comparison
equal deleted inserted replaced
10984:cd2118b62475 10986:1f4355cee9a2
1 /* 1 /*
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
52 NMT_error_reporting, // shutdown by vmError::report_and_die() 52 NMT_error_reporting, // shutdown by vmError::report_and_die()
53 NMT_out_of_generation, // running out of generation queue 53 NMT_out_of_generation, // running out of generation queue
54 NMT_sequence_overflow // overflow the sequence number 54 NMT_sequence_overflow // overflow the sequence number
55 }; 55 };
56 56
57 class Tracker {
58 public:
59 void discard() { }
60
61 void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL) { }
62 void record(address old_addr, address new_addr, size_t size,
63 MEMFLAGS flags, address pc = NULL) { }
64 };
65
66 private:
67 static Tracker _tkr;
68
57 69
58 public: 70 public:
59 static inline void init_tracking_options(const char* option_line) { } 71 static inline void init_tracking_options(const char* option_line) { }
60 static inline bool is_on() { return false; } 72 static inline bool is_on() { return false; }
61 static const char* reason() { return "Native memory tracking is not implemented"; } 73 static const char* reason() { return "Native memory tracking is not implemented"; }
66 static inline void start() { } 78 static inline void start() { }
67 79
68 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, 80 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
69 address pc = 0, Thread* thread = NULL) { } 81 address pc = 0, Thread* thread = NULL) { }
70 static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { } 82 static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { }
71 static inline void record_realloc(address old_addr, address new_addr, size_t size,
72 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
73 static inline void record_arena_size(address addr, size_t size) { } 83 static inline void record_arena_size(address addr, size_t size) { }
74 static inline void record_virtual_memory_reserve(address addr, size_t size, 84 static inline void record_virtual_memory_reserve(address addr, size_t size,
75 address pc = 0, Thread* thread = NULL) { } 85 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
86 static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size,
87 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
76 static inline void record_virtual_memory_commit(address addr, size_t size, 88 static inline void record_virtual_memory_commit(address addr, size_t size,
77 address pc = 0, Thread* thread = NULL) { } 89 address pc = 0, Thread* thread = NULL) { }
78 static inline void record_virtual_memory_uncommit(address addr, size_t size,
79 Thread* thread = NULL) { }
80 static inline void record_virtual_memory_release(address addr, size_t size,
81 Thread* thread = NULL) { }
82 static inline void record_virtual_memory_type(address base, MEMFLAGS flags, 90 static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
83 Thread* thread = NULL) { } 91 Thread* thread = NULL) { }
92 static inline Tracker get_realloc_tracker() { return _tkr; }
93 static inline Tracker get_virtual_memory_uncommit_tracker() { return _tkr; }
94 static inline Tracker get_virtual_memory_release_tracker() { return _tkr; }
84 static inline bool baseline() { return false; } 95 static inline bool baseline() { return false; }
85 static inline bool has_baseline() { return false; } 96 static inline bool has_baseline() { return false; }
86 97
87 static inline void set_autoShutdown(bool value) { } 98 static inline void set_autoShutdown(bool value) { }
88 static void shutdown(ShutdownReason reason) { } 99 static void shutdown(ShutdownReason reason) { }
161 NMT_started, // NMT fully started 172 NMT_started, // NMT fully started
162 NMT_shutdown_pending, // shutdown pending 173 NMT_shutdown_pending, // shutdown pending
163 NMT_final_shutdown, // in final phase of shutdown 174 NMT_final_shutdown, // in final phase of shutdown
164 NMT_shutdown // shutdown 175 NMT_shutdown // shutdown
165 }; 176 };
177
178 public:
179 class Tracker : public StackObj {
180 friend class MemTracker;
181 public:
182 enum MemoryOperation {
183 NoOp, // no op
184 Malloc, // malloc
185 Realloc, // realloc
186 Free, // free
187 Reserve, // virtual memory reserve
188 Commit, // virtual memory commit
189 ReserveAndCommit, // virtual memory reserve and commit
190 StackAlloc = ReserveAndCommit, // allocate thread stack
191 Type, // assign virtual memory type
192 Uncommit, // virtual memory uncommit
193 Release, // virtual memory release
194 ArenaSize, // set arena size
195 StackRelease // release thread stack
196 };
197
198
199 protected:
200 Tracker(MemoryOperation op, Thread* thr = NULL);
201
202 public:
203 void discard();
204
205 void record(address addr, size_t size = 0, MEMFLAGS flags = mtNone, address pc = NULL);
206 void record(address old_addr, address new_addr, size_t size,
207 MEMFLAGS flags, address pc = NULL);
208
209 private:
210 bool _need_thread_critical_lock;
211 JavaThread* _java_thread;
212 MemoryOperation _op; // memory operation
213 jint _seq; // reserved sequence number
214 };
215
166 216
167 public: 217 public:
168 // native memory tracking level 218 // native memory tracking level
169 enum NMTLevel { 219 enum NMTLevel {
170 NMT_off, // native memory tracking is off 220 NMT_off, // native memory tracking is off
274 static void start(); 324 static void start();
275 325
276 // record a 'malloc' call 326 // record a 'malloc' call
277 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, 327 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
278 address pc = 0, Thread* thread = NULL) { 328 address pc = 0, Thread* thread = NULL) {
279 if (is_on() && NMT_CAN_TRACK(flags)) { 329 Tracker tkr(Tracker::Malloc, thread);
280 assert(size > 0, "Sanity check"); 330 tkr.record(addr, size, flags, pc);
281 create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread);
282 }
283 } 331 }
284 // record a 'free' call 332 // record a 'free' call
285 static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { 333 static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) {
286 if (is_on() && NMT_CAN_TRACK(flags)) { 334 Tracker tkr(Tracker::Free, thread);
287 create_memory_record(addr, MemPointerRecord::free_tag(), 0, 0, thread); 335 tkr.record(addr, 0, flags, DEBUG_CALLER_PC);
288 } 336 }
289 } 337
290 // record a 'realloc' call
291 static inline void record_realloc(address old_addr, address new_addr, size_t size,
292 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) {
293 if (is_on() && NMT_CAN_TRACK(flags)) {
294 assert(size > 0, "Sanity check");
295 record_free(old_addr, flags, thread);
296 record_malloc(new_addr, size, flags, pc, thread);
297 }
298 }
299
300 // record arena memory size
301 static inline void record_arena_size(address addr, size_t size) { 338 static inline void record_arena_size(address addr, size_t size) {
302 // we add a positive offset to arena address, so we can have arena memory record 339 Tracker tkr(Tracker::ArenaSize);
303 // sorted after arena record 340 tkr.record(addr, size);
304 if (is_on() && !UseMallocOnly) {
305 assert(addr != NULL, "Sanity check");
306 create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size,
307 DEBUG_CALLER_PC, NULL);
308 }
309 } 341 }
310 342
311 // record a virtual memory 'reserve' call 343 // record a virtual memory 'reserve' call
312 static inline void record_virtual_memory_reserve(address addr, size_t size, 344 static inline void record_virtual_memory_reserve(address addr, size_t size,
313 address pc = 0, Thread* thread = NULL) { 345 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) {
314 if (is_on()) { 346 assert(size > 0, "Sanity check");
315 assert(size > 0, "Sanity check"); 347 Tracker tkr(Tracker::Reserve, thread);
316 create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(), 348 tkr.record(addr, size, flags, pc);
317 size, pc, thread);
318 }
319 } 349 }
320 350
321 static inline void record_thread_stack(address addr, size_t size, Thread* thr, 351 static inline void record_thread_stack(address addr, size_t size, Thread* thr,
322 address pc = 0) { 352 address pc = 0) {
323 if (is_on()) { 353 Tracker tkr(Tracker::StackAlloc, thr);
324 assert(size > 0 && thr != NULL, "Sanity check"); 354 tkr.record(addr, size, mtThreadStack, pc);
325 create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag() | mtThreadStack,
326 size, pc, thr);
327 create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag() | mtThreadStack,
328 size, pc, thr);
329 }
330 } 355 }
331 356
332 static inline void release_thread_stack(address addr, size_t size, Thread* thr) { 357 static inline void release_thread_stack(address addr, size_t size, Thread* thr) {
333 if (is_on()) { 358 Tracker tkr(Tracker::StackRelease, thr);
334 assert(size > 0 && thr != NULL, "Sanity check"); 359 tkr.record(addr, size, mtThreadStack, DEBUG_CALLER_PC);
335 assert(!thr->is_Java_thread(), "too early");
336 create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag() | mtThreadStack,
337 size, DEBUG_CALLER_PC, thr);
338 create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag() | mtThreadStack,
339 size, DEBUG_CALLER_PC, thr);
340 }
341 } 360 }
342 361
343 // record a virtual memory 'commit' call 362 // record a virtual memory 'commit' call
344 static inline void record_virtual_memory_commit(address addr, size_t size, 363 static inline void record_virtual_memory_commit(address addr, size_t size,
345 address pc, Thread* thread = NULL) { 364 address pc, Thread* thread = NULL) {
346 if (is_on()) { 365 Tracker tkr(Tracker::Commit, thread);
347 assert(size > 0, "Sanity check"); 366 tkr.record(addr, size, mtNone, pc);
348 create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(), 367 }
349 size, pc, thread); 368
350 } 369 static inline void record_virtual_memory_reserve_and_commit(address addr, size_t size,
351 } 370 MEMFLAGS flags, address pc, Thread* thread = NULL) {
352 371 Tracker tkr(Tracker::ReserveAndCommit, thread);
353 // record a virtual memory 'uncommit' call 372 tkr.record(addr, size, flags, pc);
354 static inline void record_virtual_memory_uncommit(address addr, size_t size, 373 }
355 Thread* thread = NULL) { 374
356 if (is_on()) {
357 assert(size > 0, "Sanity check");
358 create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(),
359 size, DEBUG_CALLER_PC, thread);
360 }
361 }
362
363 // record a virtual memory 'release' call
364 static inline void record_virtual_memory_release(address addr, size_t size,
365 Thread* thread = NULL) {
366 if (is_on()) {
367 assert(size > 0, "Sanity check");
368 create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(),
369 size, DEBUG_CALLER_PC, thread);
370 }
371 }
372 375
373 // record memory type on virtual memory base address 376 // record memory type on virtual memory base address
374 static inline void record_virtual_memory_type(address base, MEMFLAGS flags, 377 static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
375 Thread* thread = NULL) { 378 Thread* thread = NULL) {
376 if (is_on()) { 379 Tracker tkr(Tracker::Type);
377 assert(base > 0, "wrong base address"); 380 tkr.record(base, 0, flags);
378 assert((flags & (~mt_masks)) == 0, "memory type only"); 381 }
379 create_memory_record(base, (flags | MemPointerRecord::virtual_memory_type_tag()), 382
380 0, DEBUG_CALLER_PC, thread); 383 // Get memory trackers for memory operations that can result race conditions.
381 } 384 // The memory tracker has to be obtained before realloc, virtual memory uncommit
385 // and virtual memory release, and call tracker.record() method if operation
386 // succeeded, or tracker.discard() to abort the tracking.
387 static inline Tracker get_realloc_tracker() {
388 return Tracker(Tracker::Realloc);
389 }
390
391 static inline Tracker get_virtual_memory_uncommit_tracker() {
392 return Tracker(Tracker::Uncommit);
393 }
394
395 static inline Tracker get_virtual_memory_release_tracker() {
396 return Tracker(Tracker::Release);
382 } 397 }
383 398
384 399
385 // create memory baseline of current memory snapshot 400 // create memory baseline of current memory snapshot
386 static bool baseline(); 401 static bool baseline();
441 // pending recorder queue. Recorders are queued to pending queue 456 // pending recorder queue. Recorders are queued to pending queue
442 // when they are overflowed or collected at nmt sync point. 457 // when they are overflowed or collected at nmt sync point.
443 static void enqueue_pending_recorder(MemRecorder* rec); 458 static void enqueue_pending_recorder(MemRecorder* rec);
444 static MemRecorder* get_pending_recorders(); 459 static MemRecorder* get_pending_recorders();
445 static void delete_all_pending_recorders(); 460 static void delete_all_pending_recorders();
461
462 // write a memory tracking record in recorder
463 static void write_tracking_record(address addr, MEMFLAGS type,
464 size_t size, jint seq, address pc, JavaThread* thread);
465
466 static bool is_single_threaded_bootstrap() {
467 return _state == NMT_bootstrapping_single_thread;
468 }
469
470 static void check_NMT_load(Thread* thr) {
471 assert(thr != NULL, "Sanity check");
472 if (_slowdown_calling_thread && thr != _worker_thread) {
473 os::yield_all();
474 }
475 }
476
477 static void inc_pending_op_count() {
478 Atomic::inc(&_pending_op_count);
479 }
480
481 static void dec_pending_op_count() {
482 Atomic::dec(&_pending_op_count);
483 assert(_pending_op_count >= 0, "Sanity check");
484 }
485
446 486
447 private: 487 private:
448 // retrieve a pooled memory record or create new one if there is not 488 // retrieve a pooled memory record or create new one if there is not
449 // one available 489 // one available
450 static MemRecorder* get_new_or_pooled_instance(); 490 static MemRecorder* get_new_or_pooled_instance();
520 static volatile bool _worker_thread_idle; 560 static volatile bool _worker_thread_idle;
521 561
522 // if NMT should slow down calling thread to allow 562 // if NMT should slow down calling thread to allow
523 // worker thread to catch up 563 // worker thread to catch up
524 static volatile bool _slowdown_calling_thread; 564 static volatile bool _slowdown_calling_thread;
565
566 // pending memory op count.
567 // Certain memory ops need to pre-reserve sequence number
568 // before memory operation can happen to avoid race condition.
569 // See MemTracker::Tracker for detail
570 static volatile jint _pending_op_count;
525 }; 571 };
526 572
527 #endif // !INCLUDE_NMT 573 #endif // !INCLUDE_NMT
528 574
529 #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP 575 #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP