1 /* 2 * Copyright (c) 2001, 2010, 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 */ 24 25 #include "precompiled.hpp" 26 #include "memory/allocation.inline.hpp" 27 #include "runtime/arguments.hpp" 28 #include "runtime/java.hpp" 29 #include "runtime/mutex.hpp" 30 #include "runtime/mutexLocker.hpp" 31 #include "runtime/os.hpp" 32 #include "runtime/perfData.hpp" 33 #include "runtime/perfMemory.hpp" 34 #include "runtime/statSampler.hpp" 35 #include "utilities/globalDefinitions.hpp" 36 37 // Prefix of performance data file. 38 const char PERFDATA_NAME[] = "hsperfdata"; 39 40 // Add 1 for the '_' character between PERFDATA_NAME and pid. The '\0' terminating 41 // character will be included in the sizeof(PERFDATA_NAME) operation. 42 static const size_t PERFDATA_FILENAME_LEN = sizeof(PERFDATA_NAME) + 43 UINT_CHARS + 1; 44 45 char* PerfMemory::_start = NULL; 46 char* PerfMemory::_end = NULL; 47 char* PerfMemory::_top = NULL; 48 size_t PerfMemory::_capacity = 0; 49 jint PerfMemory::_initialized = false; 50 PerfDataPrologue* PerfMemory::_prologue = NULL; 51 52 void perfMemory_init() { 53 54 if (!UsePerfData) return; 55 56 PerfMemory::initialize(); 57 } 58 59 void perfMemory_exit() { 60 61 if (!UsePerfData) return; 62 if (!PerfMemory::is_initialized()) return; 63 64 // if the StatSampler is active, then we don't want to remove 65 // resources it may be dependent on. Typically, the StatSampler 66 // is disengaged from the watcher thread when this method is called, 67 // but it is not disengaged if this method is invoked during a 68 // VM abort. 69 // 70 if (!StatSampler::is_active()) 71 PerfDataManager::destroy(); 72 73 // remove the persistent external resources, if any. this method 74 // does not unmap or invalidate any virtual memory allocated during 75 // initialization. 76 // 77 PerfMemory::destroy(); 78 } 79 80 void PerfMemory::initialize() { 81 82 if (_prologue != NULL) 83 // initialization already performed 84 return; 85 86 size_t capacity = align_size_up(PerfDataMemorySize, 87 os::vm_allocation_granularity()); 88 89 if (PerfTraceMemOps) { 90 tty->print("PerfDataMemorySize = " SIZE_FORMAT "," 91 " os::vm_allocation_granularity = " SIZE_FORMAT "," 92 " adjusted size = " SIZE_FORMAT "\n", 93 PerfDataMemorySize, 94 os::vm_allocation_granularity(), 95 capacity); 96 } 97 98 // allocate PerfData memory region 99 create_memory_region(capacity); 100 101 if (_start == NULL) { 102 103 // the PerfMemory region could not be created as desired. Rather 104 // than terminating the JVM, we revert to creating the instrumentation 105 // on the C heap. When running in this mode, external monitoring 106 // clients cannot attach to and monitor this JVM. 107 // 108 // the warning is issued only in debug mode in order to avoid 109 // additional output to the stdout or stderr output streams. 110 // 111 if (PrintMiscellaneous && Verbose) { 112 warning("Could not create PerfData Memory region, reverting to malloc"); 113 } 114 115 _prologue = NEW_C_HEAP_OBJ(PerfDataPrologue); 116 } 117 else { 118 119 // the PerfMemory region was created as expected. 120 121 if (PerfTraceMemOps) { 122 tty->print("PerfMemory created: address = " INTPTR_FORMAT "," 123 " size = " SIZE_FORMAT "\n", 124 (void*)_start, 125 _capacity); 126 } 127 128 _prologue = (PerfDataPrologue *)_start; 129 _end = _start + _capacity; 130 _top = _start + sizeof(PerfDataPrologue); 131 } 132 133 assert(_prologue != NULL, "prologue pointer must be initialized"); 134 135 #ifdef VM_LITTLE_ENDIAN 136 _prologue->magic = (jint)0xc0c0feca; 137 _prologue->byte_order = PERFDATA_LITTLE_ENDIAN; 138 #else 139 _prologue->magic = (jint)0xcafec0c0; 140 _prologue->byte_order = PERFDATA_BIG_ENDIAN; 141 #endif 142 143 _prologue->major_version = PERFDATA_MAJOR_VERSION; 144 _prologue->minor_version = PERFDATA_MINOR_VERSION; 145 _prologue->accessible = 0; 146 147 _prologue->entry_offset = sizeof(PerfDataPrologue); 148 _prologue->num_entries = 0; 149 _prologue->used = 0; 150 _prologue->overflow = 0; 151 _prologue->mod_time_stamp = 0; 152 153 OrderAccess::release_store(&_initialized, 1); 154 } 155 156 void PerfMemory::destroy() { 157 158 assert(_prologue != NULL, "prologue pointer must be initialized"); 159 160 if (_start != NULL && _prologue->overflow != 0) { 161 162 // This state indicates that the contiguous memory region exists and 163 // that it wasn't large enough to hold all the counters. In this case, 164 // we output a warning message to the user on exit if the -XX:+Verbose 165 // flag is set (a debug only flag). External monitoring tools can detect 166 // this condition by monitoring the _prologue->overflow word. 167 // 168 // There are two tunables that can help resolve this issue: 169 // - increase the size of the PerfMemory with -XX:PerfDataMemorySize=<n> 170 // - decrease the maximum string constant length with 171 // -XX:PerfMaxStringConstLength=<n> 172 // 173 if (PrintMiscellaneous && Verbose) { 174 warning("PerfMemory Overflow Occurred.\n" 175 "\tCapacity = " SIZE_FORMAT " bytes" 176 " Used = " SIZE_FORMAT " bytes" 177 " Overflow = " INT32_FORMAT " bytes" 178 "\n\tUse -XX:PerfDataMemorySize=<size> to specify larger size.", 179 PerfMemory::capacity(), 180 PerfMemory::used(), 181 _prologue->overflow); 182 } 183 } 184 185 if (_start != NULL) { 186 187 // this state indicates that the contiguous memory region was successfully 188 // and that persistent resources may need to be cleaned up. This is 189 // expected to be the typical condition. 190 // 191 delete_memory_region(); 192 } 193 194 _start = NULL; 195 _end = NULL; 196 _top = NULL; 197 _prologue = NULL; 198 _capacity = 0; 199 } 200 201 // allocate an aligned block of memory from the PerfData memory 202 // region. This method assumes that the PerfData memory region 203 // was aligned on a double word boundary when created. 204 // 205 char* PerfMemory::alloc(size_t size) { 206 207 if (!UsePerfData) return NULL; 208 209 MutexLocker ml(PerfDataMemAlloc_lock); 210 211 assert(_prologue != NULL, "called before initialization"); 212 213 // check that there is enough memory for this request 214 if ((_top + size) >= _end) { 215 216 _prologue->overflow += (jint)size; 217 218 return NULL; 219 } 220 221 char* result = _top; 222 223 _top += size; 224 225 assert(contains(result), "PerfData memory pointer out of range"); 226 227 _prologue->used = (jint)used(); 228 _prologue->num_entries = _prologue->num_entries + 1; 229 230 return result; 231 } 232 233 void PerfMemory::mark_updated() { 234 if (!UsePerfData) return; 235 236 _prologue->mod_time_stamp = os::elapsed_counter(); 237 } 238 239 // Returns the complete path including the file name of performance data file. 240 // Caller is expected to release the allocated memory. 241 char* PerfMemory::get_perfdata_file_path() { 242 char* dest_file = NULL; 243 244 if (PerfDataSaveFile != NULL) { 245 // dest_file_name stores the validated file name if file_name 246 // contains %p which will be replaced by pid. 247 dest_file = NEW_C_HEAP_ARRAY(char, JVM_MAXPATHLEN); 248 if(!Arguments::copy_expand_pid(PerfDataSaveFile, strlen(PerfDataSaveFile), 249 dest_file, JVM_MAXPATHLEN)) { 250 FREE_C_HEAP_ARRAY(char, dest_file); 251 if (PrintMiscellaneous && Verbose) { 252 warning("Invalid performance data file path name specified, "\ 253 "fall back to a default name"); 254 } 255 } else { 256 return dest_file; 257 } 258 } 259 // create the name of the file for retaining the instrumentation memory. 260 dest_file = NEW_C_HEAP_ARRAY(char, PERFDATA_FILENAME_LEN); 261 jio_snprintf(dest_file, PERFDATA_FILENAME_LEN, 262 "%s_%d", PERFDATA_NAME, os::current_process_id()); 263 264 return dest_file; 265 }