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_TRACKER_HPP 26 #define SHARE_VM_SERVICES_MEM_TRACKER_HPP 27 28 #include "utilities/macros.hpp" 29 30 #if !INCLUDE_NMT 31 32 #include "utilities/ostream.hpp" 33 34 class BaselineOutputer : public StackObj { 35 36 }; 37 38 class BaselineTTYOutputer : public BaselineOutputer { 39 public: 40 BaselineTTYOutputer(outputStream* st) { } 41 }; 42 43 class MemTracker : AllStatic { 44 public: 45 enum ShutdownReason { 46 NMT_shutdown_none, // no shutdown requested 47 NMT_shutdown_user, // user requested shutdown 48 NMT_normal, // normal shutdown, process exit 49 NMT_out_of_memory, // shutdown due to out of memory 50 NMT_initialization, // shutdown due to initialization failure 51 NMT_use_malloc_only, // can not combine NMT with UseMallocOnly flag 52 NMT_error_reporting, // shutdown by vmError::report_and_die() 53 NMT_out_of_generation, // running out of generation queue 54 NMT_sequence_overflow // overflow the sequence number 55 }; 56 57 58 public: 59 static inline void init_tracking_options(const char* option_line) { } 60 static inline bool is_on() { return false; } 61 static const char* reason() { return "Native memory tracking is not implemented"; } 62 static inline bool can_walk_stack() { return false; } 63 64 static inline void bootstrap_single_thread() { } 65 static inline void bootstrap_multi_thread() { } 66 static inline void start() { } 67 68 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, 69 address pc = 0, Thread* thread = NULL) { } 70 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) { } 74 static inline void record_virtual_memory_reserve(address addr, size_t size, 75 address pc = 0, Thread* thread = NULL) { } 76 static inline void record_virtual_memory_commit(address addr, size_t size, 77 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, 83 Thread* thread = NULL) { } 84 static inline bool baseline() { return false; } 85 static inline bool has_baseline() { return false; } 86 87 static void shutdown(ShutdownReason reason) { } 88 static inline bool shutdown_in_progress() { } 89 static bool print_memory_usage(BaselineOutputer& out, size_t unit, 90 bool summary_only = true) { } 91 static bool compare_memory_usage(BaselineOutputer& out, size_t unit, 92 bool summary_only = true) { } 93 94 static inline void sync() { } 95 static inline void thread_exiting(JavaThread* thread) { } 96 97 }; 98 99 100 #else // !INCLUDE_NMT 101 102 #include "memory/allocation.hpp" 103 #include "runtime/globals.hpp" 104 #include "runtime/mutex.hpp" 105 #include "runtime/os.hpp" 106 #include "runtime/thread.hpp" 107 #include "services/memPtr.hpp" 108 #include "services/memRecorder.hpp" 109 #include "services/memSnapshot.hpp" 110 #include "services/memTrackWorker.hpp" 111 112 #ifdef SOLARIS 113 #include "thread_solaris.inline.hpp" 114 #endif 115 116 extern bool NMT_track_callsite; 117 118 #ifdef ASSERT 119 #define DEBUG_CALLER_PC (NMT_track_callsite ? os::get_caller_pc(2) : 0) 120 #else 121 #define DEBUG_CALLER_PC 0 122 #endif 123 124 // The thread closure walks threads to collect per-thread 125 // memory recorders at NMT sync point 126 class SyncThreadRecorderClosure : public ThreadClosure { 127 private: 128 int _thread_count; 129 130 public: 131 SyncThreadRecorderClosure() { 132 _thread_count =0; 133 } 134 135 void do_thread(Thread* thread); 136 int get_thread_count() const { 137 return _thread_count; 138 } 139 }; 140 141 class BaselineOutputer; 142 class MemSnapshot; 143 class MemTrackWorker; 144 class Thread; 145 /* 146 * MemTracker is the 'gate' class to native memory tracking runtime. 147 */ 148 class MemTracker : AllStatic { 149 friend class MemTrackWorker; 150 friend class MemSnapshot; 151 friend class SyncThreadRecorderClosure; 152 153 // NMT state 154 enum NMTStates { 155 NMT_uninited, // not yet initialized 156 NMT_bootstrapping_single_thread, // bootstrapping, VM is in single thread mode 157 NMT_bootstrapping_multi_thread, // bootstrapping, VM is about to enter multi-thread mode 158 NMT_started, // NMT fully started 159 NMT_shutdown_pending, // shutdown pending 160 NMT_final_shutdown, // in final phase of shutdown 161 NMT_shutdown // shutdown 162 }; 163 164 public: 165 // native memory tracking level 166 enum NMTLevel { 167 NMT_off, // native memory tracking is off 168 NMT_summary, // don't track callsite 169 NMT_detail // track callsite also 170 }; 171 172 enum ShutdownReason { 173 NMT_shutdown_none, // no shutdown requested 174 NMT_shutdown_user, // user requested shutdown 175 NMT_normal, // normal shutdown, process exit 176 NMT_out_of_memory, // shutdown due to out of memory 177 NMT_initialization, // shutdown due to initialization failure 178 NMT_use_malloc_only, // can not combine NMT with UseMallocOnly flag 179 NMT_error_reporting, // shutdown by vmError::report_and_die() 180 NMT_out_of_generation, // running out of generation queue 181 NMT_sequence_overflow // overflow the sequence number 182 }; 183 184 public: 185 // initialize NMT tracking level from command line options, called 186 // from VM command line parsing code 187 static void init_tracking_options(const char* option_line); 188 189 // if NMT is enabled to record memory activities 190 static inline bool is_on() { 191 return (_tracking_level >= NMT_summary && 192 _state >= NMT_bootstrapping_single_thread); 193 } 194 195 static inline enum NMTLevel tracking_level() { 196 return _tracking_level; 197 } 198 199 // user readable reason for shutting down NMT 200 static const char* reason() { 201 switch(_reason) { 202 case NMT_shutdown_none: 203 return "Native memory tracking is not enabled"; 204 case NMT_shutdown_user: 205 return "Native memory tracking has been shutdown by user"; 206 case NMT_normal: 207 return "Native memory tracking has been shutdown due to process exiting"; 208 case NMT_out_of_memory: 209 return "Native memory tracking has been shutdown due to out of native memory"; 210 case NMT_initialization: 211 return "Native memory tracking failed to initialize"; 212 case NMT_error_reporting: 213 return "Native memory tracking has been shutdown due to error reporting"; 214 case NMT_out_of_generation: 215 return "Native memory tracking has been shutdown due to running out of generation buffer"; 216 case NMT_sequence_overflow: 217 return "Native memory tracking has been shutdown due to overflow the sequence number"; 218 case NMT_use_malloc_only: 219 return "Native memory tracking is not supported when UseMallocOnly is on"; 220 default: 221 ShouldNotReachHere(); 222 return NULL; 223 } 224 } 225 226 // test if we can walk native stack 227 static bool can_walk_stack() { 228 // native stack is not walkable during bootstrapping on sparc 229 #if defined(SPARC) 230 return (_state == NMT_started); 231 #else 232 return (_state >= NMT_bootstrapping_single_thread && _state <= NMT_started); 233 #endif 234 } 235 236 // if native memory tracking tracks callsite 237 static inline bool track_callsite() { return _tracking_level == NMT_detail; } 238 239 // shutdown native memory tracking capability. Native memory tracking 240 // can be shutdown by VM when it encounters low memory scenarios. 241 // Memory tracker should gracefully shutdown itself, and preserve the 242 // latest memory statistics for post morten diagnosis. 243 static void shutdown(ShutdownReason reason); 244 245 // if there is shutdown requested 246 static inline bool shutdown_in_progress() { 247 return (_state >= NMT_shutdown_pending); 248 } 249 250 // bootstrap native memory tracking, so it can start to collect raw data 251 // before worker thread can start 252 253 // the first phase of bootstrapping, when VM still in single-threaded mode 254 static void bootstrap_single_thread(); 255 // the second phase of bootstrapping, VM is about or already in multi-threaded mode 256 static void bootstrap_multi_thread(); 257 258 259 // start() has to be called when VM still in single thread mode, but after 260 // command line option parsing is done. 261 static void start(); 262 263 // record a 'malloc' call 264 static inline void record_malloc(address addr, size_t size, MEMFLAGS flags, 265 address pc = 0, Thread* thread = NULL) { 266 if (is_on() && NMT_CAN_TRACK(flags)) { 267 assert(size > 0, "Sanity check"); 268 create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread); 269 } 270 } 271 // record a 'free' call 272 static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { 273 if (is_on() && NMT_CAN_TRACK(flags)) { 274 create_memory_record(addr, MemPointerRecord::free_tag(), 0, 0, thread); 275 } 276 } 277 // record a 'realloc' call 278 static inline void record_realloc(address old_addr, address new_addr, size_t size, 279 MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { 280 if (is_on() && NMT_CAN_TRACK(flags)) { 281 assert(size > 0, "Sanity check"); 282 record_free(old_addr, flags, thread); 283 record_malloc(new_addr, size, flags, pc, thread); 284 } 285 } 286 287 // record arena memory size 288 static inline void record_arena_size(address addr, size_t size) { 289 // we add a positive offset to arena address, so we can have arena memory record 290 // sorted after arena record 291 if (is_on() && !UseMallocOnly) { 292 assert(addr != NULL, "Sanity check"); 293 create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size, 294 DEBUG_CALLER_PC, NULL); 295 } 296 } 297 298 // record a virtual memory 'reserve' call 299 static inline void record_virtual_memory_reserve(address addr, size_t size, 300 address pc = 0, Thread* thread = NULL) { 301 if (is_on()) { 302 assert(size > 0, "Sanity check"); 303 create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(), 304 size, pc, thread); 305 } 306 } 307 308 static inline void record_thread_stack(address addr, size_t size, Thread* thr, 309 address pc = 0) { 310 if (is_on()) { 311 assert(size > 0 && thr != NULL, "Sanity check"); 312 create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag() | mtThreadStack, 313 size, pc, thr); 314 create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag() | mtThreadStack, 315 size, pc, thr); 316 } 317 } 318 319 static inline void release_thread_stack(address addr, size_t size, Thread* thr) { 320 if (is_on()) { 321 assert(size > 0 && thr != NULL, "Sanity check"); 322 assert(!thr->is_Java_thread(), "too early"); 323 create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag() | mtThreadStack, 324 size, DEBUG_CALLER_PC, thr); 325 create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag() | mtThreadStack, 326 size, DEBUG_CALLER_PC, thr); 327 } 328 } 329 330 // record a virtual memory 'commit' call 331 static inline void record_virtual_memory_commit(address addr, size_t size, 332 address pc, Thread* thread = NULL) { 333 if (is_on()) { 334 assert(size > 0, "Sanity check"); 335 create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(), 336 size, pc, thread); 337 } 338 } 339 340 // record a virtual memory 'uncommit' call 341 static inline void record_virtual_memory_uncommit(address addr, size_t size, 342 Thread* thread = NULL) { 343 if (is_on()) { 344 assert(size > 0, "Sanity check"); 345 create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(), 346 size, DEBUG_CALLER_PC, thread); 347 } 348 } 349 350 // record a virtual memory 'release' call 351 static inline void record_virtual_memory_release(address addr, size_t size, 352 Thread* thread = NULL) { 353 if (is_on()) { 354 assert(size > 0, "Sanity check"); 355 create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(), 356 size, DEBUG_CALLER_PC, thread); 357 } 358 } 359 360 // record memory type on virtual memory base address 361 static inline void record_virtual_memory_type(address base, MEMFLAGS flags, 362 Thread* thread = NULL) { 363 if (is_on()) { 364 assert(base > 0, "wrong base address"); 365 assert((flags & (~mt_masks)) == 0, "memory type only"); 366 create_memory_record(base, (flags | MemPointerRecord::virtual_memory_type_tag()), 367 0, DEBUG_CALLER_PC, thread); 368 } 369 } 370 371 372 // create memory baseline of current memory snapshot 373 static bool baseline(); 374 // is there a memory baseline 375 static bool has_baseline() { 376 return _baseline.baselined(); 377 } 378 379 // print memory usage from current snapshot 380 static bool print_memory_usage(BaselineOutputer& out, size_t unit, 381 bool summary_only = true); 382 // compare memory usage between current snapshot and baseline 383 static bool compare_memory_usage(BaselineOutputer& out, size_t unit, 384 bool summary_only = true); 385 386 // sync is called within global safepoint to synchronize nmt data 387 static void sync(); 388 389 // called when a thread is about to exit 390 static void thread_exiting(JavaThread* thread); 391 392 // retrieve global snapshot 393 static MemSnapshot* get_snapshot() { 394 if (shutdown_in_progress()) { 395 return NULL; 396 } 397 return _snapshot; 398 } 399 400 // print tracker stats 401 NOT_PRODUCT(static void print_tracker_stats(outputStream* st);) 402 NOT_PRODUCT(static void walk_stack(int toSkip, char* buf, int len);) 403 404 private: 405 // start native memory tracking worker thread 406 static bool start_worker(); 407 408 // called by worker thread to complete shutdown process 409 static void final_shutdown(); 410 411 protected: 412 // retrieve per-thread recorder of the specified thread. 413 // if the recorder is full, it will be enqueued to overflow 414 // queue, a new recorder is acquired from recorder pool or a 415 // new instance is created. 416 // when thread == NULL, it means global recorder 417 static MemRecorder* get_thread_recorder(JavaThread* thread); 418 419 // per-thread recorder pool 420 static void release_thread_recorder(MemRecorder* rec); 421 static void delete_all_pooled_recorders(); 422 423 // pending recorder queue. Recorders are queued to pending queue 424 // when they are overflowed or collected at nmt sync point. 425 static void enqueue_pending_recorder(MemRecorder* rec); 426 static MemRecorder* get_pending_recorders(); 427 static void delete_all_pending_recorders(); 428 429 private: 430 // retrieve a pooled memory record or create new one if there is not 431 // one available 432 static MemRecorder* get_new_or_pooled_instance(); 433 static void create_memory_record(address addr, MEMFLAGS type, 434 size_t size, address pc, Thread* thread); 435 static void create_record_in_recorder(address addr, MEMFLAGS type, 436 size_t size, address pc, JavaThread* thread); 437 438 private: 439 // global memory snapshot 440 static MemSnapshot* _snapshot; 441 442 // a memory baseline of snapshot 443 static MemBaseline _baseline; 444 445 // query lock 446 static Mutex* _query_lock; 447 448 // a thread can start to allocate memory before it is attached 449 // to VM 'Thread', those memory activities are recorded here. 450 // ThreadCritical is required to guard this global recorder. 451 static MemRecorder* _global_recorder; 452 453 // main thread id 454 debug_only(static intx _main_thread_tid;) 455 456 // pending recorders to be merged 457 static volatile MemRecorder* _merge_pending_queue; 458 459 NOT_PRODUCT(static volatile jint _pending_recorder_count;) 460 461 // pooled memory recorders 462 static volatile MemRecorder* _pooled_recorders; 463 464 // memory recorder pool management, uses following 465 // counter to determine if a released memory recorder 466 // should be pooled 467 468 // latest thread count 469 static int _thread_count; 470 // pooled recorder count 471 static volatile jint _pooled_recorder_count; 472 473 474 // worker thread to merge pending recorders into snapshot 475 static MemTrackWorker* _worker_thread; 476 477 // how many safepoints we skipped without entering sync point 478 static int _sync_point_skip_count; 479 480 // if the tracker is properly intialized 481 static bool _is_tracker_ready; 482 // tracking level (off, summary and detail) 483 static enum NMTLevel _tracking_level; 484 485 // current nmt state 486 static volatile enum NMTStates _state; 487 // the reason for shutting down nmt 488 static enum ShutdownReason _reason; 489 }; 490 491 #endif // !INCLUDE_NMT 492 493 #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP