hotspot/src/share/vm/services/memTracker.hpp
changeset 18086 f44cf213a775
parent 16991 aa4978a77e1f
child 18681 c3f1b735c47f
equal deleted inserted replaced
18084:c2e807acd8c5 18086:f44cf213a775
     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