memTracker.hpp 18.4 KB
Newer Older
Z
zgu 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */

#ifndef SHARE_VM_SERVICES_MEM_TRACKER_HPP
#define SHARE_VM_SERVICES_MEM_TRACKER_HPP

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
#include "utilities/macros.hpp"

#if !INCLUDE_NMT

#include "utilities/ostream.hpp"

class BaselineOutputer : public StackObj {

};

class BaselineTTYOutputer : public BaselineOutputer {
  public:
    BaselineTTYOutputer(outputStream* st) { }
};

class MemTracker : AllStatic {
  public:
   enum ShutdownReason {
      NMT_shutdown_none,     // no shutdown requested
      NMT_shutdown_user,     // user requested shutdown
      NMT_normal,            // normal shutdown, process exit
      NMT_out_of_memory,     // shutdown due to out of memory
      NMT_initialization,    // shutdown due to initialization failure
      NMT_use_malloc_only,   // can not combine NMT with UseMallocOnly flag
      NMT_error_reporting,   // shutdown by vmError::report_and_die()
      NMT_out_of_generation, // running out of generation queue
      NMT_sequence_overflow  // overflow the sequence number
   };


  public:
   static inline void init_tracking_options(const char* option_line) { }
   static inline bool is_on()   { return false; }
   static const char* reason()  { return "Native memory tracking is not implemented"; }
   static inline bool can_walk_stack() { return false; }

   static inline void bootstrap_single_thread() { }
   static inline void bootstrap_multi_thread() { }
   static inline void start() { }

   static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
        address pc = 0, Thread* thread = NULL) { }
   static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) { }
   static inline void record_realloc(address old_addr, address new_addr, size_t size,
        MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { }
   static inline void record_arena_size(address addr, size_t size) { }
   static inline void record_virtual_memory_reserve(address addr, size_t size,
        address pc = 0, Thread* thread = NULL) { }
   static inline void record_virtual_memory_commit(address addr, size_t size,
        address pc = 0, Thread* thread = NULL) { }
   static inline void record_virtual_memory_uncommit(address addr, size_t size,
        Thread* thread = NULL) { }
   static inline void record_virtual_memory_release(address addr, size_t size,
        Thread* thread = NULL) { }
   static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
        Thread* thread = NULL) { }
   static inline bool baseline() { return false; }
   static inline bool has_baseline() { return false; }

   static void shutdown(ShutdownReason reason) { }
   static inline bool shutdown_in_progress() {  }
   static bool print_memory_usage(BaselineOutputer& out, size_t unit,
            bool summary_only = true) { }
   static bool compare_memory_usage(BaselineOutputer& out, size_t unit,
            bool summary_only = true) { }

94 95
   static bool wbtest_wait_for_data_merge() { }

96 97 98 99 100 101 102
   static inline void sync() { }
   static inline void thread_exiting(JavaThread* thread) { }
};


#else // !INCLUDE_NMT

Z
zgu 已提交
103 104 105 106 107 108 109 110 111 112
#include "memory/allocation.hpp"
#include "runtime/globals.hpp"
#include "runtime/mutex.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.hpp"
#include "services/memPtr.hpp"
#include "services/memRecorder.hpp"
#include "services/memSnapshot.hpp"
#include "services/memTrackWorker.hpp"

113 114
extern bool NMT_track_callsite;

115 116 117 118
#ifndef MAX_UNSIGNED_LONG
#define MAX_UNSIGNED_LONG    (unsigned long)(-1)
#endif

119 120
#ifdef ASSERT
  #define DEBUG_CALLER_PC  (NMT_track_callsite ? os::get_caller_pc(2) : 0)
Z
zgu 已提交
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
#else
  #define DEBUG_CALLER_PC  0
#endif

// The thread closure walks threads to collect per-thread
// memory recorders at NMT sync point
class SyncThreadRecorderClosure : public ThreadClosure {
 private:
  int _thread_count;

 public:
  SyncThreadRecorderClosure() {
    _thread_count =0;
  }

  void do_thread(Thread* thread);
  int  get_thread_count() const {
    return _thread_count;
  }
};

class BaselineOutputer;
class MemSnapshot;
class MemTrackWorker;
class Thread;
/*
 * MemTracker is the 'gate' class to native memory tracking runtime.
 */
class MemTracker : AllStatic {
150
  friend class GenerationData;
Z
zgu 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  friend class MemTrackWorker;
  friend class MemSnapshot;
  friend class SyncThreadRecorderClosure;

  // NMT state
  enum NMTStates {
    NMT_uninited,                        // not yet initialized
    NMT_bootstrapping_single_thread,     // bootstrapping, VM is in single thread mode
    NMT_bootstrapping_multi_thread,      // bootstrapping, VM is about to enter multi-thread mode
    NMT_started,                         // NMT fully started
    NMT_shutdown_pending,                // shutdown pending
    NMT_final_shutdown,                  // in final phase of shutdown
    NMT_shutdown                         // shutdown
  };

166
 public:
Z
zgu 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  // native memory tracking level
  enum NMTLevel {
    NMT_off,              // native memory tracking is off
    NMT_summary,          // don't track callsite
    NMT_detail            // track callsite also
  };

   enum ShutdownReason {
     NMT_shutdown_none,     // no shutdown requested
     NMT_shutdown_user,     // user requested shutdown
     NMT_normal,            // normal shutdown, process exit
     NMT_out_of_memory,     // shutdown due to out of memory
     NMT_initialization,    // shutdown due to initialization failure
     NMT_use_malloc_only,   // can not combine NMT with UseMallocOnly flag
     NMT_error_reporting,   // shutdown by vmError::report_and_die()
     NMT_out_of_generation, // running out of generation queue
     NMT_sequence_overflow  // overflow the sequence number
   };

 public:
  // initialize NMT tracking level from command line options, called
   // from VM command line parsing code
  static void init_tracking_options(const char* option_line);

  // if NMT is enabled to record memory activities
  static inline bool is_on() {
    return (_tracking_level >= NMT_summary &&
      _state >= NMT_bootstrapping_single_thread);
  }

197 198 199 200
  static inline enum NMTLevel tracking_level() {
    return _tracking_level;
  }

Z
zgu 已提交
201 202 203 204 205 206 207 208 209
  // user readable reason for shutting down NMT
  static const char* reason() {
    switch(_reason) {
      case NMT_shutdown_none:
        return "Native memory tracking is not enabled";
      case NMT_shutdown_user:
        return "Native memory tracking has been shutdown by user";
      case NMT_normal:
        return "Native memory tracking has been shutdown due to process exiting";
210 211
      case NMT_out_of_memory:
        return "Native memory tracking has been shutdown due to out of native memory";
Z
zgu 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
      case NMT_initialization:
        return "Native memory tracking failed to initialize";
      case NMT_error_reporting:
        return "Native memory tracking has been shutdown due to error reporting";
      case NMT_out_of_generation:
        return "Native memory tracking has been shutdown due to running out of generation buffer";
      case NMT_sequence_overflow:
        return "Native memory tracking has been shutdown due to overflow the sequence number";
      case NMT_use_malloc_only:
        return "Native memory tracking is not supported when UseMallocOnly is on";
      default:
        ShouldNotReachHere();
        return NULL;
    }
  }

  // test if we can walk native stack
  static bool can_walk_stack() {
  // native stack is not walkable during bootstrapping on sparc
#if defined(SPARC)
    return (_state == NMT_started);
#else
    return (_state >= NMT_bootstrapping_single_thread && _state  <= NMT_started);
#endif
  }

  // if native memory tracking tracks callsite
  static inline bool track_callsite() { return _tracking_level == NMT_detail; }

  // shutdown native memory tracking capability. Native memory tracking
  // can be shutdown by VM when it encounters low memory scenarios.
  // Memory tracker should gracefully shutdown itself, and preserve the
  // latest memory statistics for post morten diagnosis.
  static void shutdown(ShutdownReason reason);

  // if there is shutdown requested
  static inline bool shutdown_in_progress() {
    return (_state >= NMT_shutdown_pending);
  }

  // bootstrap native memory tracking, so it can start to collect raw data
  // before worker thread can start

  // the first phase of bootstrapping, when VM still in single-threaded mode
  static void bootstrap_single_thread();
  // the second phase of bootstrapping, VM is about or already in multi-threaded mode
  static void bootstrap_multi_thread();


  // start() has to be called when VM still in single thread mode, but after
  // command line option parsing is done.
  static void start();

  // record a 'malloc' call
  static inline void record_malloc(address addr, size_t size, MEMFLAGS flags,
                            address pc = 0, Thread* thread = NULL) {
268
    if (is_on() && NMT_CAN_TRACK(flags)) {
269
      assert(size > 0, "Sanity check");
Z
zgu 已提交
270 271 272 273 274 275 276 277 278 279 280 281
      create_memory_record(addr, (flags|MemPointerRecord::malloc_tag()), size, pc, thread);
    }
  }
  // record a 'free' call
  static inline void record_free(address addr, MEMFLAGS flags, Thread* thread = NULL) {
    if (is_on() && NMT_CAN_TRACK(flags)) {
      create_memory_record(addr, MemPointerRecord::free_tag(), 0, 0, thread);
    }
  }
  // record a 'realloc' call
  static inline void record_realloc(address old_addr, address new_addr, size_t size,
       MEMFLAGS flags, address pc = 0, Thread* thread = NULL) {
282
    if (is_on() && NMT_CAN_TRACK(flags)) {
283
      assert(size > 0, "Sanity check");
Z
zgu 已提交
284 285 286 287 288
      record_free(old_addr, flags, thread);
      record_malloc(new_addr, size, flags, pc, thread);
    }
  }

289
  // record arena memory size
Z
zgu 已提交
290
  static inline void record_arena_size(address addr, size_t size) {
291
    // we add a positive offset to arena address, so we can have arena memory record
Z
zgu 已提交
292 293
    // sorted after arena record
    if (is_on() && !UseMallocOnly) {
294
      assert(addr != NULL, "Sanity check");
Z
zgu 已提交
295
      create_memory_record((addr + sizeof(void*)), MemPointerRecord::arena_size_tag(), size,
296
        DEBUG_CALLER_PC, NULL);
Z
zgu 已提交
297 298 299 300 301 302 303
    }
  }

  // record a virtual memory 'reserve' call
  static inline void record_virtual_memory_reserve(address addr, size_t size,
                            address pc = 0, Thread* thread = NULL) {
    if (is_on()) {
304
      assert(size > 0, "Sanity check");
Z
zgu 已提交
305 306 307 308 309
      create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag(),
                           size, pc, thread);
    }
  }

310 311 312 313 314 315 316 317 318 319 320 321 322 323
  static inline void record_thread_stack(address addr, size_t size, Thread* thr,
                           address pc = 0) {
    if (is_on()) {
      assert(size > 0 && thr != NULL, "Sanity check");
      create_memory_record(addr, MemPointerRecord::virtual_memory_reserve_tag() | mtThreadStack,
                          size, pc, thr);
      create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag() | mtThreadStack,
                          size, pc, thr);
    }
  }

  static inline void release_thread_stack(address addr, size_t size, Thread* thr) {
    if (is_on()) {
      assert(size > 0 && thr != NULL, "Sanity check");
324
      assert(!thr->is_Java_thread(), "too early");
325 326 327 328 329 330 331
      create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag() | mtThreadStack,
                          size, DEBUG_CALLER_PC, thr);
      create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag() | mtThreadStack,
                          size, DEBUG_CALLER_PC, thr);
    }
  }

Z
zgu 已提交
332 333
  // record a virtual memory 'commit' call
  static inline void record_virtual_memory_commit(address addr, size_t size,
334
                            address pc, Thread* thread = NULL) {
Z
zgu 已提交
335
    if (is_on()) {
336
      assert(size > 0, "Sanity check");
Z
zgu 已提交
337
      create_memory_record(addr, MemPointerRecord::virtual_memory_commit_tag(),
338
                           size, pc, thread);
Z
zgu 已提交
339 340 341 342 343 344 345
    }
  }

  // record a virtual memory 'uncommit' call
  static inline void record_virtual_memory_uncommit(address addr, size_t size,
                            Thread* thread = NULL) {
    if (is_on()) {
346
      assert(size > 0, "Sanity check");
Z
zgu 已提交
347
      create_memory_record(addr, MemPointerRecord::virtual_memory_uncommit_tag(),
348
                           size, DEBUG_CALLER_PC, thread);
Z
zgu 已提交
349 350 351 352 353 354 355
    }
  }

  // record a virtual memory 'release' call
  static inline void record_virtual_memory_release(address addr, size_t size,
                            Thread* thread = NULL) {
    if (is_on()) {
356
      assert(size > 0, "Sanity check");
Z
zgu 已提交
357
      create_memory_record(addr, MemPointerRecord::virtual_memory_release_tag(),
358
                           size, DEBUG_CALLER_PC, thread);
Z
zgu 已提交
359 360 361 362 363 364 365 366 367 368
    }
  }

  // record memory type on virtual memory base address
  static inline void record_virtual_memory_type(address base, MEMFLAGS flags,
                            Thread* thread = NULL) {
    if (is_on()) {
      assert(base > 0, "wrong base address");
      assert((flags & (~mt_masks)) == 0, "memory type only");
      create_memory_record(base, (flags | MemPointerRecord::virtual_memory_type_tag()),
369
                           0, DEBUG_CALLER_PC, thread);
Z
zgu 已提交
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
    }
  }


  // create memory baseline of current memory snapshot
  static bool baseline();
  // is there a memory baseline
  static bool has_baseline() {
    return _baseline.baselined();
  }

  // print memory usage from current snapshot
  static bool print_memory_usage(BaselineOutputer& out, size_t unit,
           bool summary_only = true);
  // compare memory usage between current snapshot and baseline
  static bool compare_memory_usage(BaselineOutputer& out, size_t unit,
           bool summary_only = true);

388 389 390 391 392
  // the version for whitebox testing support, it ensures that all memory
  // activities before this method call, are reflected in the snapshot
  // database.
  static bool wbtest_wait_for_data_merge();

Z
zgu 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
  // sync is called within global safepoint to synchronize nmt data
  static void sync();

  // called when a thread is about to exit
  static void thread_exiting(JavaThread* thread);

  // retrieve global snapshot
  static MemSnapshot* get_snapshot() {
    if (shutdown_in_progress()) {
      return NULL;
    }
    return _snapshot;
  }

  // print tracker stats
  NOT_PRODUCT(static void print_tracker_stats(outputStream* st);)
  NOT_PRODUCT(static void walk_stack(int toSkip, char* buf, int len);)

 private:
  // start native memory tracking worker thread
  static bool start_worker();

  // called by worker thread to complete shutdown process
  static void final_shutdown();

 protected:
  // retrieve per-thread recorder of the specified thread.
  // if the recorder is full, it will be enqueued to overflow
  // queue, a new recorder is acquired from recorder pool or a
  // new instance is created.
  // when thread == NULL, it means global recorder
  static MemRecorder* get_thread_recorder(JavaThread* thread);

  // per-thread recorder pool
  static void release_thread_recorder(MemRecorder* rec);
  static void delete_all_pooled_recorders();

  // pending recorder queue. Recorders are queued to pending queue
  // when they are overflowed or collected at nmt sync point.
  static void enqueue_pending_recorder(MemRecorder* rec);
  static MemRecorder* get_pending_recorders();
  static void delete_all_pending_recorders();

 private:
  // retrieve a pooled memory record or create new one if there is not
  // one available
  static MemRecorder* get_new_or_pooled_instance();
  static void create_memory_record(address addr, MEMFLAGS type,
                   size_t size, address pc, Thread* thread);
  static void create_record_in_recorder(address addr, MEMFLAGS type,
443
                   size_t size, address pc, JavaThread* thread);
Z
zgu 已提交
444

445 446 447 448 449 450 451 452 453
  static void set_current_processing_generation(unsigned long generation) {
    _worker_thread_idle = false;
    _processing_generation = generation;
  }

  static void report_worker_idle() {
    _worker_thread_idle = true;
  }

Z
zgu 已提交
454 455 456 457 458 459 460 461
 private:
  // global memory snapshot
  static MemSnapshot*     _snapshot;

  // a memory baseline of snapshot
  static MemBaseline      _baseline;

  // query lock
462
  static Mutex*           _query_lock;
Z
zgu 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504

  // a thread can start to allocate memory before it is attached
  // to VM 'Thread', those memory activities are recorded here.
  // ThreadCritical is required to guard this global recorder.
  static MemRecorder*     _global_recorder;

  // main thread id
  debug_only(static intx   _main_thread_tid;)

  // pending recorders to be merged
  static volatile MemRecorder*      _merge_pending_queue;

  NOT_PRODUCT(static volatile jint   _pending_recorder_count;)

  // pooled memory recorders
  static volatile MemRecorder*      _pooled_recorders;

  // memory recorder pool management, uses following
  // counter to determine if a released memory recorder
  // should be pooled

  // latest thread count
  static int               _thread_count;
  // pooled recorder count
  static volatile jint     _pooled_recorder_count;


  // worker thread to merge pending recorders into snapshot
  static MemTrackWorker*  _worker_thread;

  // how many safepoints we skipped without entering sync point
  static int              _sync_point_skip_count;

  // if the tracker is properly intialized
  static bool             _is_tracker_ready;
  // tracking level (off, summary and detail)
  static enum NMTLevel    _tracking_level;

  // current nmt state
  static volatile enum NMTStates   _state;
  // the reason for shutting down nmt
  static enum ShutdownReason       _reason;
505 506 507 508 509
  // the generation that NMT is processing
  static volatile unsigned long    _processing_generation;
  // although NMT is still procesing current generation, but
  // there is not more recorder to process, set idle state
  static volatile bool             _worker_thread_idle;
Z
zgu 已提交
510 511
};

512 513
#endif // !INCLUDE_NMT

Z
zgu 已提交
514
#endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP