memTracker.hpp 11.4 KB
Newer Older
Z
zgu 已提交
1
/*
2
 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
Z
zgu 已提交
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
 * 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
#include "services/nmtCommon.hpp"
29
#include "utilities/nativeCallStack.hpp"
30 31


32
#if !INCLUDE_NMT
33

34 35
#define CURRENT_PC   NativeCallStack::EMPTY_STACK
#define CALLER_PC    NativeCallStack::EMPTY_STACK
36

37 38 39 40
class Tracker : public StackObj {
 public:
  Tracker() { }
  void record(address addr, size_t size) { }
41 42 43
};

class MemTracker : AllStatic {
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
 public:
  static inline NMT_TrackingLevel tracking_level() { return NMT_off; }
  static inline void shutdown() { }
  static inline void init() { }
  static bool check_launcher_nmt_support(const char* value) { return true; }
  static bool verify_nmt_option() { return true; }

  static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
    const NativeCallStack& stack, NMT_TrackingLevel level) { return mem_base; }
  static inline size_t malloc_header_size(NMT_TrackingLevel level) { return 0; }
  static inline size_t malloc_header_size(void* memblock) { return 0; }
  static inline void* malloc_base(void* memblock) { return memblock; }
  static inline void* record_free(void* memblock) { return memblock; }

  static inline void record_new_arena(MEMFLAGS flag) { }
  static inline void record_arena_free(MEMFLAGS flag) { }
  static inline void record_arena_size_change(int diff, MEMFLAGS flag) { }
  static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
                       MEMFLAGS flag = mtNone) { }
  static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
    const NativeCallStack& stack, MEMFLAGS flag = mtNone) { }
  static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { }
  static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); }
  static inline Tracker get_virtual_memory_release_tracker() { }
  static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { }
  static inline void record_thread_stack(void* addr, size_t size) { }
  static inline void release_thread_stack(void* addr, size_t size) { }

  static void final_report(outputStream*) { }
73
  static void error_report(outputStream*) { }
74 75
};

Z
zgu 已提交
76 77
#else

78 79 80 81
#include "runtime/atomic.hpp"
#include "runtime/threadCritical.hpp"
#include "services/mallocTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
Z
zgu 已提交
82

83
extern volatile bool NMT_stack_walkable;
Z
zgu 已提交
84

85
#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \
86
                    NativeCallStack(0, true) : NativeCallStack::EMPTY_STACK)
87
#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ?  \
88
                    NativeCallStack(1, true) : NativeCallStack::EMPTY_STACK)
Z
zgu 已提交
89

90 91
class MemBaseline;
class Mutex;
Z
zgu 已提交
92

93 94 95 96
// Tracker is used for guarding 'release' semantics of virtual memory operation, to avoid
// the other thread obtains and records the same region that is just 'released' by current
// thread but before it can record the operation.
class Tracker : public StackObj {
97
 public:
98 99 100
  enum TrackerType {
     uncommit,
     release
101 102
  };

103
 public:
104 105 106 107 108 109 110
  Tracker(enum TrackerType type) : _type(type) { }
  void record(address addr, size_t size);
 private:
  enum TrackerType  _type;
  // Virtual memory tracking data structures are protected by ThreadCritical lock.
  ThreadCritical    _tc;
};
Z
zgu 已提交
111

112
class MemTracker : AllStatic {
Z
zgu 已提交
113
 public:
114 115 116 117 118 119 120
  static inline NMT_TrackingLevel tracking_level() {
    if (_tracking_level == NMT_unknown) {
      // No fencing is needed here, since JVM is in single-threaded
      // mode.
      _tracking_level = init_tracking_level();
      _cmdline_tracking_level = _tracking_level;
    }
121 122 123
    return _tracking_level;
  }

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 150 151 152 153 154
  // A late initialization, for the stuff(s) can not be
  // done in init_tracking_level(), which can NOT malloc
  // any memory.
  static void init();

  // Shutdown native memory tracking
  static void shutdown();

  // Verify native memory tracking command line option.
  // This check allows JVM to detect if compatible launcher
  // is used.
  // If an incompatible launcher is used, NMT may not be
  // able to start, even it is enabled by command line option.
  // A warning message should be given if it is encountered.
  static bool check_launcher_nmt_support(const char* value);

  // This method checks native memory tracking environment
  // variable value passed by launcher.
  // Launcher only obligates to pass native memory tracking
  // option value, but not obligates to validate the value,
  // and launcher has option to discard native memory tracking
  // option from the command line once it sets up the environment
  // variable, so NMT has to catch the bad value here.
  static bool verify_nmt_option();

  // Transition the tracking level to specified level
  static bool transition_to(NMT_TrackingLevel level);

  static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
    const NativeCallStack& stack, NMT_TrackingLevel level) {
    return MallocTracker::record_malloc(mem_base, size, flag, stack, level);
Z
zgu 已提交
155 156
  }

157 158
  static inline size_t malloc_header_size(NMT_TrackingLevel level) {
    return MallocTracker::malloc_header_size(level);
Z
zgu 已提交
159 160
  }

161 162 163
  static size_t malloc_header_size(void* memblock) {
    if (tracking_level() != NMT_off) {
      return MallocTracker::get_header_size(memblock);
164
    }
165
    return 0;
166 167
  }

168 169 170 171
  // To malloc base address, which is the starting address
  // of malloc tracking header if tracking is enabled.
  // Otherwise, it returns the same address.
  static void* malloc_base(void* memblock);
Z
zgu 已提交
172

173 174 175
  // Record malloc free and return malloc base address
  static inline void* record_free(void* memblock) {
    return MallocTracker::record_free(memblock);
Z
zgu 已提交
176 177 178
  }


179 180 181 182
  // Record creation of an arena
  static inline void record_new_arena(MEMFLAGS flag) {
    if (tracking_level() < NMT_summary) return;
    MallocTracker::record_new_arena(flag);
Z
zgu 已提交
183 184
  }

185 186 187 188
  // Record destruction of an arena
  static inline void record_arena_free(MEMFLAGS flag) {
    if (tracking_level() < NMT_summary) return;
    MallocTracker::record_arena_free(flag);
Z
zgu 已提交
189 190
  }

191 192 193 194 195
  // Record arena size change. Arena size is the size of all arena
  // chuncks that backing up the arena.
  static inline void record_arena_size_change(int diff, MEMFLAGS flag) {
    if (tracking_level() < NMT_summary) return;
    MallocTracker::record_arena_size_change(diff, flag);
196 197
  }

198 199 200 201 202 203 204 205
  static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
    MEMFLAGS flag = mtNone) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      ThreadCritical tc;
      // Recheck to avoid potential racing during NMT shutdown
      if (tracking_level() < NMT_summary) return;
      VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag);
206 207
    }
  }
Z
zgu 已提交
208

209 210 211 212 213 214 215 216 217
  static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
    const NativeCallStack& stack, MEMFLAGS flag = mtNone) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      ThreadCritical tc;
      if (tracking_level() < NMT_summary) return;
      VirtualMemoryTracker::add_reserved_region((address)addr, size,
        stack, flag, true);
    }
218 219
  }

220 221 222 223 224 225 226 227
  static inline void record_virtual_memory_commit(void* addr, size_t size,
    const NativeCallStack& stack) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      ThreadCritical tc;
      if (tracking_level() < NMT_summary) return;
      VirtualMemoryTracker::add_committed_region((address)addr, size, stack);
    }
228 229 230
  }

  static inline Tracker get_virtual_memory_uncommit_tracker() {
231 232
    assert(tracking_level() >= NMT_summary, "Check by caller");
    return Tracker(Tracker::uncommit);
233 234 235
  }

  static inline Tracker get_virtual_memory_release_tracker() {
236 237
    assert(tracking_level() >= NMT_summary, "Check by caller");
    return Tracker(Tracker::release);
Z
zgu 已提交
238 239
  }

240 241 242 243 244 245
  static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      ThreadCritical tc;
      if (tracking_level() < NMT_summary) return;
      VirtualMemoryTracker::set_reserved_region_type((address)addr, flag);
Z
zgu 已提交
246 247 248
    }
  }

249 250 251 252 253 254 255
  static inline void record_thread_stack(void* addr, size_t size) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      // uses thread stack malloc slot for book keeping number of threads
      MallocMemorySummary::record_malloc(0, mtThreadStack);
      record_virtual_memory_reserve_and_commit(addr, size, CALLER_PC, mtThreadStack);
    }
256 257
  }

258 259 260 261 262 263 264 265
  static inline void release_thread_stack(void* addr, size_t size) {
    if (tracking_level() < NMT_summary) return;
    if (addr != NULL) {
      // uses thread stack malloc slot for book keeping number of threads
      MallocMemorySummary::record_free(0, mtThreadStack);
      ThreadCritical tc;
      if (tracking_level() < NMT_summary) return;
      VirtualMemoryTracker::remove_released_region((address)addr, size);
266 267 268
    }
  }

269 270 271 272 273
  // Query lock is used to synchronize the access to tracking data.
  // So far, it is only used by JCmd query, but it may be used by
  // other tools.
  static inline Mutex* query_lock() { return _query_lock; }

274 275 276 277 278 279 280 281 282 283 284 285 286 287
  // Make a final report or report for hs_err file.
  static void error_report(outputStream* output) {
    if (tracking_level() >= NMT_summary) {
      report(true, output);  // just print summary for error case.
    }
   }

  static void final_report(outputStream* output) {
    NMT_TrackingLevel level = tracking_level();
    if (level >= NMT_summary) {
      report(level == NMT_summary, output);
    }
  }

288 289 290 291

  // Stored baseline
  static inline MemBaseline& get_baseline() {
    return _baseline;
292 293
  }

294 295
  static NMT_TrackingLevel cmdline_tracking_level() {
    return _cmdline_tracking_level;
296 297
  }

298
  static void tuning_statistics(outputStream* out);
299

Z
zgu 已提交
300
 private:
301
  static NMT_TrackingLevel init_tracking_level();
302
  static void report(bool summary_only, outputStream* output);
303

Z
zgu 已提交
304
 private:
305 306 307 308 309 310 311 312
  // Tracking level
  static volatile NMT_TrackingLevel   _tracking_level;
  // If NMT option value passed by launcher through environment
  // variable is valid
  static bool                         _is_nmt_env_valid;
  // command line tracking level
  static NMT_TrackingLevel            _cmdline_tracking_level;
  // Stored baseline
Z
zgu 已提交
313
  static MemBaseline      _baseline;
314
  // Query lock
315
  static Mutex*           _query_lock;
Z
zgu 已提交
316 317
};

318
#endif // INCLUDE_NMT
319

Z
zgu 已提交
320
#endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP
321