src/share/vm/services/memTracker.hpp

Wed, 27 Aug 2014 08:19:12 -0400

author
zgu
date
Wed, 27 Aug 2014 08:19:12 -0400
changeset 7074
833b0f92429a
parent 5578
4c84d351cca9
child 7078
c6211b707068
permissions
-rw-r--r--

8046598: Scalable Native memory tracking development
Summary: Enhance scalability of native memory tracking
Reviewed-by: coleenp, ctornqvi, gtriantafill

zgu@3900 1 /*
zgu@7074 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
zgu@3900 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
zgu@3900 4 *
zgu@3900 5 * This code is free software; you can redistribute it and/or modify it
zgu@3900 6 * under the terms of the GNU General Public License version 2 only, as
zgu@3900 7 * published by the Free Software Foundation.
zgu@3900 8 *
zgu@3900 9 * This code is distributed in the hope that it will be useful, but WITHOUT
zgu@3900 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
zgu@3900 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
zgu@3900 12 * version 2 for more details (a copy is included in the LICENSE file that
zgu@3900 13 * accompanied this code).
zgu@3900 14 *
zgu@3900 15 * You should have received a copy of the GNU General Public License version
zgu@3900 16 * 2 along with this work; if not, write to the Free Software Foundation,
zgu@3900 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
zgu@3900 18 *
zgu@3900 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
zgu@3900 20 * or visit www.oracle.com if you need additional information or have any
zgu@3900 21 * questions.
zgu@3900 22 *
zgu@3900 23 */
zgu@3900 24
zgu@3900 25 #ifndef SHARE_VM_SERVICES_MEM_TRACKER_HPP
zgu@3900 26 #define SHARE_VM_SERVICES_MEM_TRACKER_HPP
zgu@3900 27
zgu@7074 28 #include "services/nmtCommon.hpp"
zgu@7074 29
zgu@7074 30 class NativeCallStack;
zgu@7074 31 extern NativeCallStack emptyStack;
jprovino@4165 32
jprovino@4165 33 #if !INCLUDE_NMT
jprovino@4165 34
zgu@7074 35 #define CURRENT_PC emptyStack
zgu@7074 36 #define CALLER_PC emptyStack
jprovino@4165 37
zgu@7074 38 class Tracker : public StackObj {
zgu@7074 39 public:
zgu@7074 40 Tracker() { }
zgu@7074 41 void record(address addr, size_t size) { }
jprovino@4165 42 };
jprovino@4165 43
jprovino@4165 44 class MemTracker : AllStatic {
zgu@7074 45 public:
zgu@7074 46 static inline NMT_TrackingLevel tracking_level() { return NMT_off; }
zgu@7074 47 static inline void shutdown() { }
zgu@7074 48 static inline void init() { }
zgu@7074 49 static bool check_launcher_nmt_support(const char* value) { return true; }
zgu@7074 50 static bool verify_nmt_option() { return true; }
jprovino@4165 51
zgu@7074 52 static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
zgu@7074 53 const NativeCallStack& stack, NMT_TrackingLevel level) { return mem_base; }
zgu@7074 54 static inline size_t malloc_header_size(NMT_TrackingLevel level) { return 0; }
zgu@7074 55 static inline size_t malloc_header_size(void* memblock) { return 0; }
zgu@7074 56 static inline void* malloc_base(void* memblock) { return memblock; }
zgu@7074 57 static inline void* record_free(void* memblock) { return memblock; }
zgu@5272 58
zgu@7074 59 static inline void record_new_arena(MEMFLAGS flag) { }
zgu@7074 60 static inline void record_arena_free(MEMFLAGS flag) { }
zgu@7074 61 static inline void record_arena_size_change(int diff, MEMFLAGS flag) { }
zgu@7074 62 static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
zgu@7074 63 MEMFLAGS flag = mtNone) { }
zgu@7074 64 static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
zgu@7074 65 const NativeCallStack& stack, MEMFLAGS flag = mtNone) { }
zgu@7074 66 static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { }
zgu@7074 67 static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); }
zgu@7074 68 static inline Tracker get_virtual_memory_release_tracker() { }
zgu@7074 69 static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { }
zgu@7074 70 static inline void record_thread_stack(void* addr, size_t size) { }
zgu@7074 71 static inline void release_thread_stack(void* addr, size_t size) { }
zgu@5272 72
zgu@7074 73 static void final_report(outputStream*) { }
jprovino@4165 74 };
jprovino@4165 75
zgu@7074 76 #else
jprovino@4165 77
zgu@7074 78 #include "runtime/atomic.hpp"
zgu@7074 79 #include "runtime/threadCritical.hpp"
zgu@7074 80 #include "services/mallocTracker.hpp"
zgu@7074 81 #include "services/virtualMemoryTracker.hpp"
jprovino@4165 82
zgu@7074 83 extern volatile bool NMT_stack_walkable;
zgu@3900 84
zgu@7074 85 #define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \
zgu@7074 86 NativeCallStack(0, true) : emptyStack)
zgu@7074 87 #define CALLER_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \
zgu@7074 88 NativeCallStack(1, true) : emptyStack)
zgu@4193 89
zgu@7074 90 class MemBaseline;
zgu@7074 91 class Mutex;
ctornqvi@4512 92
zgu@7074 93 // Tracker is used for guarding 'release' semantics of virtual memory operation, to avoid
zgu@7074 94 // the other thread obtains and records the same region that is just 'released' by current
zgu@7074 95 // thread but before it can record the operation.
zgu@7074 96 class Tracker : public StackObj {
zgu@3900 97 public:
zgu@7074 98 enum TrackerType {
zgu@7074 99 uncommit,
zgu@7074 100 release
zgu@3900 101 };
zgu@3900 102
zgu@4081 103 public:
zgu@7074 104 Tracker(enum TrackerType type) : _type(type) { }
zgu@7074 105 void record(address addr, size_t size);
zgu@7074 106 private:
zgu@7074 107 enum TrackerType _type;
zgu@7074 108 // Virtual memory tracking data structures are protected by ThreadCritical lock.
zgu@7074 109 ThreadCritical _tc;
zgu@7074 110 };
zgu@5272 111
zgu@7074 112 class MemTracker : AllStatic {
zgu@5272 113 public:
zgu@7074 114 static inline NMT_TrackingLevel tracking_level() {
zgu@7074 115 if (_tracking_level == NMT_unknown) {
zgu@7074 116 // No fencing is needed here, since JVM is in single-threaded
zgu@7074 117 // mode.
zgu@7074 118 _tracking_level = init_tracking_level();
zgu@7074 119 _cmdline_tracking_level = _tracking_level;
zgu@7074 120 }
zgu@4081 121 return _tracking_level;
zgu@4081 122 }
zgu@4081 123
zgu@7074 124 // A late initialization, for the stuff(s) can not be
zgu@7074 125 // done in init_tracking_level(), which can NOT malloc
zgu@7074 126 // any memory.
zgu@7074 127 static void init();
zgu@7074 128
zgu@7074 129 // Shutdown native memory tracking
zgu@7074 130 static void shutdown();
zgu@7074 131
zgu@7074 132 // Verify native memory tracking command line option.
zgu@7074 133 // This check allows JVM to detect if compatible launcher
zgu@7074 134 // is used.
zgu@7074 135 // If an incompatible launcher is used, NMT may not be
zgu@7074 136 // able to start, even it is enabled by command line option.
zgu@7074 137 // A warning message should be given if it is encountered.
zgu@7074 138 static bool check_launcher_nmt_support(const char* value);
zgu@7074 139
zgu@7074 140 // This method checks native memory tracking environment
zgu@7074 141 // variable value passed by launcher.
zgu@7074 142 // Launcher only obligates to pass native memory tracking
zgu@7074 143 // option value, but not obligates to validate the value,
zgu@7074 144 // and launcher has option to discard native memory tracking
zgu@7074 145 // option from the command line once it sets up the environment
zgu@7074 146 // variable, so NMT has to catch the bad value here.
zgu@7074 147 static bool verify_nmt_option();
zgu@7074 148
zgu@7074 149 // Transition the tracking level to specified level
zgu@7074 150 static bool transition_to(NMT_TrackingLevel level);
zgu@7074 151
zgu@7074 152 static inline void* record_malloc(void* mem_base, size_t size, MEMFLAGS flag,
zgu@7074 153 const NativeCallStack& stack, NMT_TrackingLevel level) {
zgu@7074 154 return MallocTracker::record_malloc(mem_base, size, flag, stack, level);
zgu@7074 155 }
zgu@7074 156
zgu@7074 157 static inline size_t malloc_header_size(NMT_TrackingLevel level) {
zgu@7074 158 return MallocTracker::malloc_header_size(level);
zgu@7074 159 }
zgu@7074 160
zgu@7074 161 static size_t malloc_header_size(void* memblock) {
zgu@7074 162 if (tracking_level() != NMT_off) {
zgu@7074 163 return MallocTracker::get_header_size(memblock);
zgu@7074 164 }
zgu@7074 165 return 0;
zgu@7074 166 }
zgu@7074 167
zgu@7074 168 // To malloc base address, which is the starting address
zgu@7074 169 // of malloc tracking header if tracking is enabled.
zgu@7074 170 // Otherwise, it returns the same address.
zgu@7074 171 static void* malloc_base(void* memblock);
zgu@7074 172
zgu@7074 173 // Record malloc free and return malloc base address
zgu@7074 174 static inline void* record_free(void* memblock) {
zgu@7074 175 return MallocTracker::record_free(memblock);
zgu@7074 176 }
zgu@7074 177
zgu@7074 178
zgu@7074 179 // Record creation of an arena
zgu@7074 180 static inline void record_new_arena(MEMFLAGS flag) {
zgu@7074 181 if (tracking_level() < NMT_summary) return;
zgu@7074 182 MallocTracker::record_new_arena(flag);
zgu@7074 183 }
zgu@7074 184
zgu@7074 185 // Record destruction of an arena
zgu@7074 186 static inline void record_arena_free(MEMFLAGS flag) {
zgu@7074 187 if (tracking_level() < NMT_summary) return;
zgu@7074 188 MallocTracker::record_arena_free(flag);
zgu@7074 189 }
zgu@7074 190
zgu@7074 191 // Record arena size change. Arena size is the size of all arena
zgu@7074 192 // chuncks that backing up the arena.
zgu@7074 193 static inline void record_arena_size_change(int diff, MEMFLAGS flag) {
zgu@7074 194 if (tracking_level() < NMT_summary) return;
zgu@7074 195 MallocTracker::record_arena_size_change(diff, flag);
zgu@7074 196 }
zgu@7074 197
zgu@7074 198 static inline void record_virtual_memory_reserve(void* addr, size_t size, const NativeCallStack& stack,
zgu@7074 199 MEMFLAGS flag = mtNone) {
zgu@7074 200 if (tracking_level() < NMT_summary) return;
zgu@7074 201 if (addr != NULL) {
zgu@7074 202 ThreadCritical tc;
zgu@7074 203 // Recheck to avoid potential racing during NMT shutdown
zgu@7074 204 if (tracking_level() < NMT_summary) return;
zgu@7074 205 VirtualMemoryTracker::add_reserved_region((address)addr, size, stack, flag);
zgu@3900 206 }
zgu@3900 207 }
zgu@3900 208
zgu@7074 209 static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
zgu@7074 210 const NativeCallStack& stack, MEMFLAGS flag = mtNone) {
zgu@7074 211 if (tracking_level() < NMT_summary) return;
zgu@7074 212 if (addr != NULL) {
zgu@7074 213 ThreadCritical tc;
zgu@7074 214 if (tracking_level() < NMT_summary) return;
zgu@7074 215 VirtualMemoryTracker::add_reserved_region((address)addr, size,
zgu@7074 216 stack, flag, true);
zgu@4810 217 }
zgu@4810 218 }
zgu@4810 219
zgu@7074 220 static inline void record_virtual_memory_commit(void* addr, size_t size,
zgu@7074 221 const NativeCallStack& stack) {
zgu@7074 222 if (tracking_level() < NMT_summary) return;
zgu@7074 223 if (addr != NULL) {
zgu@7074 224 ThreadCritical tc;
zgu@7074 225 if (tracking_level() < NMT_summary) return;
zgu@7074 226 VirtualMemoryTracker::add_committed_region((address)addr, size, stack);
stefank@5578 227 }
stefank@5578 228 }
zgu@3900 229
zgu@5272 230 static inline Tracker get_virtual_memory_uncommit_tracker() {
zgu@7074 231 assert(tracking_level() >= NMT_summary, "Check by caller");
zgu@7074 232 return Tracker(Tracker::uncommit);
zgu@5272 233 }
zgu@5272 234
zgu@5272 235 static inline Tracker get_virtual_memory_release_tracker() {
zgu@7074 236 assert(tracking_level() >= NMT_summary, "Check by caller");
zgu@7074 237 return Tracker(Tracker::release);
zgu@3900 238 }
zgu@3900 239
zgu@7074 240 static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) {
zgu@7074 241 if (tracking_level() < NMT_summary) return;
zgu@7074 242 if (addr != NULL) {
zgu@7074 243 ThreadCritical tc;
zgu@7074 244 if (tracking_level() < NMT_summary) return;
zgu@7074 245 VirtualMemoryTracker::set_reserved_region_type((address)addr, flag);
zgu@5272 246 }
zgu@5272 247 }
zgu@5272 248
zgu@7074 249 static inline void record_thread_stack(void* addr, size_t size) {
zgu@7074 250 if (tracking_level() < NMT_summary) return;
zgu@7074 251 if (addr != NULL) {
zgu@7074 252 // uses thread stack malloc slot for book keeping number of threads
zgu@7074 253 MallocMemorySummary::record_malloc(0, mtThreadStack);
zgu@7074 254 record_virtual_memory_reserve_and_commit(addr, size, CALLER_PC, mtThreadStack);
zgu@7074 255 }
zgu@5272 256 }
zgu@5272 257
zgu@7074 258 static inline void release_thread_stack(void* addr, size_t size) {
zgu@7074 259 if (tracking_level() < NMT_summary) return;
zgu@7074 260 if (addr != NULL) {
zgu@7074 261 // uses thread stack malloc slot for book keeping number of threads
zgu@7074 262 MallocMemorySummary::record_free(0, mtThreadStack);
zgu@7074 263 ThreadCritical tc;
zgu@7074 264 if (tracking_level() < NMT_summary) return;
zgu@7074 265 VirtualMemoryTracker::remove_released_region((address)addr, size);
zgu@7074 266 }
zgu@5272 267 }
zgu@5272 268
zgu@7074 269 // Query lock is used to synchronize the access to tracking data.
zgu@7074 270 // So far, it is only used by JCmd query, but it may be used by
zgu@7074 271 // other tools.
zgu@7074 272 static inline Mutex* query_lock() { return _query_lock; }
zgu@7074 273
zgu@7074 274 // Make a final report and shutdown.
zgu@7074 275 // This function generates summary report without creating snapshots,
zgu@7074 276 // to avoid additional memory allocation. It uses native memory summary
zgu@7074 277 // counters, and makes adjustment to them, once the adjustment is made,
zgu@7074 278 // the counters are no longer accurate. As the result, this function
zgu@7074 279 // should only be used for final reporting before shutting down.
zgu@7074 280 static void final_report(outputStream*);
zgu@7074 281
zgu@7074 282 // Stored baseline
zgu@7074 283 static inline MemBaseline& get_baseline() {
zgu@7074 284 return _baseline;
zgu@7074 285 }
zgu@7074 286
zgu@7074 287 static NMT_TrackingLevel cmdline_tracking_level() {
zgu@7074 288 return _cmdline_tracking_level;
zgu@7074 289 }
zgu@7074 290
zgu@7074 291 static void tuning_statistics(outputStream* out);
zgu@5272 292
zgu@3900 293 private:
zgu@7074 294 static NMT_TrackingLevel init_tracking_level();
ctornqvi@4512 295
zgu@3900 296 private:
zgu@7074 297 // Tracking level
zgu@7074 298 static volatile NMT_TrackingLevel _tracking_level;
zgu@7074 299 // If NMT option value passed by launcher through environment
zgu@7074 300 // variable is valid
zgu@7074 301 static bool _is_nmt_env_valid;
zgu@7074 302 // command line tracking level
zgu@7074 303 static NMT_TrackingLevel _cmdline_tracking_level;
zgu@7074 304 // Stored baseline
zgu@3900 305 static MemBaseline _baseline;
zgu@7074 306 // Query lock
zgu@3936 307 static Mutex* _query_lock;
zgu@3900 308 };
zgu@3900 309
zgu@7074 310 #endif // INCLUDE_NMT
jprovino@4165 311
zgu@3900 312 #endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP
zgu@7074 313

mercurial