src/share/vm/services/memTracker.hpp

Sat, 29 Sep 2012 06:40:00 -0400

author
coleenp
date
Sat, 29 Sep 2012 06:40:00 -0400
changeset 4142
d8ce2825b193
parent 4081
9a86ddfc6c8f
child 4165
fb19af007ffc
permissions
-rw-r--r--

8000213: NPG: Should have renamed arrayKlass and typeArrayKlass
Summary: Capitalize these metadata types (and objArrayKlass)
Reviewed-by: stefank, twisti, kvn

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

mercurial