1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018, 2019 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 #include "code/codeHeapState.hpp" 28 #include "compiler/compileBroker.hpp" 29 #include "runtime/safepoint.hpp" 30 #include "runtime/sweeper.hpp" 31 32 // ------------------------- 33 // | General Description | 34 // ------------------------- 35 // The CodeHeap state analytics are divided in two parts. 36 // The first part examines the entire CodeHeap and aggregates all 37 // information that is believed useful/important. 38 // 39 // Aggregation condenses the information of a piece of the CodeHeap 40 // (4096 bytes by default) into an analysis granule. These granules 41 // contain enough detail to gain initial insight while keeping the 42 // internal structure sizes in check. 43 // 44 // The second part, which consists of several, independent steps, 45 // prints the previously collected information with emphasis on 46 // various aspects. 47 // 48 // The CodeHeap is a living thing. Therefore, protection against concurrent 49 // modification (by acquiring the CodeCache_lock) is necessary. It has 50 // to be provided by the caller of the analysis functions. 51 // If the CodeCache_lock is not held, the analysis functions may print 52 // less detailed information or may just do nothing. It is by intention 53 // that an unprotected invocation is not abnormally terminated. 54 // 55 // Data collection and printing is done on an "on request" basis. 56 // While no request is being processed, there is no impact on performance. 57 // The CodeHeap state analytics do have some memory footprint. 58 // The "aggregate" step allocates some data structures to hold the aggregated 59 // information for later output. These data structures live until they are 60 // explicitly discarded (function "discard") or until the VM terminates. 61 // There is one exception: the function "all" does not leave any data 62 // structures allocated. 63 // 64 // Requests for real-time, on-the-fly analysis can be issued via 65 // jcmd <pid> Compiler.CodeHeap_Analytics [<function>] [<granularity>] 66 // 67 // If you are (only) interested in how the CodeHeap looks like after running 68 // a sample workload, you can use the command line option 69 // -XX:+PrintCodeHeapAnalytics 70 // It will cause a full analysis to be written to tty. In addition, a full 71 // analysis will be written the first time a "CodeCache full" condition is 72 // detected. 73 // 74 // The command line option produces output identical to the jcmd function 75 // jcmd <pid> Compiler.CodeHeap_Analytics all 4096 76 // --------------------------------------------------------------------------------- 77 78 // With this declaration macro, it is possible to switch between 79 // - direct output into an argument-passed outputStream and 80 // - buffered output into a bufferedStream with subsequent flush 81 // of the filled buffer to the outputStream. 82 #define USE_BUFFEREDSTREAM 83 84 // There are instances when composing an output line or a small set of 85 // output lines out of many tty->print() calls creates significant overhead. 86 // Writing to a bufferedStream buffer first has a significant advantage: 87 // It uses noticeably less cpu cycles and reduces (when writing to a 88 // network file) the required bandwidth by at least a factor of ten. Observed on MacOS. 89 // That clearly makes up for the increased code complexity. 90 // 91 // Conversion of existing code is easy and straightforward, if the code already 92 // uses a parameterized output destination, e.g. "outputStream st". 93 // - rename the formal parameter to any other name, e.g. out_st. 94 // - at a suitable place in your code, insert 95 // BUFFEREDSTEAM_DECL(buf_st, out_st) 96 // This will provide all the declarations necessary. After that, all 97 // buf_st->print() (and the like) calls will be directed to a bufferedStream object. 98 // Once a block of output (a line or a small set of lines) is composed, insert 99 // BUFFEREDSTREAM_FLUSH(termstring) 100 // to flush the bufferedStream to the final destination out_st. termstring is just 101 // an arbitrary string (e.g. "\n") which is appended to the bufferedStream before 102 // being written to out_st. Be aware that the last character written MUST be a '\n'. 103 // Otherwise, buf_st->position() does not correspond to out_st->position() any longer. 104 // BUFFEREDSTREAM_FLUSH_LOCKED(termstring) 105 // does the same thing, protected by the ttyLocker lock. 106 // BUFFEREDSTREAM_FLUSH_IF(termstring, remSize) 107 // does a flush only if the remaining buffer space is less than remSize. 108 // 109 // To activate, #define USE_BUFFERED_STREAM before including this header. 110 // If not activated, output will directly go to the originally used outputStream 111 // with no additional overhead. 112 // 113 #if defined(USE_BUFFEREDSTREAM) 114 // All necessary declarations to print via a bufferedStream 115 // This macro must be placed before any other BUFFEREDSTREAM* 116 // macro in the function. 117 #define BUFFEREDSTREAM_DECL_SIZE(_anyst, _outst, _capa) \ 118 ResourceMark _rm; \ 119 /* _anyst name of the stream as used in the code */ \ 120 /* _outst stream where final output will go to */ \ 121 /* _capa allocated capacity of stream buffer */ \ 122 size_t _nflush = 0; \ 123 size_t _nforcedflush = 0; \ 124 size_t _nsavedflush = 0; \ 125 size_t _nlockedflush = 0; \ 126 size_t _nflush_bytes = 0; \ 127 size_t _capacity = _capa; \ 128 bufferedStream _sstobj(_capa); \ 129 bufferedStream* _sstbuf = &_sstobj; \ 130 outputStream* _outbuf = _outst; \ 131 bufferedStream* _anyst = &_sstobj; /* any stream. Use this to just print - no buffer flush. */ 132 133 // Same as above, but with fixed buffer size. 134 #define BUFFEREDSTREAM_DECL(_anyst, _outst) \ 135 BUFFEREDSTREAM_DECL_SIZE(_anyst, _outst, 4*K); 136 137 // Flush the buffer contents unconditionally. 138 // No action if the buffer is empty. 139 #define BUFFEREDSTREAM_FLUSH(_termString) \ 140 if (((_termString) != NULL) && (strlen(_termString) > 0)){\ 141 _sstbuf->print("%s", _termString); \ 142 } \ 143 if (_sstbuf != _outbuf) { \ 144 if (_sstbuf->size() != 0) { \ 145 _nforcedflush++; _nflush_bytes += _sstbuf->size(); \ 146 _outbuf->print("%s", _sstbuf->as_string()); \ 147 _sstbuf->reset(); \ 148 } \ 149 } 150 151 // Flush the buffer contents if the remaining capacity is 152 // less than the given threshold. 153 #define BUFFEREDSTREAM_FLUSH_IF(_termString, _remSize) \ 154 if (((_termString) != NULL) && (strlen(_termString) > 0)){\ 155 _sstbuf->print("%s", _termString); \ 156 } \ 157 if (_sstbuf != _outbuf) { \ 158 if ((_capacity - _sstbuf->size()) < (size_t)(_remSize)){\ 159 _nflush++; _nforcedflush--; \ 160 BUFFEREDSTREAM_FLUSH("") \ 161 } else { \ 162 _nsavedflush++; \ 163 } \ 164 } 165 166 // Flush the buffer contents if the remaining capacity is less 167 // than the calculated threshold (256 bytes + capacity/16) 168 // That should suffice for all reasonably sized output lines. 169 #define BUFFEREDSTREAM_FLUSH_AUTO(_termString) \ 170 BUFFEREDSTREAM_FLUSH_IF(_termString, 256+(_capacity>>4)) 171 172 #define BUFFEREDSTREAM_FLUSH_LOCKED(_termString) \ 173 { ttyLocker ttyl;/* keep this output block together */ \ 174 _nlockedflush++; \ 175 BUFFEREDSTREAM_FLUSH(_termString) \ 176 } 177 178 // #define BUFFEREDSTREAM_FLUSH_STAT() \ 179 // if (_sstbuf != _outbuf) { \ 180 // _outbuf->print_cr("%ld flushes (buffer full), %ld forced, %ld locked, %ld bytes total, %ld flushes saved", _nflush, _nforcedflush, _nlockedflush, _nflush_bytes, _nsavedflush); \ 181 // } 182 183 #define BUFFEREDSTREAM_FLUSH_STAT() 184 #else 185 #define BUFFEREDSTREAM_DECL_SIZE(_anyst, _outst, _capa) \ 186 size_t _capacity = _capa; \ 187 outputStream* _outbuf = _outst; \ 188 outputStream* _anyst = _outst; /* any stream. Use this to just print - no buffer flush. */ 189 190 #define BUFFEREDSTREAM_DECL(_anyst, _outst) \ 191 BUFFEREDSTREAM_DECL_SIZE(_anyst, _outst, 4*K) 192 193 #define BUFFEREDSTREAM_FLUSH(_termString) \ 194 if (((_termString) != NULL) && (strlen(_termString) > 0)){\ 195 _outbuf->print("%s", _termString); \ 196 } 197 198 #define BUFFEREDSTREAM_FLUSH_IF(_termString, _remSize) \ 199 BUFFEREDSTREAM_FLUSH(_termString) 200 201 #define BUFFEREDSTREAM_FLUSH_AUTO(_termString) \ 202 BUFFEREDSTREAM_FLUSH(_termString) 203 204 #define BUFFEREDSTREAM_FLUSH_LOCKED(_termString) \ 205 BUFFEREDSTREAM_FLUSH(_termString) 206 207 #define BUFFEREDSTREAM_FLUSH_STAT() 208 #endif 209 #define HEX32_FORMAT "0x%x" // just a helper format string used below multiple times 210 211 const char blobTypeChar[] = {' ', 'C', 'N', 'I', 'X', 'Z', 'U', 'R', '?', 'D', 'T', 'E', 'S', 'A', 'M', 'B', 'L' }; 212 const char* blobTypeName[] = {"noType" 213 , "nMethod (under construction), cannot be observed" 214 , "nMethod (active)" 215 , "nMethod (inactive)" 216 , "nMethod (deopt)" 217 , "nMethod (zombie)" 218 , "nMethod (unloaded)" 219 , "runtime stub" 220 , "ricochet stub" 221 , "deopt stub" 222 , "uncommon trap stub" 223 , "exception stub" 224 , "safepoint stub" 225 , "adapter blob" 226 , "MH adapter blob" 227 , "buffer blob" 228 , "lastType" 229 }; 230 const char* compTypeName[] = { "none", "c1", "c2", "jvmci" }; 231 232 // Be prepared for ten different CodeHeap segments. Should be enough for a few years. 233 const unsigned int nSizeDistElements = 31; // logarithmic range growth, max size: 2**32 234 const unsigned int maxTopSizeBlocks = 100; 235 const unsigned int tsbStopper = 2 * maxTopSizeBlocks; 236 const unsigned int maxHeaps = 10; 237 static unsigned int nHeaps = 0; 238 static struct CodeHeapStat CodeHeapStatArray[maxHeaps]; 239 240 // static struct StatElement *StatArray = NULL; 241 static StatElement* StatArray = NULL; 242 static int log2_seg_size = 0; 243 static size_t seg_size = 0; 244 static size_t alloc_granules = 0; 245 static size_t granule_size = 0; 246 static bool segment_granules = false; 247 static unsigned int nBlocks_t1 = 0; // counting "in_use" nmethods only. 248 static unsigned int nBlocks_t2 = 0; // counting "in_use" nmethods only. 249 static unsigned int nBlocks_alive = 0; // counting "not_used" and "not_entrant" nmethods only. 250 static unsigned int nBlocks_dead = 0; // counting "zombie" and "unloaded" methods only. 251 static unsigned int nBlocks_unloaded = 0; // counting "unloaded" nmethods only. This is a transient state. 252 static unsigned int nBlocks_stub = 0; 253 254 static struct FreeBlk* FreeArray = NULL; 255 static unsigned int alloc_freeBlocks = 0; 256 257 static struct TopSizeBlk* TopSizeArray = NULL; 258 static unsigned int alloc_topSizeBlocks = 0; 259 static unsigned int used_topSizeBlocks = 0; 260 261 static struct SizeDistributionElement* SizeDistributionArray = NULL; 262 263 // nMethod temperature (hotness) indicators. 264 static int avgTemp = 0; 265 static int maxTemp = 0; 266 static int minTemp = 0; 267 268 static unsigned int latest_compilation_id = 0; 269 static volatile bool initialization_complete = false; 270 271 const char* CodeHeapState::get_heapName(CodeHeap* heap) { 272 if (SegmentedCodeCache) { 273 return heap->name(); 274 } else { 275 return "CodeHeap"; 276 } 277 } 278 279 // returns the index for the heap being processed. 280 unsigned int CodeHeapState::findHeapIndex(outputStream* out, const char* heapName) { 281 if (heapName == NULL) { 282 return maxHeaps; 283 } 284 if (SegmentedCodeCache) { 285 // Search for a pre-existing entry. If found, return that index. 286 for (unsigned int i = 0; i < nHeaps; i++) { 287 if (CodeHeapStatArray[i].heapName != NULL && strcmp(heapName, CodeHeapStatArray[i].heapName) == 0) { 288 return i; 289 } 290 } 291 292 // check if there are more code heap segments than we can handle. 293 if (nHeaps == maxHeaps) { 294 out->print_cr("Too many heap segments for current limit(%d).", maxHeaps); 295 return maxHeaps; 296 } 297 298 // allocate new slot in StatArray. 299 CodeHeapStatArray[nHeaps].heapName = heapName; 300 return nHeaps++; 301 } else { 302 nHeaps = 1; 303 CodeHeapStatArray[0].heapName = heapName; 304 return 0; // This is the default index if CodeCache is not segmented. 305 } 306 } 307 308 void CodeHeapState::get_HeapStatGlobals(outputStream* out, const char* heapName) { 309 unsigned int ix = findHeapIndex(out, heapName); 310 if (ix < maxHeaps) { 311 StatArray = CodeHeapStatArray[ix].StatArray; 312 seg_size = CodeHeapStatArray[ix].segment_size; 313 log2_seg_size = seg_size == 0 ? 0 : exact_log2(seg_size); 314 alloc_granules = CodeHeapStatArray[ix].alloc_granules; 315 granule_size = CodeHeapStatArray[ix].granule_size; 316 segment_granules = CodeHeapStatArray[ix].segment_granules; 317 nBlocks_t1 = CodeHeapStatArray[ix].nBlocks_t1; 318 nBlocks_t2 = CodeHeapStatArray[ix].nBlocks_t2; 319 nBlocks_alive = CodeHeapStatArray[ix].nBlocks_alive; 320 nBlocks_dead = CodeHeapStatArray[ix].nBlocks_dead; 321 nBlocks_unloaded = CodeHeapStatArray[ix].nBlocks_unloaded; 322 nBlocks_stub = CodeHeapStatArray[ix].nBlocks_stub; 323 FreeArray = CodeHeapStatArray[ix].FreeArray; 324 alloc_freeBlocks = CodeHeapStatArray[ix].alloc_freeBlocks; 325 TopSizeArray = CodeHeapStatArray[ix].TopSizeArray; 326 alloc_topSizeBlocks = CodeHeapStatArray[ix].alloc_topSizeBlocks; 327 used_topSizeBlocks = CodeHeapStatArray[ix].used_topSizeBlocks; 328 SizeDistributionArray = CodeHeapStatArray[ix].SizeDistributionArray; 329 avgTemp = CodeHeapStatArray[ix].avgTemp; 330 maxTemp = CodeHeapStatArray[ix].maxTemp; 331 minTemp = CodeHeapStatArray[ix].minTemp; 332 } else { 333 StatArray = NULL; 334 seg_size = 0; 335 log2_seg_size = 0; 336 alloc_granules = 0; 337 granule_size = 0; 338 segment_granules = false; 339 nBlocks_t1 = 0; 340 nBlocks_t2 = 0; 341 nBlocks_alive = 0; 342 nBlocks_dead = 0; 343 nBlocks_unloaded = 0; 344 nBlocks_stub = 0; 345 FreeArray = NULL; 346 alloc_freeBlocks = 0; 347 TopSizeArray = NULL; 348 alloc_topSizeBlocks = 0; 349 used_topSizeBlocks = 0; 350 SizeDistributionArray = NULL; 351 avgTemp = 0; 352 maxTemp = 0; 353 minTemp = 0; 354 } 355 } 356 357 void CodeHeapState::set_HeapStatGlobals(outputStream* out, const char* heapName) { 358 unsigned int ix = findHeapIndex(out, heapName); 359 if (ix < maxHeaps) { 360 CodeHeapStatArray[ix].StatArray = StatArray; 361 CodeHeapStatArray[ix].segment_size = seg_size; 362 CodeHeapStatArray[ix].alloc_granules = alloc_granules; 363 CodeHeapStatArray[ix].granule_size = granule_size; 364 CodeHeapStatArray[ix].segment_granules = segment_granules; 365 CodeHeapStatArray[ix].nBlocks_t1 = nBlocks_t1; 366 CodeHeapStatArray[ix].nBlocks_t2 = nBlocks_t2; 367 CodeHeapStatArray[ix].nBlocks_alive = nBlocks_alive; 368 CodeHeapStatArray[ix].nBlocks_dead = nBlocks_dead; 369 CodeHeapStatArray[ix].nBlocks_unloaded = nBlocks_unloaded; 370 CodeHeapStatArray[ix].nBlocks_stub = nBlocks_stub; 371 CodeHeapStatArray[ix].FreeArray = FreeArray; 372 CodeHeapStatArray[ix].alloc_freeBlocks = alloc_freeBlocks; 373 CodeHeapStatArray[ix].TopSizeArray = TopSizeArray; 374 CodeHeapStatArray[ix].alloc_topSizeBlocks = alloc_topSizeBlocks; 375 CodeHeapStatArray[ix].used_topSizeBlocks = used_topSizeBlocks; 376 CodeHeapStatArray[ix].SizeDistributionArray = SizeDistributionArray; 377 CodeHeapStatArray[ix].avgTemp = avgTemp; 378 CodeHeapStatArray[ix].maxTemp = maxTemp; 379 CodeHeapStatArray[ix].minTemp = minTemp; 380 } 381 } 382 383 //---< get a new statistics array >--- 384 void CodeHeapState::prepare_StatArray(outputStream* out, size_t nElem, size_t granularity, const char* heapName) { 385 if (StatArray == NULL) { 386 StatArray = new StatElement[nElem]; 387 //---< reset some counts >--- 388 alloc_granules = nElem; 389 granule_size = granularity; 390 } 391 392 if (StatArray == NULL) { 393 //---< just do nothing if allocation failed >--- 394 out->print_cr("Statistics could not be collected for %s, probably out of memory.", heapName); 395 out->print_cr("Current granularity is " SIZE_FORMAT " bytes. Try a coarser granularity.", granularity); 396 alloc_granules = 0; 397 granule_size = 0; 398 } else { 399 //---< initialize statistics array >--- 400 memset((void*)StatArray, 0, nElem*sizeof(StatElement)); 401 } 402 } 403 404 //---< get a new free block array >--- 405 void CodeHeapState::prepare_FreeArray(outputStream* out, unsigned int nElem, const char* heapName) { 406 if (FreeArray == NULL) { 407 FreeArray = new FreeBlk[nElem]; 408 //---< reset some counts >--- 409 alloc_freeBlocks = nElem; 410 } 411 412 if (FreeArray == NULL) { 413 //---< just do nothing if allocation failed >--- 414 out->print_cr("Free space analysis cannot be done for %s, probably out of memory.", heapName); 415 alloc_freeBlocks = 0; 416 } else { 417 //---< initialize free block array >--- 418 memset((void*)FreeArray, 0, alloc_freeBlocks*sizeof(FreeBlk)); 419 } 420 } 421 422 //---< get a new TopSizeArray >--- 423 void CodeHeapState::prepare_TopSizeArray(outputStream* out, unsigned int nElem, const char* heapName) { 424 if (TopSizeArray == NULL) { 425 TopSizeArray = new TopSizeBlk[nElem]; 426 //---< reset some counts >--- 427 alloc_topSizeBlocks = nElem; 428 used_topSizeBlocks = 0; 429 } 430 431 if (TopSizeArray == NULL) { 432 //---< just do nothing if allocation failed >--- 433 out->print_cr("Top-%d list of largest CodeHeap blocks can not be collected for %s, probably out of memory.", nElem, heapName); 434 alloc_topSizeBlocks = 0; 435 } else { 436 //---< initialize TopSizeArray >--- 437 memset((void*)TopSizeArray, 0, nElem*sizeof(TopSizeBlk)); 438 used_topSizeBlocks = 0; 439 } 440 } 441 442 //---< get a new SizeDistributionArray >--- 443 void CodeHeapState::prepare_SizeDistArray(outputStream* out, unsigned int nElem, const char* heapName) { 444 if (SizeDistributionArray == NULL) { 445 SizeDistributionArray = new SizeDistributionElement[nElem]; 446 } 447 448 if (SizeDistributionArray == NULL) { 449 //---< just do nothing if allocation failed >--- 450 out->print_cr("Size distribution can not be collected for %s, probably out of memory.", heapName); 451 } else { 452 //---< initialize SizeDistArray >--- 453 memset((void*)SizeDistributionArray, 0, nElem*sizeof(SizeDistributionElement)); 454 // Logarithmic range growth. First range starts at _segment_size. 455 SizeDistributionArray[log2_seg_size-1].rangeEnd = 1U; 456 for (unsigned int i = log2_seg_size; i < nElem; i++) { 457 SizeDistributionArray[i].rangeStart = 1U << (i - log2_seg_size); 458 SizeDistributionArray[i].rangeEnd = 1U << ((i+1) - log2_seg_size); 459 } 460 } 461 } 462 463 //---< get a new SizeDistributionArray >--- 464 void CodeHeapState::update_SizeDistArray(outputStream* out, unsigned int len) { 465 if (SizeDistributionArray != NULL) { 466 for (unsigned int i = log2_seg_size-1; i < nSizeDistElements; i++) { 467 if ((SizeDistributionArray[i].rangeStart <= len) && (len < SizeDistributionArray[i].rangeEnd)) { 468 SizeDistributionArray[i].lenSum += len; 469 SizeDistributionArray[i].count++; 470 break; 471 } 472 } 473 } 474 } 475 476 void CodeHeapState::discard_StatArray(outputStream* out) { 477 if (StatArray != NULL) { 478 delete StatArray; 479 StatArray = NULL; 480 alloc_granules = 0; 481 granule_size = 0; 482 } 483 } 484 485 void CodeHeapState::discard_FreeArray(outputStream* out) { 486 if (FreeArray != NULL) { 487 delete[] FreeArray; 488 FreeArray = NULL; 489 alloc_freeBlocks = 0; 490 } 491 } 492 493 void CodeHeapState::discard_TopSizeArray(outputStream* out) { 494 if (TopSizeArray != NULL) { 495 for (unsigned int i = 0; i < alloc_topSizeBlocks; i++) { 496 if (TopSizeArray[i].blob_name != NULL) { 497 os::free((void*)TopSizeArray[i].blob_name); 498 } 499 } 500 delete[] TopSizeArray; 501 TopSizeArray = NULL; 502 alloc_topSizeBlocks = 0; 503 used_topSizeBlocks = 0; 504 } 505 } 506 507 void CodeHeapState::discard_SizeDistArray(outputStream* out) { 508 if (SizeDistributionArray != NULL) { 509 delete[] SizeDistributionArray; 510 SizeDistributionArray = NULL; 511 } 512 } 513 514 // Discard all allocated internal data structures. 515 // This should be done after an analysis session is completed. 516 void CodeHeapState::discard(outputStream* out, CodeHeap* heap) { 517 if (!initialization_complete) { 518 return; 519 } 520 521 if (nHeaps > 0) { 522 for (unsigned int ix = 0; ix < nHeaps; ix++) { 523 get_HeapStatGlobals(out, CodeHeapStatArray[ix].heapName); 524 discard_StatArray(out); 525 discard_FreeArray(out); 526 discard_TopSizeArray(out); 527 discard_SizeDistArray(out); 528 set_HeapStatGlobals(out, CodeHeapStatArray[ix].heapName); 529 CodeHeapStatArray[ix].heapName = NULL; 530 } 531 nHeaps = 0; 532 } 533 } 534 535 void CodeHeapState::aggregate(outputStream* out, CodeHeap* heap, size_t granularity) { 536 unsigned int nBlocks_free = 0; 537 unsigned int nBlocks_used = 0; 538 unsigned int nBlocks_zomb = 0; 539 unsigned int nBlocks_disconn = 0; 540 unsigned int nBlocks_notentr = 0; 541 542 //---< max & min of TopSizeArray >--- 543 // it is sufficient to have these sizes as 32bit unsigned ints. 544 // The CodeHeap is limited in size to 4GB. Furthermore, the sizes 545 // are stored in _segment_size units, scaling them down by a factor of 64 (at least). 546 unsigned int currMax = 0; 547 unsigned int currMin = 0; 548 unsigned int currMin_ix = 0; 549 unsigned long total_iterations = 0; 550 551 bool done = false; 552 const int min_granules = 256; 553 const int max_granules = 512*K; // limits analyzable CodeHeap (with segment_granules) to 32M..128M 554 // results in StatArray size of 24M (= max_granules * 48 Bytes per element) 555 // For a 1GB CodeHeap, the granule size must be at least 2kB to not violate the max_granles limit. 556 const char* heapName = get_heapName(heap); 557 BUFFEREDSTREAM_DECL(ast, out) 558 559 if (!initialization_complete) { 560 memset(CodeHeapStatArray, 0, sizeof(CodeHeapStatArray)); 561 initialization_complete = true; 562 563 printBox(ast, '=', "C O D E H E A P A N A L Y S I S (general remarks)", NULL); 564 ast->print_cr(" The code heap analysis function provides deep insights into\n" 565 " the inner workings and the internal state of the Java VM's\n" 566 " code cache - the place where all the JVM generated machine\n" 567 " code is stored.\n" 568 " \n" 569 " This function is designed and provided for support engineers\n" 570 " to help them understand and solve issues in customer systems.\n" 571 " It is not intended for use and interpretation by other persons.\n" 572 " \n"); 573 BUFFEREDSTREAM_FLUSH("") 574 } 575 get_HeapStatGlobals(out, heapName); 576 577 578 // Since we are (and must be) analyzing the CodeHeap contents under the CodeCache_lock, 579 // all heap information is "constant" and can be safely extracted/calculated before we 580 // enter the while() loop. Actually, the loop will only be iterated once. 581 char* low_bound = heap->low_boundary(); 582 size_t size = heap->capacity(); 583 size_t res_size = heap->max_capacity(); 584 seg_size = heap->segment_size(); 585 log2_seg_size = seg_size == 0 ? 0 : exact_log2(seg_size); // This is a global static value. 586 587 if (seg_size == 0) { 588 printBox(ast, '-', "Heap not fully initialized yet, segment size is zero for segment ", heapName); 589 BUFFEREDSTREAM_FLUSH("") 590 return; 591 } 592 593 if (!holding_required_locks()) { 594 printBox(ast, '-', "Must be at safepoint or hold Compile_lock and CodeCache_lock when calling aggregate function for ", heapName); 595 BUFFEREDSTREAM_FLUSH("") 596 return; 597 } 598 599 // Calculate granularity of analysis (and output). 600 // The CodeHeap is managed (allocated) in segments (units) of CodeCacheSegmentSize. 601 // The CodeHeap can become fairly large, in particular in productive real-life systems. 602 // 603 // It is often neither feasible nor desirable to aggregate the data with the highest possible 604 // level of detail, i.e. inspecting and printing each segment on its own. 605 // 606 // The granularity parameter allows to specify the level of detail available in the analysis. 607 // It must be a positive multiple of the segment size and should be selected such that enough 608 // detail is provided while, at the same time, the printed output does not explode. 609 // 610 // By manipulating the granularity value, we enforce that at least min_granules units 611 // of analysis are available. We also enforce an upper limit of max_granules units to 612 // keep the amount of allocated storage in check. 613 // 614 // Finally, we adjust the granularity such that each granule covers at most 64k-1 segments. 615 // This is necessary to prevent an unsigned short overflow while accumulating space information. 616 // 617 assert(granularity > 0, "granularity should be positive."); 618 619 if (granularity > size) { 620 granularity = size; 621 } 622 if (size/granularity < min_granules) { 623 granularity = size/min_granules; // at least min_granules granules 624 } 625 granularity = granularity & (~(seg_size - 1)); // must be multiple of seg_size 626 if (granularity < seg_size) { 627 granularity = seg_size; // must be at least seg_size 628 } 629 if (size/granularity > max_granules) { 630 granularity = size/max_granules; // at most max_granules granules 631 } 632 granularity = granularity & (~(seg_size - 1)); // must be multiple of seg_size 633 if (granularity>>log2_seg_size >= (1L<<sizeof(unsigned short)*8)) { 634 granularity = ((1L<<(sizeof(unsigned short)*8))-1)<<log2_seg_size; // Limit: (64k-1) * seg_size 635 } 636 segment_granules = granularity == seg_size; 637 size_t granules = (size + (granularity-1))/granularity; 638 639 printBox(ast, '=', "C O D E H E A P A N A L Y S I S (used blocks) for segment ", heapName); 640 ast->print_cr(" The aggregate step takes an aggregated snapshot of the CodeHeap.\n" 641 " Subsequent print functions create their output based on this snapshot.\n" 642 " The CodeHeap is a living thing, and every effort has been made for the\n" 643 " collected data to be consistent. Only the method names and signatures\n" 644 " are retrieved at print time. That may lead to rare cases where the\n" 645 " name of a method is no longer available, e.g. because it was unloaded.\n"); 646 ast->print_cr(" CodeHeap committed size " SIZE_FORMAT "K (" SIZE_FORMAT "M), reserved size " SIZE_FORMAT "K (" SIZE_FORMAT "M), %d%% occupied.", 647 size/(size_t)K, size/(size_t)M, res_size/(size_t)K, res_size/(size_t)M, (unsigned int)(100.0*size/res_size)); 648 ast->print_cr(" CodeHeap allocation segment size is " SIZE_FORMAT " bytes. This is the smallest possible granularity.", seg_size); 649 ast->print_cr(" CodeHeap (committed part) is mapped to " SIZE_FORMAT " granules of size " SIZE_FORMAT " bytes.", granules, granularity); 650 ast->print_cr(" Each granule takes " SIZE_FORMAT " bytes of C heap, that is " SIZE_FORMAT "K in total for statistics data.", sizeof(StatElement), (sizeof(StatElement)*granules)/(size_t)K); 651 ast->print_cr(" The number of granules is limited to %dk, requiring a granules size of at least %d bytes for a 1GB heap.", (unsigned int)(max_granules/K), (unsigned int)(G/max_granules)); 652 BUFFEREDSTREAM_FLUSH("\n") 653 654 655 while (!done) { 656 //---< reset counters with every aggregation >--- 657 nBlocks_t1 = 0; 658 nBlocks_t2 = 0; 659 nBlocks_alive = 0; 660 nBlocks_dead = 0; 661 nBlocks_unloaded = 0; 662 nBlocks_stub = 0; 663 664 nBlocks_free = 0; 665 nBlocks_used = 0; 666 nBlocks_zomb = 0; 667 nBlocks_disconn = 0; 668 nBlocks_notentr = 0; 669 670 //---< discard old arrays if size does not match >--- 671 if (granules != alloc_granules) { 672 discard_StatArray(out); 673 discard_TopSizeArray(out); 674 } 675 676 //---< allocate arrays if they don't yet exist, initialize >--- 677 prepare_StatArray(out, granules, granularity, heapName); 678 if (StatArray == NULL) { 679 set_HeapStatGlobals(out, heapName); 680 return; 681 } 682 prepare_TopSizeArray(out, maxTopSizeBlocks, heapName); 683 prepare_SizeDistArray(out, nSizeDistElements, heapName); 684 685 latest_compilation_id = CompileBroker::get_compilation_id(); 686 unsigned int highest_compilation_id = 0; 687 size_t usedSpace = 0; 688 size_t t1Space = 0; 689 size_t t2Space = 0; 690 size_t aliveSpace = 0; 691 size_t disconnSpace = 0; 692 size_t notentrSpace = 0; 693 size_t deadSpace = 0; 694 size_t unloadedSpace = 0; 695 size_t stubSpace = 0; 696 size_t freeSpace = 0; 697 size_t maxFreeSize = 0; 698 HeapBlock* maxFreeBlock = NULL; 699 bool insane = false; 700 701 int64_t hotnessAccumulator = 0; 702 unsigned int n_methods = 0; 703 avgTemp = 0; 704 minTemp = (int)(res_size > M ? (res_size/M)*2 : 1); 705 maxTemp = -minTemp; 706 707 for (HeapBlock *h = heap->first_block(); h != NULL && !insane; h = heap->next_block(h)) { 708 unsigned int hb_len = (unsigned int)h->length(); // despite being size_t, length can never overflow an unsigned int. 709 size_t hb_bytelen = ((size_t)hb_len)<<log2_seg_size; 710 unsigned int ix_beg = (unsigned int)(((char*)h-low_bound)/granule_size); 711 unsigned int ix_end = (unsigned int)(((char*)h-low_bound+(hb_bytelen-1))/granule_size); 712 unsigned int compile_id = 0; 713 CompLevel comp_lvl = CompLevel_none; 714 compType cType = noComp; 715 blobType cbType = noType; 716 717 //---< some sanity checks >--- 718 // Do not assert here, just check, print error message and return. 719 // This is a diagnostic function. It is not supposed to tear down the VM. 720 if ((char*)h < low_bound) { 721 insane = true; ast->print_cr("Sanity check: HeapBlock @%p below low bound (%p)", (char*)h, low_bound); 722 } 723 if ((char*)h > (low_bound + res_size)) { 724 insane = true; ast->print_cr("Sanity check: HeapBlock @%p outside reserved range (%p)", (char*)h, low_bound + res_size); 725 } 726 if ((char*)h > (low_bound + size)) { 727 insane = true; ast->print_cr("Sanity check: HeapBlock @%p outside used range (%p)", (char*)h, low_bound + size); 728 } 729 if (ix_end >= granules) { 730 insane = true; ast->print_cr("Sanity check: end index (%d) out of bounds (" SIZE_FORMAT ")", ix_end, granules); 731 } 732 if (size != heap->capacity()) { 733 insane = true; ast->print_cr("Sanity check: code heap capacity has changed (" SIZE_FORMAT "K to " SIZE_FORMAT "K)", size/(size_t)K, heap->capacity()/(size_t)K); 734 } 735 if (ix_beg > ix_end) { 736 insane = true; ast->print_cr("Sanity check: end index (%d) lower than begin index (%d)", ix_end, ix_beg); 737 } 738 if (insane) { 739 BUFFEREDSTREAM_FLUSH("") 740 continue; 741 } 742 743 if (h->free()) { 744 nBlocks_free++; 745 freeSpace += hb_bytelen; 746 if (hb_bytelen > maxFreeSize) { 747 maxFreeSize = hb_bytelen; 748 maxFreeBlock = h; 749 } 750 } else { 751 update_SizeDistArray(out, hb_len); 752 nBlocks_used++; 753 usedSpace += hb_bytelen; 754 CodeBlob* cb = (CodeBlob*)heap->find_start(h); 755 cbType = get_cbType(cb); // Will check for cb == NULL and other safety things. 756 if (cbType != noType) { 757 const char* blob_name = os::strdup(cb->name()); 758 unsigned int nm_size = 0; 759 int temperature = 0; 760 nmethod* nm = cb->as_nmethod_or_null(); 761 if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. 762 ResourceMark rm; 763 Method* method = nm->method(); 764 if (nm->is_in_use()) { 765 blob_name = os::strdup(method->name_and_sig_as_C_string()); 766 } 767 if (nm->is_not_entrant()) { 768 blob_name = os::strdup(method->name_and_sig_as_C_string()); 769 } 770 771 nm_size = nm->total_size(); 772 compile_id = nm->compile_id(); 773 comp_lvl = (CompLevel)(nm->comp_level()); 774 if (nm->is_compiled_by_c1()) { 775 cType = c1; 776 } 777 if (nm->is_compiled_by_c2()) { 778 cType = c2; 779 } 780 if (nm->is_compiled_by_jvmci()) { 781 cType = jvmci; 782 } 783 switch (cbType) { 784 case nMethod_inuse: { // only for executable methods!!! 785 // space for these cbs is accounted for later. 786 temperature = nm->hotness_counter(); 787 hotnessAccumulator += temperature; 788 n_methods++; 789 maxTemp = (temperature > maxTemp) ? temperature : maxTemp; 790 minTemp = (temperature < minTemp) ? temperature : minTemp; 791 break; 792 } 793 case nMethod_notused: 794 nBlocks_alive++; 795 nBlocks_disconn++; 796 aliveSpace += hb_bytelen; 797 disconnSpace += hb_bytelen; 798 break; 799 case nMethod_notentrant: // equivalent to nMethod_alive 800 nBlocks_alive++; 801 nBlocks_notentr++; 802 aliveSpace += hb_bytelen; 803 notentrSpace += hb_bytelen; 804 break; 805 case nMethod_unloaded: 806 nBlocks_unloaded++; 807 unloadedSpace += hb_bytelen; 808 break; 809 case nMethod_dead: 810 nBlocks_dead++; 811 deadSpace += hb_bytelen; 812 break; 813 default: 814 break; 815 } 816 } 817 818 //------------------------------------------ 819 //---< register block in TopSizeArray >--- 820 //------------------------------------------ 821 if (alloc_topSizeBlocks > 0) { 822 if (used_topSizeBlocks == 0) { 823 TopSizeArray[0].start = h; 824 TopSizeArray[0].blob_name = blob_name; 825 TopSizeArray[0].len = hb_len; 826 TopSizeArray[0].index = tsbStopper; 827 TopSizeArray[0].nm_size = nm_size; 828 TopSizeArray[0].temperature = temperature; 829 TopSizeArray[0].compiler = cType; 830 TopSizeArray[0].level = comp_lvl; 831 TopSizeArray[0].type = cbType; 832 currMax = hb_len; 833 currMin = hb_len; 834 currMin_ix = 0; 835 used_topSizeBlocks++; 836 blob_name = NULL; // indicate blob_name was consumed 837 // This check roughly cuts 5000 iterations (JVM98, mixed, dbg, termination stats): 838 } else if ((used_topSizeBlocks < alloc_topSizeBlocks) && (hb_len < currMin)) { 839 //---< all blocks in list are larger, but there is room left in array >--- 840 TopSizeArray[currMin_ix].index = used_topSizeBlocks; 841 TopSizeArray[used_topSizeBlocks].start = h; 842 TopSizeArray[used_topSizeBlocks].blob_name = blob_name; 843 TopSizeArray[used_topSizeBlocks].len = hb_len; 844 TopSizeArray[used_topSizeBlocks].index = tsbStopper; 845 TopSizeArray[used_topSizeBlocks].nm_size = nm_size; 846 TopSizeArray[used_topSizeBlocks].temperature = temperature; 847 TopSizeArray[used_topSizeBlocks].compiler = cType; 848 TopSizeArray[used_topSizeBlocks].level = comp_lvl; 849 TopSizeArray[used_topSizeBlocks].type = cbType; 850 currMin = hb_len; 851 currMin_ix = used_topSizeBlocks; 852 used_topSizeBlocks++; 853 blob_name = NULL; // indicate blob_name was consumed 854 } else { 855 // This check cuts total_iterations by a factor of 6 (JVM98, mixed, dbg, termination stats): 856 // We don't need to search the list if we know beforehand that the current block size is 857 // smaller than the currently recorded minimum and there is no free entry left in the list. 858 if (!((used_topSizeBlocks == alloc_topSizeBlocks) && (hb_len <= currMin))) { 859 if (currMax < hb_len) { 860 currMax = hb_len; 861 } 862 unsigned int i; 863 unsigned int prev_i = tsbStopper; 864 unsigned int limit_i = 0; 865 for (i = 0; i != tsbStopper; i = TopSizeArray[i].index) { 866 if (limit_i++ >= alloc_topSizeBlocks) { 867 insane = true; break; // emergency exit 868 } 869 if (i >= used_topSizeBlocks) { 870 insane = true; break; // emergency exit 871 } 872 total_iterations++; 873 if (TopSizeArray[i].len < hb_len) { 874 //---< We want to insert here, element <i> is smaller than the current one >--- 875 if (used_topSizeBlocks < alloc_topSizeBlocks) { // still room for a new entry to insert 876 // old entry gets moved to the next free element of the array. 877 // That's necessary to keep the entry for the largest block at index 0. 878 // This move might cause the current minimum to be moved to another place 879 if (i == currMin_ix) { 880 assert(TopSizeArray[i].len == currMin, "sort error"); 881 currMin_ix = used_topSizeBlocks; 882 } 883 memcpy((void*)&TopSizeArray[used_topSizeBlocks], (void*)&TopSizeArray[i], sizeof(TopSizeBlk)); 884 TopSizeArray[i].start = h; 885 TopSizeArray[i].blob_name = blob_name; 886 TopSizeArray[i].len = hb_len; 887 TopSizeArray[i].index = used_topSizeBlocks; 888 TopSizeArray[i].nm_size = nm_size; 889 TopSizeArray[i].temperature = temperature; 890 TopSizeArray[i].compiler = cType; 891 TopSizeArray[i].level = comp_lvl; 892 TopSizeArray[i].type = cbType; 893 used_topSizeBlocks++; 894 blob_name = NULL; // indicate blob_name was consumed 895 } else { // no room for new entries, current block replaces entry for smallest block 896 //---< Find last entry (entry for smallest remembered block) >--- 897 // We either want to insert right before the smallest entry, which is when <i> 898 // indexes the smallest entry. We then just overwrite the smallest entry. 899 // What's more likely: 900 // We want to insert somewhere in the list. The smallest entry (@<j>) then falls off the cliff. 901 // The element at the insert point <i> takes it's slot. The second-smallest entry now becomes smallest. 902 // Data of the current block is filled in at index <i>. 903 unsigned int j = i; 904 unsigned int prev_j = tsbStopper; 905 unsigned int limit_j = 0; 906 while (TopSizeArray[j].index != tsbStopper) { 907 if (limit_j++ >= alloc_topSizeBlocks) { 908 insane = true; break; // emergency exit 909 } 910 if (j >= used_topSizeBlocks) { 911 insane = true; break; // emergency exit 912 } 913 total_iterations++; 914 prev_j = j; 915 j = TopSizeArray[j].index; 916 } 917 if (!insane) { 918 if (TopSizeArray[j].blob_name != NULL) { 919 os::free((void*)TopSizeArray[j].blob_name); 920 } 921 if (prev_j == tsbStopper) { 922 //---< Above while loop did not iterate, we already are the min entry >--- 923 //---< We have to just replace the smallest entry >--- 924 currMin = hb_len; 925 currMin_ix = j; 926 TopSizeArray[j].start = h; 927 TopSizeArray[j].blob_name = blob_name; 928 TopSizeArray[j].len = hb_len; 929 TopSizeArray[j].index = tsbStopper; // already set!! 930 TopSizeArray[i].nm_size = nm_size; 931 TopSizeArray[i].temperature = temperature; 932 TopSizeArray[j].compiler = cType; 933 TopSizeArray[j].level = comp_lvl; 934 TopSizeArray[j].type = cbType; 935 } else { 936 //---< second-smallest entry is now smallest >--- 937 TopSizeArray[prev_j].index = tsbStopper; 938 currMin = TopSizeArray[prev_j].len; 939 currMin_ix = prev_j; 940 //---< previously smallest entry gets overwritten >--- 941 memcpy((void*)&TopSizeArray[j], (void*)&TopSizeArray[i], sizeof(TopSizeBlk)); 942 TopSizeArray[i].start = h; 943 TopSizeArray[i].blob_name = blob_name; 944 TopSizeArray[i].len = hb_len; 945 TopSizeArray[i].index = j; 946 TopSizeArray[i].nm_size = nm_size; 947 TopSizeArray[i].temperature = temperature; 948 TopSizeArray[i].compiler = cType; 949 TopSizeArray[i].level = comp_lvl; 950 TopSizeArray[i].type = cbType; 951 } 952 blob_name = NULL; // indicate blob_name was consumed 953 } // insane 954 } 955 break; 956 } 957 prev_i = i; 958 } 959 if (insane) { 960 // Note: regular analysis could probably continue by resetting "insane" flag. 961 out->print_cr("Possible loop in TopSizeBlocks list detected. Analysis aborted."); 962 discard_TopSizeArray(out); 963 } 964 } 965 } 966 } 967 if (blob_name != NULL) { 968 os::free((void*)blob_name); 969 blob_name = NULL; 970 } 971 //---------------------------------------------- 972 //---< END register block in TopSizeArray >--- 973 //---------------------------------------------- 974 } else { 975 nBlocks_zomb++; 976 } 977 978 if (ix_beg == ix_end) { 979 StatArray[ix_beg].type = cbType; 980 switch (cbType) { 981 case nMethod_inuse: 982 highest_compilation_id = (highest_compilation_id >= compile_id) ? highest_compilation_id : compile_id; 983 if (comp_lvl < CompLevel_full_optimization) { 984 nBlocks_t1++; 985 t1Space += hb_bytelen; 986 StatArray[ix_beg].t1_count++; 987 StatArray[ix_beg].t1_space += (unsigned short)hb_len; 988 StatArray[ix_beg].t1_age = StatArray[ix_beg].t1_age < compile_id ? compile_id : StatArray[ix_beg].t1_age; 989 } else { 990 nBlocks_t2++; 991 t2Space += hb_bytelen; 992 StatArray[ix_beg].t2_count++; 993 StatArray[ix_beg].t2_space += (unsigned short)hb_len; 994 StatArray[ix_beg].t2_age = StatArray[ix_beg].t2_age < compile_id ? compile_id : StatArray[ix_beg].t2_age; 995 } 996 StatArray[ix_beg].level = comp_lvl; 997 StatArray[ix_beg].compiler = cType; 998 break; 999 case nMethod_alive: 1000 StatArray[ix_beg].tx_count++; 1001 StatArray[ix_beg].tx_space += (unsigned short)hb_len; 1002 StatArray[ix_beg].tx_age = StatArray[ix_beg].tx_age < compile_id ? compile_id : StatArray[ix_beg].tx_age; 1003 StatArray[ix_beg].level = comp_lvl; 1004 StatArray[ix_beg].compiler = cType; 1005 break; 1006 case nMethod_dead: 1007 case nMethod_unloaded: 1008 StatArray[ix_beg].dead_count++; 1009 StatArray[ix_beg].dead_space += (unsigned short)hb_len; 1010 break; 1011 default: 1012 // must be a stub, if it's not a dead or alive nMethod 1013 nBlocks_stub++; 1014 stubSpace += hb_bytelen; 1015 StatArray[ix_beg].stub_count++; 1016 StatArray[ix_beg].stub_space += (unsigned short)hb_len; 1017 break; 1018 } 1019 } else { 1020 unsigned int beg_space = (unsigned int)(granule_size - ((char*)h - low_bound - ix_beg*granule_size)); 1021 unsigned int end_space = (unsigned int)(hb_bytelen - beg_space - (ix_end-ix_beg-1)*granule_size); 1022 beg_space = beg_space>>log2_seg_size; // store in units of _segment_size 1023 end_space = end_space>>log2_seg_size; // store in units of _segment_size 1024 StatArray[ix_beg].type = cbType; 1025 StatArray[ix_end].type = cbType; 1026 switch (cbType) { 1027 case nMethod_inuse: 1028 highest_compilation_id = (highest_compilation_id >= compile_id) ? highest_compilation_id : compile_id; 1029 if (comp_lvl < CompLevel_full_optimization) { 1030 nBlocks_t1++; 1031 t1Space += hb_bytelen; 1032 StatArray[ix_beg].t1_count++; 1033 StatArray[ix_beg].t1_space += (unsigned short)beg_space; 1034 StatArray[ix_beg].t1_age = StatArray[ix_beg].t1_age < compile_id ? compile_id : StatArray[ix_beg].t1_age; 1035 1036 StatArray[ix_end].t1_count++; 1037 StatArray[ix_end].t1_space += (unsigned short)end_space; 1038 StatArray[ix_end].t1_age = StatArray[ix_end].t1_age < compile_id ? compile_id : StatArray[ix_end].t1_age; 1039 } else { 1040 nBlocks_t2++; 1041 t2Space += hb_bytelen; 1042 StatArray[ix_beg].t2_count++; 1043 StatArray[ix_beg].t2_space += (unsigned short)beg_space; 1044 StatArray[ix_beg].t2_age = StatArray[ix_beg].t2_age < compile_id ? compile_id : StatArray[ix_beg].t2_age; 1045 1046 StatArray[ix_end].t2_count++; 1047 StatArray[ix_end].t2_space += (unsigned short)end_space; 1048 StatArray[ix_end].t2_age = StatArray[ix_end].t2_age < compile_id ? compile_id : StatArray[ix_end].t2_age; 1049 } 1050 StatArray[ix_beg].level = comp_lvl; 1051 StatArray[ix_beg].compiler = cType; 1052 StatArray[ix_end].level = comp_lvl; 1053 StatArray[ix_end].compiler = cType; 1054 break; 1055 case nMethod_alive: 1056 StatArray[ix_beg].tx_count++; 1057 StatArray[ix_beg].tx_space += (unsigned short)beg_space; 1058 StatArray[ix_beg].tx_age = StatArray[ix_beg].tx_age < compile_id ? compile_id : StatArray[ix_beg].tx_age; 1059 1060 StatArray[ix_end].tx_count++; 1061 StatArray[ix_end].tx_space += (unsigned short)end_space; 1062 StatArray[ix_end].tx_age = StatArray[ix_end].tx_age < compile_id ? compile_id : StatArray[ix_end].tx_age; 1063 1064 StatArray[ix_beg].level = comp_lvl; 1065 StatArray[ix_beg].compiler = cType; 1066 StatArray[ix_end].level = comp_lvl; 1067 StatArray[ix_end].compiler = cType; 1068 break; 1069 case nMethod_dead: 1070 case nMethod_unloaded: 1071 StatArray[ix_beg].dead_count++; 1072 StatArray[ix_beg].dead_space += (unsigned short)beg_space; 1073 StatArray[ix_end].dead_count++; 1074 StatArray[ix_end].dead_space += (unsigned short)end_space; 1075 break; 1076 default: 1077 // must be a stub, if it's not a dead or alive nMethod 1078 nBlocks_stub++; 1079 stubSpace += hb_bytelen; 1080 StatArray[ix_beg].stub_count++; 1081 StatArray[ix_beg].stub_space += (unsigned short)beg_space; 1082 StatArray[ix_end].stub_count++; 1083 StatArray[ix_end].stub_space += (unsigned short)end_space; 1084 break; 1085 } 1086 for (unsigned int ix = ix_beg+1; ix < ix_end; ix++) { 1087 StatArray[ix].type = cbType; 1088 switch (cbType) { 1089 case nMethod_inuse: 1090 if (comp_lvl < CompLevel_full_optimization) { 1091 StatArray[ix].t1_count++; 1092 StatArray[ix].t1_space += (unsigned short)(granule_size>>log2_seg_size); 1093 StatArray[ix].t1_age = StatArray[ix].t1_age < compile_id ? compile_id : StatArray[ix].t1_age; 1094 } else { 1095 StatArray[ix].t2_count++; 1096 StatArray[ix].t2_space += (unsigned short)(granule_size>>log2_seg_size); 1097 StatArray[ix].t2_age = StatArray[ix].t2_age < compile_id ? compile_id : StatArray[ix].t2_age; 1098 } 1099 StatArray[ix].level = comp_lvl; 1100 StatArray[ix].compiler = cType; 1101 break; 1102 case nMethod_alive: 1103 StatArray[ix].tx_count++; 1104 StatArray[ix].tx_space += (unsigned short)(granule_size>>log2_seg_size); 1105 StatArray[ix].tx_age = StatArray[ix].tx_age < compile_id ? compile_id : StatArray[ix].tx_age; 1106 StatArray[ix].level = comp_lvl; 1107 StatArray[ix].compiler = cType; 1108 break; 1109 case nMethod_dead: 1110 case nMethod_unloaded: 1111 StatArray[ix].dead_count++; 1112 StatArray[ix].dead_space += (unsigned short)(granule_size>>log2_seg_size); 1113 break; 1114 default: 1115 // must be a stub, if it's not a dead or alive nMethod 1116 StatArray[ix].stub_count++; 1117 StatArray[ix].stub_space += (unsigned short)(granule_size>>log2_seg_size); 1118 break; 1119 } 1120 } 1121 } 1122 } 1123 } 1124 done = true; 1125 1126 if (!insane) { 1127 // There is a risk for this block (because it contains many print statements) to get 1128 // interspersed with print data from other threads. We take this risk intentionally. 1129 // Getting stalled waiting for tty_lock while holding the CodeCache_lock is not desirable. 1130 printBox(ast, '-', "Global CodeHeap statistics for segment ", heapName); 1131 ast->print_cr("freeSpace = " SIZE_FORMAT_W(8) "k, nBlocks_free = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", freeSpace/(size_t)K, nBlocks_free, (100.0*freeSpace)/size, (100.0*freeSpace)/res_size); 1132 ast->print_cr("usedSpace = " SIZE_FORMAT_W(8) "k, nBlocks_used = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", usedSpace/(size_t)K, nBlocks_used, (100.0*usedSpace)/size, (100.0*usedSpace)/res_size); 1133 ast->print_cr(" Tier1 Space = " SIZE_FORMAT_W(8) "k, nBlocks_t1 = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", t1Space/(size_t)K, nBlocks_t1, (100.0*t1Space)/size, (100.0*t1Space)/res_size); 1134 ast->print_cr(" Tier2 Space = " SIZE_FORMAT_W(8) "k, nBlocks_t2 = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", t2Space/(size_t)K, nBlocks_t2, (100.0*t2Space)/size, (100.0*t2Space)/res_size); 1135 ast->print_cr(" Alive Space = " SIZE_FORMAT_W(8) "k, nBlocks_alive = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", aliveSpace/(size_t)K, nBlocks_alive, (100.0*aliveSpace)/size, (100.0*aliveSpace)/res_size); 1136 ast->print_cr(" disconnected = " SIZE_FORMAT_W(8) "k, nBlocks_disconn = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", disconnSpace/(size_t)K, nBlocks_disconn, (100.0*disconnSpace)/size, (100.0*disconnSpace)/res_size); 1137 ast->print_cr(" not entrant = " SIZE_FORMAT_W(8) "k, nBlocks_notentr = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", notentrSpace/(size_t)K, nBlocks_notentr, (100.0*notentrSpace)/size, (100.0*notentrSpace)/res_size); 1138 ast->print_cr(" unloadedSpace = " SIZE_FORMAT_W(8) "k, nBlocks_unloaded = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", unloadedSpace/(size_t)K, nBlocks_unloaded, (100.0*unloadedSpace)/size, (100.0*unloadedSpace)/res_size); 1139 ast->print_cr(" deadSpace = " SIZE_FORMAT_W(8) "k, nBlocks_dead = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", deadSpace/(size_t)K, nBlocks_dead, (100.0*deadSpace)/size, (100.0*deadSpace)/res_size); 1140 ast->print_cr(" stubSpace = " SIZE_FORMAT_W(8) "k, nBlocks_stub = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", stubSpace/(size_t)K, nBlocks_stub, (100.0*stubSpace)/size, (100.0*stubSpace)/res_size); 1141 ast->print_cr("ZombieBlocks = %8d. These are HeapBlocks which could not be identified as CodeBlobs.", nBlocks_zomb); 1142 ast->cr(); 1143 ast->print_cr("Segment start = " INTPTR_FORMAT ", used space = " SIZE_FORMAT_W(8)"k", p2i(low_bound), size/K); 1144 ast->print_cr("Segment end (used) = " INTPTR_FORMAT ", remaining space = " SIZE_FORMAT_W(8)"k", p2i(low_bound) + size, (res_size - size)/K); 1145 ast->print_cr("Segment end (reserved) = " INTPTR_FORMAT ", reserved space = " SIZE_FORMAT_W(8)"k", p2i(low_bound) + res_size, res_size/K); 1146 ast->cr(); 1147 ast->print_cr("latest allocated compilation id = %d", latest_compilation_id); 1148 ast->print_cr("highest observed compilation id = %d", highest_compilation_id); 1149 ast->print_cr("Building TopSizeList iterations = %ld", total_iterations); 1150 ast->cr(); 1151 1152 int reset_val = NMethodSweeper::hotness_counter_reset_val(); 1153 double reverse_free_ratio = (res_size > size) ? (double)res_size/(double)(res_size-size) : (double)res_size; 1154 printBox(ast, '-', "Method hotness information at time of this analysis", NULL); 1155 ast->print_cr("Highest possible method temperature: %12d", reset_val); 1156 ast->print_cr("Threshold for method to be considered 'cold': %12.3f", -reset_val + reverse_free_ratio * NmethodSweepActivity); 1157 if (n_methods > 0) { 1158 avgTemp = hotnessAccumulator/n_methods; 1159 ast->print_cr("min. hotness = %6d", minTemp); 1160 ast->print_cr("avg. hotness = %6d", avgTemp); 1161 ast->print_cr("max. hotness = %6d", maxTemp); 1162 } else { 1163 avgTemp = 0; 1164 ast->print_cr("No hotness data available"); 1165 } 1166 BUFFEREDSTREAM_FLUSH("\n") 1167 1168 // This loop is intentionally printing directly to "out". 1169 // It should not print anything, anyway. 1170 out->print("Verifying collected data..."); 1171 size_t granule_segs = granule_size>>log2_seg_size; 1172 for (unsigned int ix = 0; ix < granules; ix++) { 1173 if (StatArray[ix].t1_count > granule_segs) { 1174 out->print_cr("t1_count[%d] = %d", ix, StatArray[ix].t1_count); 1175 } 1176 if (StatArray[ix].t2_count > granule_segs) { 1177 out->print_cr("t2_count[%d] = %d", ix, StatArray[ix].t2_count); 1178 } 1179 if (StatArray[ix].tx_count > granule_segs) { 1180 out->print_cr("tx_count[%d] = %d", ix, StatArray[ix].tx_count); 1181 } 1182 if (StatArray[ix].stub_count > granule_segs) { 1183 out->print_cr("stub_count[%d] = %d", ix, StatArray[ix].stub_count); 1184 } 1185 if (StatArray[ix].dead_count > granule_segs) { 1186 out->print_cr("dead_count[%d] = %d", ix, StatArray[ix].dead_count); 1187 } 1188 if (StatArray[ix].t1_space > granule_segs) { 1189 out->print_cr("t1_space[%d] = %d", ix, StatArray[ix].t1_space); 1190 } 1191 if (StatArray[ix].t2_space > granule_segs) { 1192 out->print_cr("t2_space[%d] = %d", ix, StatArray[ix].t2_space); 1193 } 1194 if (StatArray[ix].tx_space > granule_segs) { 1195 out->print_cr("tx_space[%d] = %d", ix, StatArray[ix].tx_space); 1196 } 1197 if (StatArray[ix].stub_space > granule_segs) { 1198 out->print_cr("stub_space[%d] = %d", ix, StatArray[ix].stub_space); 1199 } 1200 if (StatArray[ix].dead_space > granule_segs) { 1201 out->print_cr("dead_space[%d] = %d", ix, StatArray[ix].dead_space); 1202 } 1203 // this cast is awful! I need it because NT/Intel reports a signed/unsigned mismatch. 1204 if ((size_t)(StatArray[ix].t1_count+StatArray[ix].t2_count+StatArray[ix].tx_count+StatArray[ix].stub_count+StatArray[ix].dead_count) > granule_segs) { 1205 out->print_cr("t1_count[%d] = %d, t2_count[%d] = %d, tx_count[%d] = %d, stub_count[%d] = %d", ix, StatArray[ix].t1_count, ix, StatArray[ix].t2_count, ix, StatArray[ix].tx_count, ix, StatArray[ix].stub_count); 1206 } 1207 if ((size_t)(StatArray[ix].t1_space+StatArray[ix].t2_space+StatArray[ix].tx_space+StatArray[ix].stub_space+StatArray[ix].dead_space) > granule_segs) { 1208 out->print_cr("t1_space[%d] = %d, t2_space[%d] = %d, tx_space[%d] = %d, stub_space[%d] = %d", ix, StatArray[ix].t1_space, ix, StatArray[ix].t2_space, ix, StatArray[ix].tx_space, ix, StatArray[ix].stub_space); 1209 } 1210 } 1211 1212 // This loop is intentionally printing directly to "out". 1213 // It should not print anything, anyway. 1214 if (used_topSizeBlocks > 0) { 1215 unsigned int j = 0; 1216 if (TopSizeArray[0].len != currMax) { 1217 out->print_cr("currMax(%d) differs from TopSizeArray[0].len(%d)", currMax, TopSizeArray[0].len); 1218 } 1219 for (unsigned int i = 0; (TopSizeArray[i].index != tsbStopper) && (j++ < alloc_topSizeBlocks); i = TopSizeArray[i].index) { 1220 if (TopSizeArray[i].len < TopSizeArray[TopSizeArray[i].index].len) { 1221 out->print_cr("sort error at index %d: %d !>= %d", i, TopSizeArray[i].len, TopSizeArray[TopSizeArray[i].index].len); 1222 } 1223 } 1224 if (j >= alloc_topSizeBlocks) { 1225 out->print_cr("Possible loop in TopSizeArray chaining!\n allocBlocks = %d, usedBlocks = %d", alloc_topSizeBlocks, used_topSizeBlocks); 1226 for (unsigned int i = 0; i < alloc_topSizeBlocks; i++) { 1227 out->print_cr(" TopSizeArray[%d].index = %d, len = %d", i, TopSizeArray[i].index, TopSizeArray[i].len); 1228 } 1229 } 1230 } 1231 out->print_cr("...done\n\n"); 1232 } else { 1233 // insane heap state detected. Analysis data incomplete. Just throw it away. 1234 discard_StatArray(out); 1235 discard_TopSizeArray(out); 1236 } 1237 } 1238 1239 1240 done = false; 1241 while (!done && (nBlocks_free > 0)) { 1242 1243 printBox(ast, '=', "C O D E H E A P A N A L Y S I S (free blocks) for segment ", heapName); 1244 ast->print_cr(" The aggregate step collects information about all free blocks in CodeHeap.\n" 1245 " Subsequent print functions create their output based on this snapshot.\n"); 1246 ast->print_cr(" Free space in %s is distributed over %d free blocks.", heapName, nBlocks_free); 1247 ast->print_cr(" Each free block takes " SIZE_FORMAT " bytes of C heap for statistics data, that is " SIZE_FORMAT "K in total.", sizeof(FreeBlk), (sizeof(FreeBlk)*nBlocks_free)/K); 1248 BUFFEREDSTREAM_FLUSH("\n") 1249 1250 //---------------------------------------- 1251 //-- Prepare the FreeArray of FreeBlks -- 1252 //---------------------------------------- 1253 1254 //---< discard old array if size does not match >--- 1255 if (nBlocks_free != alloc_freeBlocks) { 1256 discard_FreeArray(out); 1257 } 1258 1259 prepare_FreeArray(out, nBlocks_free, heapName); 1260 if (FreeArray == NULL) { 1261 done = true; 1262 continue; 1263 } 1264 1265 //---------------------------------------- 1266 //-- Collect all FreeBlks in FreeArray -- 1267 //---------------------------------------- 1268 1269 unsigned int ix = 0; 1270 FreeBlock* cur = heap->freelist(); 1271 1272 while (cur != NULL) { 1273 if (ix < alloc_freeBlocks) { // don't index out of bounds if _freelist has more blocks than anticipated 1274 FreeArray[ix].start = cur; 1275 FreeArray[ix].len = (unsigned int)(cur->length()<<log2_seg_size); 1276 FreeArray[ix].index = ix; 1277 } 1278 cur = cur->link(); 1279 ix++; 1280 } 1281 if (ix != alloc_freeBlocks) { 1282 ast->print_cr("Free block count mismatch. Expected %d free blocks, but found %d.", alloc_freeBlocks, ix); 1283 ast->print_cr("I will update the counter and retry data collection"); 1284 BUFFEREDSTREAM_FLUSH("\n") 1285 nBlocks_free = ix; 1286 continue; 1287 } 1288 done = true; 1289 } 1290 1291 if (!done || (nBlocks_free == 0)) { 1292 if (nBlocks_free == 0) { 1293 printBox(ast, '-', "no free blocks found in ", heapName); 1294 } else if (!done) { 1295 ast->print_cr("Free block count mismatch could not be resolved."); 1296 ast->print_cr("Try to run \"aggregate\" function to update counters"); 1297 } 1298 BUFFEREDSTREAM_FLUSH("") 1299 1300 //---< discard old array and update global values >--- 1301 discard_FreeArray(out); 1302 set_HeapStatGlobals(out, heapName); 1303 return; 1304 } 1305 1306 //---< calculate and fill remaining fields >--- 1307 if (FreeArray != NULL) { 1308 // This loop is intentionally printing directly to "out". 1309 // It should not print anything, anyway. 1310 for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) { 1311 size_t lenSum = 0; 1312 FreeArray[ix].gap = (unsigned int)((address)FreeArray[ix+1].start - ((address)FreeArray[ix].start + FreeArray[ix].len)); 1313 for (HeapBlock *h = heap->next_block(FreeArray[ix].start); (h != NULL) && (h != FreeArray[ix+1].start); h = heap->next_block(h)) { 1314 CodeBlob *cb = (CodeBlob*)(heap->find_start(h)); 1315 if ((cb != NULL) && !cb->is_nmethod()) { // checks equivalent to those in get_cbType() 1316 FreeArray[ix].stubs_in_gap = true; 1317 } 1318 FreeArray[ix].n_gapBlocks++; 1319 lenSum += h->length()<<log2_seg_size; 1320 if (((address)h < ((address)FreeArray[ix].start+FreeArray[ix].len)) || (h >= FreeArray[ix+1].start)) { 1321 out->print_cr("unsorted occupied CodeHeap block found @ %p, gap interval [%p, %p)", h, (address)FreeArray[ix].start+FreeArray[ix].len, FreeArray[ix+1].start); 1322 } 1323 } 1324 if (lenSum != FreeArray[ix].gap) { 1325 out->print_cr("Length mismatch for gap between FreeBlk[%d] and FreeBlk[%d]. Calculated: %d, accumulated: %d.", ix, ix+1, FreeArray[ix].gap, (unsigned int)lenSum); 1326 } 1327 } 1328 } 1329 set_HeapStatGlobals(out, heapName); 1330 1331 printBox(ast, '=', "C O D E H E A P A N A L Y S I S C O M P L E T E for segment ", heapName); 1332 BUFFEREDSTREAM_FLUSH("\n") 1333 } 1334 1335 1336 void CodeHeapState::print_usedSpace(outputStream* out, CodeHeap* heap) { 1337 if (!initialization_complete) { 1338 return; 1339 } 1340 1341 const char* heapName = get_heapName(heap); 1342 get_HeapStatGlobals(out, heapName); 1343 1344 if ((StatArray == NULL) || (TopSizeArray == NULL) || (used_topSizeBlocks == 0)) { 1345 return; 1346 } 1347 BUFFEREDSTREAM_DECL(ast, out) 1348 1349 { 1350 printBox(ast, '=', "U S E D S P A C E S T A T I S T I C S for ", heapName); 1351 ast->print_cr("Note: The Top%d list of the largest used blocks associates method names\n" 1352 " and other identifying information with the block size data.\n" 1353 "\n" 1354 " Method names are dynamically retrieved from the code cache at print time.\n" 1355 " Due to the living nature of the code cache and because the CodeCache_lock\n" 1356 " is not continuously held, the displayed name might be wrong or no name\n" 1357 " might be found at all. The likelihood for that to happen increases\n" 1358 " over time passed between analysis and print step.\n", used_topSizeBlocks); 1359 BUFFEREDSTREAM_FLUSH_LOCKED("\n") 1360 } 1361 1362 //---------------------------- 1363 //-- Print Top Used Blocks -- 1364 //---------------------------- 1365 { 1366 char* low_bound = heap->low_boundary(); 1367 1368 printBox(ast, '-', "Largest Used Blocks in ", heapName); 1369 print_blobType_legend(ast); 1370 1371 ast->fill_to(51); 1372 ast->print("%4s", "blob"); 1373 ast->fill_to(56); 1374 ast->print("%9s", "compiler"); 1375 ast->fill_to(66); 1376 ast->print_cr("%6s", "method"); 1377 ast->print_cr("%18s %13s %17s %4s %9s %5s %s", "Addr(module) ", "offset", "size", "type", " type lvl", " temp", "Name"); 1378 BUFFEREDSTREAM_FLUSH_LOCKED("") 1379 1380 //---< print Top Ten Used Blocks >--- 1381 if (used_topSizeBlocks > 0) { 1382 unsigned int printed_topSizeBlocks = 0; 1383 for (unsigned int i = 0; i != tsbStopper; i = TopSizeArray[i].index) { 1384 printed_topSizeBlocks++; 1385 if (TopSizeArray[i].blob_name == NULL) { 1386 TopSizeArray[i].blob_name = os::strdup("unnamed blob or blob name unavailable"); 1387 } 1388 // heap->find_start() is safe. Only works on _segmap. 1389 // Returns NULL or void*. Returned CodeBlob may be uninitialized. 1390 HeapBlock* heapBlock = TopSizeArray[i].start; 1391 CodeBlob* this_blob = (CodeBlob*)(heap->find_start(heapBlock)); 1392 if (this_blob != NULL) { 1393 //---< access these fields only if we own the CodeCache_lock >--- 1394 //---< blob address >--- 1395 ast->print(INTPTR_FORMAT, p2i(this_blob)); 1396 ast->fill_to(19); 1397 //---< blob offset from CodeHeap begin >--- 1398 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); 1399 ast->fill_to(33); 1400 } else { 1401 //---< block address >--- 1402 ast->print(INTPTR_FORMAT, p2i(TopSizeArray[i].start)); 1403 ast->fill_to(19); 1404 //---< block offset from CodeHeap begin >--- 1405 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound)); 1406 ast->fill_to(33); 1407 } 1408 1409 //---< print size, name, and signature (for nMethods) >--- 1410 bool is_nmethod = TopSizeArray[i].nm_size > 0; 1411 if (is_nmethod) { 1412 //---< nMethod size in hex >--- 1413 ast->print(PTR32_FORMAT, TopSizeArray[i].nm_size); 1414 ast->print("(" SIZE_FORMAT_W(4) "K)", TopSizeArray[i].nm_size/K); 1415 ast->fill_to(51); 1416 ast->print(" %c", blobTypeChar[TopSizeArray[i].type]); 1417 //---< compiler information >--- 1418 ast->fill_to(56); 1419 ast->print("%5s %3d", compTypeName[TopSizeArray[i].compiler], TopSizeArray[i].level); 1420 //---< method temperature >--- 1421 ast->fill_to(67); 1422 ast->print("%5d", TopSizeArray[i].temperature); 1423 //---< name and signature >--- 1424 ast->fill_to(67+6); 1425 if (TopSizeArray[i].type == nMethod_dead) { 1426 ast->print(" zombie method "); 1427 } 1428 ast->print("%s", TopSizeArray[i].blob_name); 1429 } else { 1430 //---< block size in hex >--- 1431 ast->print(PTR32_FORMAT, (unsigned int)(TopSizeArray[i].len<<log2_seg_size)); 1432 ast->print("(" SIZE_FORMAT_W(4) "K)", (TopSizeArray[i].len<<log2_seg_size)/K); 1433 //---< no compiler information >--- 1434 ast->fill_to(56); 1435 //---< name and signature >--- 1436 ast->fill_to(67+6); 1437 ast->print("%s", TopSizeArray[i].blob_name); 1438 } 1439 ast->cr(); 1440 BUFFEREDSTREAM_FLUSH_AUTO("") 1441 } 1442 if (used_topSizeBlocks != printed_topSizeBlocks) { 1443 ast->print_cr("used blocks: %d, printed blocks: %d", used_topSizeBlocks, printed_topSizeBlocks); 1444 for (unsigned int i = 0; i < alloc_topSizeBlocks; i++) { 1445 ast->print_cr(" TopSizeArray[%d].index = %d, len = %d", i, TopSizeArray[i].index, TopSizeArray[i].len); 1446 BUFFEREDSTREAM_FLUSH_AUTO("") 1447 } 1448 } 1449 BUFFEREDSTREAM_FLUSH("\n\n") 1450 } 1451 } 1452 1453 //----------------------------- 1454 //-- Print Usage Histogram -- 1455 //----------------------------- 1456 1457 if (SizeDistributionArray != NULL) { 1458 unsigned long total_count = 0; 1459 unsigned long total_size = 0; 1460 const unsigned long pctFactor = 200; 1461 1462 for (unsigned int i = 0; i < nSizeDistElements; i++) { 1463 total_count += SizeDistributionArray[i].count; 1464 total_size += SizeDistributionArray[i].lenSum; 1465 } 1466 1467 if ((total_count > 0) && (total_size > 0)) { 1468 printBox(ast, '-', "Block count histogram for ", heapName); 1469 ast->print_cr("Note: The histogram indicates how many blocks (as a percentage\n" 1470 " of all blocks) have a size in the given range.\n" 1471 " %ld characters are printed per percentage point.\n", pctFactor/100); 1472 ast->print_cr("total size of all blocks: %7ldM", (total_size<<log2_seg_size)/M); 1473 ast->print_cr("total number of all blocks: %7ld\n", total_count); 1474 BUFFEREDSTREAM_FLUSH_LOCKED("") 1475 1476 ast->print_cr("[Size Range)------avg.-size-+----count-+"); 1477 for (unsigned int i = 0; i < nSizeDistElements; i++) { 1478 if (SizeDistributionArray[i].rangeStart<<log2_seg_size < K) { 1479 ast->print("[" SIZE_FORMAT_W(5) " .." SIZE_FORMAT_W(5) " ): " 1480 ,(size_t)(SizeDistributionArray[i].rangeStart<<log2_seg_size) 1481 ,(size_t)(SizeDistributionArray[i].rangeEnd<<log2_seg_size) 1482 ); 1483 } else if (SizeDistributionArray[i].rangeStart<<log2_seg_size < M) { 1484 ast->print("[" SIZE_FORMAT_W(5) "K.." SIZE_FORMAT_W(5) "K): " 1485 ,(SizeDistributionArray[i].rangeStart<<log2_seg_size)/K 1486 ,(SizeDistributionArray[i].rangeEnd<<log2_seg_size)/K 1487 ); 1488 } else { 1489 ast->print("[" SIZE_FORMAT_W(5) "M.." SIZE_FORMAT_W(5) "M): " 1490 ,(SizeDistributionArray[i].rangeStart<<log2_seg_size)/M 1491 ,(SizeDistributionArray[i].rangeEnd<<log2_seg_size)/M 1492 ); 1493 } 1494 ast->print(" %8d | %8d |", 1495 SizeDistributionArray[i].count > 0 ? (SizeDistributionArray[i].lenSum<<log2_seg_size)/SizeDistributionArray[i].count : 0, 1496 SizeDistributionArray[i].count); 1497 1498 unsigned int percent = pctFactor*SizeDistributionArray[i].count/total_count; 1499 for (unsigned int j = 1; j <= percent; j++) { 1500 ast->print("%c", (j%((pctFactor/100)*10) == 0) ? ('0'+j/(((unsigned int)pctFactor/100)*10)) : '*'); 1501 } 1502 ast->cr(); 1503 BUFFEREDSTREAM_FLUSH_AUTO("") 1504 } 1505 ast->print_cr("----------------------------+----------+"); 1506 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1507 1508 printBox(ast, '-', "Contribution per size range to total size for ", heapName); 1509 ast->print_cr("Note: The histogram indicates how much space (as a percentage of all\n" 1510 " occupied space) is used by the blocks in the given size range.\n" 1511 " %ld characters are printed per percentage point.\n", pctFactor/100); 1512 ast->print_cr("total size of all blocks: %7ldM", (total_size<<log2_seg_size)/M); 1513 ast->print_cr("total number of all blocks: %7ld\n", total_count); 1514 BUFFEREDSTREAM_FLUSH_LOCKED("") 1515 1516 ast->print_cr("[Size Range)------avg.-size-+----count-+"); 1517 for (unsigned int i = 0; i < nSizeDistElements; i++) { 1518 if (SizeDistributionArray[i].rangeStart<<log2_seg_size < K) { 1519 ast->print("[" SIZE_FORMAT_W(5) " .." SIZE_FORMAT_W(5) " ): " 1520 ,(size_t)(SizeDistributionArray[i].rangeStart<<log2_seg_size) 1521 ,(size_t)(SizeDistributionArray[i].rangeEnd<<log2_seg_size) 1522 ); 1523 } else if (SizeDistributionArray[i].rangeStart<<log2_seg_size < M) { 1524 ast->print("[" SIZE_FORMAT_W(5) "K.." SIZE_FORMAT_W(5) "K): " 1525 ,(SizeDistributionArray[i].rangeStart<<log2_seg_size)/K 1526 ,(SizeDistributionArray[i].rangeEnd<<log2_seg_size)/K 1527 ); 1528 } else { 1529 ast->print("[" SIZE_FORMAT_W(5) "M.." SIZE_FORMAT_W(5) "M): " 1530 ,(SizeDistributionArray[i].rangeStart<<log2_seg_size)/M 1531 ,(SizeDistributionArray[i].rangeEnd<<log2_seg_size)/M 1532 ); 1533 } 1534 ast->print(" %8d | %8d |", 1535 SizeDistributionArray[i].count > 0 ? (SizeDistributionArray[i].lenSum<<log2_seg_size)/SizeDistributionArray[i].count : 0, 1536 SizeDistributionArray[i].count); 1537 1538 unsigned int percent = pctFactor*(unsigned long)SizeDistributionArray[i].lenSum/total_size; 1539 for (unsigned int j = 1; j <= percent; j++) { 1540 ast->print("%c", (j%((pctFactor/100)*10) == 0) ? ('0'+j/(((unsigned int)pctFactor/100)*10)) : '*'); 1541 } 1542 ast->cr(); 1543 BUFFEREDSTREAM_FLUSH_AUTO("") 1544 } 1545 ast->print_cr("----------------------------+----------+"); 1546 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1547 } 1548 } 1549 } 1550 1551 1552 void CodeHeapState::print_freeSpace(outputStream* out, CodeHeap* heap) { 1553 if (!initialization_complete) { 1554 return; 1555 } 1556 1557 const char* heapName = get_heapName(heap); 1558 get_HeapStatGlobals(out, heapName); 1559 1560 if ((StatArray == NULL) || (FreeArray == NULL) || (alloc_granules == 0)) { 1561 return; 1562 } 1563 BUFFEREDSTREAM_DECL(ast, out) 1564 1565 { 1566 printBox(ast, '=', "F R E E S P A C E S T A T I S T I C S for ", heapName); 1567 ast->print_cr("Note: in this context, a gap is the occupied space between two free blocks.\n" 1568 " Those gaps are of interest if there is a chance that they become\n" 1569 " unoccupied, e.g. by class unloading. Then, the two adjacent free\n" 1570 " blocks, together with the now unoccupied space, form a new, large\n" 1571 " free block."); 1572 BUFFEREDSTREAM_FLUSH_LOCKED("\n") 1573 } 1574 1575 { 1576 printBox(ast, '-', "List of all Free Blocks in ", heapName); 1577 1578 unsigned int ix = 0; 1579 for (ix = 0; ix < alloc_freeBlocks-1; ix++) { 1580 ast->print(INTPTR_FORMAT ": Len[%4d] = " HEX32_FORMAT ",", p2i(FreeArray[ix].start), ix, FreeArray[ix].len); 1581 ast->fill_to(38); 1582 ast->print("Gap[%4d..%4d]: " HEX32_FORMAT " bytes,", ix, ix+1, FreeArray[ix].gap); 1583 ast->fill_to(71); 1584 ast->print("block count: %6d", FreeArray[ix].n_gapBlocks); 1585 if (FreeArray[ix].stubs_in_gap) { 1586 ast->print(" !! permanent gap, contains stubs and/or blobs !!"); 1587 } 1588 ast->cr(); 1589 BUFFEREDSTREAM_FLUSH_AUTO("") 1590 } 1591 ast->print_cr(INTPTR_FORMAT ": Len[%4d] = " HEX32_FORMAT, p2i(FreeArray[ix].start), ix, FreeArray[ix].len); 1592 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n") 1593 } 1594 1595 1596 //----------------------------------------- 1597 //-- Find and Print Top Ten Free Blocks -- 1598 //----------------------------------------- 1599 1600 //---< find Top Ten Free Blocks >--- 1601 const unsigned int nTop = 10; 1602 unsigned int currMax10 = 0; 1603 struct FreeBlk* FreeTopTen[nTop]; 1604 memset(FreeTopTen, 0, sizeof(FreeTopTen)); 1605 1606 for (unsigned int ix = 0; ix < alloc_freeBlocks; ix++) { 1607 if (FreeArray[ix].len > currMax10) { // larger than the ten largest found so far 1608 unsigned int currSize = FreeArray[ix].len; 1609 1610 unsigned int iy; 1611 for (iy = 0; iy < nTop && FreeTopTen[iy] != NULL; iy++) { 1612 if (FreeTopTen[iy]->len < currSize) { 1613 for (unsigned int iz = nTop-1; iz > iy; iz--) { // make room to insert new free block 1614 FreeTopTen[iz] = FreeTopTen[iz-1]; 1615 } 1616 FreeTopTen[iy] = &FreeArray[ix]; // insert new free block 1617 if (FreeTopTen[nTop-1] != NULL) { 1618 currMax10 = FreeTopTen[nTop-1]->len; 1619 } 1620 break; // done with this, check next free block 1621 } 1622 } 1623 if (iy >= nTop) { 1624 ast->print_cr("Internal logic error. New Max10 = %d detected, but could not be merged. Old Max10 = %d", 1625 currSize, currMax10); 1626 continue; 1627 } 1628 if (FreeTopTen[iy] == NULL) { 1629 FreeTopTen[iy] = &FreeArray[ix]; 1630 if (iy == (nTop-1)) { 1631 currMax10 = currSize; 1632 } 1633 } 1634 } 1635 } 1636 BUFFEREDSTREAM_FLUSH_AUTO("") 1637 1638 { 1639 printBox(ast, '-', "Top Ten Free Blocks in ", heapName); 1640 1641 //---< print Top Ten Free Blocks >--- 1642 for (unsigned int iy = 0; (iy < nTop) && (FreeTopTen[iy] != NULL); iy++) { 1643 ast->print("Pos %3d: Block %4d - size " HEX32_FORMAT ",", iy+1, FreeTopTen[iy]->index, FreeTopTen[iy]->len); 1644 ast->fill_to(39); 1645 if (FreeTopTen[iy]->index == (alloc_freeBlocks-1)) { 1646 ast->print("last free block in list."); 1647 } else { 1648 ast->print("Gap (to next) " HEX32_FORMAT ",", FreeTopTen[iy]->gap); 1649 ast->fill_to(63); 1650 ast->print("#blocks (in gap) %d", FreeTopTen[iy]->n_gapBlocks); 1651 } 1652 ast->cr(); 1653 BUFFEREDSTREAM_FLUSH_AUTO("") 1654 } 1655 } 1656 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n") 1657 1658 1659 //-------------------------------------------------------- 1660 //-- Find and Print Top Ten Free-Occupied-Free Triples -- 1661 //-------------------------------------------------------- 1662 1663 //---< find and print Top Ten Triples (Free-Occupied-Free) >--- 1664 currMax10 = 0; 1665 struct FreeBlk *FreeTopTenTriple[nTop]; 1666 memset(FreeTopTenTriple, 0, sizeof(FreeTopTenTriple)); 1667 1668 for (unsigned int ix = 0; ix < alloc_freeBlocks-1; ix++) { 1669 // If there are stubs in the gap, this gap will never become completely free. 1670 // The triple will thus never merge to one free block. 1671 unsigned int lenTriple = FreeArray[ix].len + (FreeArray[ix].stubs_in_gap ? 0 : FreeArray[ix].gap + FreeArray[ix+1].len); 1672 FreeArray[ix].len = lenTriple; 1673 if (lenTriple > currMax10) { // larger than the ten largest found so far 1674 1675 unsigned int iy; 1676 for (iy = 0; (iy < nTop) && (FreeTopTenTriple[iy] != NULL); iy++) { 1677 if (FreeTopTenTriple[iy]->len < lenTriple) { 1678 for (unsigned int iz = nTop-1; iz > iy; iz--) { 1679 FreeTopTenTriple[iz] = FreeTopTenTriple[iz-1]; 1680 } 1681 FreeTopTenTriple[iy] = &FreeArray[ix]; 1682 if (FreeTopTenTriple[nTop-1] != NULL) { 1683 currMax10 = FreeTopTenTriple[nTop-1]->len; 1684 } 1685 break; 1686 } 1687 } 1688 if (iy == nTop) { 1689 ast->print_cr("Internal logic error. New Max10 = %d detected, but could not be merged. Old Max10 = %d", 1690 lenTriple, currMax10); 1691 continue; 1692 } 1693 if (FreeTopTenTriple[iy] == NULL) { 1694 FreeTopTenTriple[iy] = &FreeArray[ix]; 1695 if (iy == (nTop-1)) { 1696 currMax10 = lenTriple; 1697 } 1698 } 1699 } 1700 } 1701 BUFFEREDSTREAM_FLUSH_AUTO("") 1702 1703 { 1704 printBox(ast, '-', "Top Ten Free-Occupied-Free Triples in ", heapName); 1705 ast->print_cr(" Use this information to judge how likely it is that a large(r) free block\n" 1706 " might get created by code cache sweeping.\n" 1707 " If all the occupied blocks can be swept, the three free blocks will be\n" 1708 " merged into one (much larger) free block. That would reduce free space\n" 1709 " fragmentation.\n"); 1710 1711 //---< print Top Ten Free-Occupied-Free Triples >--- 1712 for (unsigned int iy = 0; (iy < nTop) && (FreeTopTenTriple[iy] != NULL); iy++) { 1713 ast->print("Pos %3d: Block %4d - size " HEX32_FORMAT ",", iy+1, FreeTopTenTriple[iy]->index, FreeTopTenTriple[iy]->len); 1714 ast->fill_to(39); 1715 ast->print("Gap (to next) " HEX32_FORMAT ",", FreeTopTenTriple[iy]->gap); 1716 ast->fill_to(63); 1717 ast->print("#blocks (in gap) %d", FreeTopTenTriple[iy]->n_gapBlocks); 1718 ast->cr(); 1719 BUFFEREDSTREAM_FLUSH_AUTO("") 1720 } 1721 } 1722 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n") 1723 } 1724 1725 1726 void CodeHeapState::print_count(outputStream* out, CodeHeap* heap) { 1727 if (!initialization_complete) { 1728 return; 1729 } 1730 1731 const char* heapName = get_heapName(heap); 1732 get_HeapStatGlobals(out, heapName); 1733 1734 if ((StatArray == NULL) || (alloc_granules == 0)) { 1735 return; 1736 } 1737 BUFFEREDSTREAM_DECL(ast, out) 1738 1739 unsigned int granules_per_line = 32; 1740 char* low_bound = heap->low_boundary(); 1741 1742 { 1743 printBox(ast, '=', "B L O C K C O U N T S for ", heapName); 1744 ast->print_cr(" Each granule contains an individual number of heap blocks. Large blocks\n" 1745 " may span multiple granules and are counted for each granule they touch.\n"); 1746 if (segment_granules) { 1747 ast->print_cr(" You have selected granule size to be as small as segment size.\n" 1748 " As a result, each granule contains exactly one block (or a part of one block)\n" 1749 " or is displayed as empty (' ') if it's BlobType does not match the selection.\n" 1750 " Occupied granules show their BlobType character, see legend.\n"); 1751 print_blobType_legend(ast); 1752 } 1753 BUFFEREDSTREAM_FLUSH_LOCKED("") 1754 } 1755 1756 { 1757 if (segment_granules) { 1758 printBox(ast, '-', "Total (all types) count for granule size == segment size", NULL); 1759 1760 granules_per_line = 128; 1761 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1762 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1763 print_blobType_single(ast, StatArray[ix].type); 1764 } 1765 } else { 1766 printBox(ast, '-', "Total (all tiers) count, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1767 1768 granules_per_line = 128; 1769 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1770 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1771 unsigned int count = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count 1772 + StatArray[ix].stub_count + StatArray[ix].dead_count; 1773 print_count_single(ast, count); 1774 } 1775 } 1776 BUFFEREDSTREAM_FLUSH_LOCKED("|\n\n\n") 1777 } 1778 1779 { 1780 if (nBlocks_t1 > 0) { 1781 printBox(ast, '-', "Tier1 nMethod count only, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1782 1783 granules_per_line = 128; 1784 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1785 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1786 if (segment_granules && StatArray[ix].t1_count > 0) { 1787 print_blobType_single(ast, StatArray[ix].type); 1788 } else { 1789 print_count_single(ast, StatArray[ix].t1_count); 1790 } 1791 } 1792 ast->print("|"); 1793 } else { 1794 ast->print("No Tier1 nMethods found in CodeHeap."); 1795 } 1796 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1797 } 1798 1799 { 1800 if (nBlocks_t2 > 0) { 1801 printBox(ast, '-', "Tier2 nMethod count only, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1802 1803 granules_per_line = 128; 1804 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1805 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1806 if (segment_granules && StatArray[ix].t2_count > 0) { 1807 print_blobType_single(ast, StatArray[ix].type); 1808 } else { 1809 print_count_single(ast, StatArray[ix].t2_count); 1810 } 1811 } 1812 ast->print("|"); 1813 } else { 1814 ast->print("No Tier2 nMethods found in CodeHeap."); 1815 } 1816 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1817 } 1818 1819 { 1820 if (nBlocks_alive > 0) { 1821 printBox(ast, '-', "not_used/not_entrant/not_installed nMethod count only, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1822 1823 granules_per_line = 128; 1824 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1825 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1826 if (segment_granules && StatArray[ix].tx_count > 0) { 1827 print_blobType_single(ast, StatArray[ix].type); 1828 } else { 1829 print_count_single(ast, StatArray[ix].tx_count); 1830 } 1831 } 1832 ast->print("|"); 1833 } else { 1834 ast->print("No not_used/not_entrant nMethods found in CodeHeap."); 1835 } 1836 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1837 } 1838 1839 { 1840 if (nBlocks_stub > 0) { 1841 printBox(ast, '-', "Stub & Blob count only, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1842 1843 granules_per_line = 128; 1844 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1845 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1846 if (segment_granules && StatArray[ix].stub_count > 0) { 1847 print_blobType_single(ast, StatArray[ix].type); 1848 } else { 1849 print_count_single(ast, StatArray[ix].stub_count); 1850 } 1851 } 1852 ast->print("|"); 1853 } else { 1854 ast->print("No Stubs and Blobs found in CodeHeap."); 1855 } 1856 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1857 } 1858 1859 { 1860 if (nBlocks_dead > 0) { 1861 printBox(ast, '-', "Dead nMethod count only, 0x1..0xf. '*' indicates >= 16 blocks, ' ' indicates empty", NULL); 1862 1863 granules_per_line = 128; 1864 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1865 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1866 if (segment_granules && StatArray[ix].dead_count > 0) { 1867 print_blobType_single(ast, StatArray[ix].type); 1868 } else { 1869 print_count_single(ast, StatArray[ix].dead_count); 1870 } 1871 } 1872 ast->print("|"); 1873 } else { 1874 ast->print("No dead nMethods found in CodeHeap."); 1875 } 1876 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1877 } 1878 1879 { 1880 if (!segment_granules) { // Prevent totally redundant printouts 1881 printBox(ast, '-', "Count by tier (combined, no dead blocks): <#t1>:<#t2>:<#s>, 0x0..0xf. '*' indicates >= 16 blocks", NULL); 1882 1883 granules_per_line = 24; 1884 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1885 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1886 1887 print_count_single(ast, StatArray[ix].t1_count); 1888 ast->print(":"); 1889 print_count_single(ast, StatArray[ix].t2_count); 1890 ast->print(":"); 1891 if (segment_granules && StatArray[ix].stub_count > 0) { 1892 print_blobType_single(ast, StatArray[ix].type); 1893 } else { 1894 print_count_single(ast, StatArray[ix].stub_count); 1895 } 1896 ast->print(" "); 1897 } 1898 BUFFEREDSTREAM_FLUSH_LOCKED("|\n\n\n") 1899 } 1900 } 1901 } 1902 1903 1904 void CodeHeapState::print_space(outputStream* out, CodeHeap* heap) { 1905 if (!initialization_complete) { 1906 return; 1907 } 1908 1909 const char* heapName = get_heapName(heap); 1910 get_HeapStatGlobals(out, heapName); 1911 1912 if ((StatArray == NULL) || (alloc_granules == 0)) { 1913 return; 1914 } 1915 BUFFEREDSTREAM_DECL(ast, out) 1916 1917 unsigned int granules_per_line = 32; 1918 char* low_bound = heap->low_boundary(); 1919 1920 { 1921 printBox(ast, '=', "S P A C E U S A G E & F R A G M E N T A T I O N for ", heapName); 1922 ast->print_cr(" The heap space covered by one granule is occupied to a various extend.\n" 1923 " The granule occupancy is displayed by one decimal digit per granule.\n"); 1924 if (segment_granules) { 1925 ast->print_cr(" You have selected granule size to be as small as segment size.\n" 1926 " As a result, each granule contains exactly one block (or a part of one block)\n" 1927 " or is displayed as empty (' ') if it's BlobType does not match the selection.\n" 1928 " Occupied granules show their BlobType character, see legend.\n"); 1929 print_blobType_legend(ast); 1930 } else { 1931 ast->print_cr(" These digits represent a fill percentage range (see legend).\n"); 1932 print_space_legend(ast); 1933 } 1934 BUFFEREDSTREAM_FLUSH_LOCKED("") 1935 } 1936 1937 { 1938 if (segment_granules) { 1939 printBox(ast, '-', "Total (all types) space consumption for granule size == segment size", NULL); 1940 1941 granules_per_line = 128; 1942 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1943 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1944 print_blobType_single(ast, StatArray[ix].type); 1945 } 1946 } else { 1947 printBox(ast, '-', "Total (all types) space consumption. ' ' indicates empty, '*' indicates full.", NULL); 1948 1949 granules_per_line = 128; 1950 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1951 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1952 unsigned int space = StatArray[ix].t1_space + StatArray[ix].t2_space + StatArray[ix].tx_space 1953 + StatArray[ix].stub_space + StatArray[ix].dead_space; 1954 print_space_single(ast, space); 1955 } 1956 } 1957 BUFFEREDSTREAM_FLUSH_LOCKED("|\n\n\n") 1958 } 1959 1960 { 1961 if (nBlocks_t1 > 0) { 1962 printBox(ast, '-', "Tier1 space consumption. ' ' indicates empty, '*' indicates full", NULL); 1963 1964 granules_per_line = 128; 1965 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1966 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1967 if (segment_granules && StatArray[ix].t1_space > 0) { 1968 print_blobType_single(ast, StatArray[ix].type); 1969 } else { 1970 print_space_single(ast, StatArray[ix].t1_space); 1971 } 1972 } 1973 ast->print("|"); 1974 } else { 1975 ast->print("No Tier1 nMethods found in CodeHeap."); 1976 } 1977 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1978 } 1979 1980 { 1981 if (nBlocks_t2 > 0) { 1982 printBox(ast, '-', "Tier2 space consumption. ' ' indicates empty, '*' indicates full", NULL); 1983 1984 granules_per_line = 128; 1985 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 1986 print_line_delim(out, ast, low_bound, ix, granules_per_line); 1987 if (segment_granules && StatArray[ix].t2_space > 0) { 1988 print_blobType_single(ast, StatArray[ix].type); 1989 } else { 1990 print_space_single(ast, StatArray[ix].t2_space); 1991 } 1992 } 1993 ast->print("|"); 1994 } else { 1995 ast->print("No Tier2 nMethods found in CodeHeap."); 1996 } 1997 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 1998 } 1999 2000 { 2001 if (nBlocks_alive > 0) { 2002 printBox(ast, '-', "not_used/not_entrant/not_installed space consumption. ' ' indicates empty, '*' indicates full", NULL); 2003 2004 granules_per_line = 128; 2005 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2006 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2007 if (segment_granules && StatArray[ix].tx_space > 0) { 2008 print_blobType_single(ast, StatArray[ix].type); 2009 } else { 2010 print_space_single(ast, StatArray[ix].tx_space); 2011 } 2012 } 2013 ast->print("|"); 2014 } else { 2015 ast->print("No Tier2 nMethods found in CodeHeap."); 2016 } 2017 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2018 } 2019 2020 { 2021 if (nBlocks_stub > 0) { 2022 printBox(ast, '-', "Stub and Blob space consumption. ' ' indicates empty, '*' indicates full", NULL); 2023 2024 granules_per_line = 128; 2025 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2026 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2027 if (segment_granules && StatArray[ix].stub_space > 0) { 2028 print_blobType_single(ast, StatArray[ix].type); 2029 } else { 2030 print_space_single(ast, StatArray[ix].stub_space); 2031 } 2032 } 2033 ast->print("|"); 2034 } else { 2035 ast->print("No Stubs and Blobs found in CodeHeap."); 2036 } 2037 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2038 } 2039 2040 { 2041 if (nBlocks_dead > 0) { 2042 printBox(ast, '-', "Dead space consumption. ' ' indicates empty, '*' indicates full", NULL); 2043 2044 granules_per_line = 128; 2045 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2046 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2047 print_space_single(ast, StatArray[ix].dead_space); 2048 } 2049 ast->print("|"); 2050 } else { 2051 ast->print("No dead nMethods found in CodeHeap."); 2052 } 2053 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2054 } 2055 2056 { 2057 if (!segment_granules) { // Prevent totally redundant printouts 2058 printBox(ast, '-', "Space consumption by tier (combined): <t1%>:<t2%>:<s%>. ' ' indicates empty, '*' indicates full", NULL); 2059 2060 granules_per_line = 24; 2061 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2062 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2063 2064 if (segment_granules && StatArray[ix].t1_space > 0) { 2065 print_blobType_single(ast, StatArray[ix].type); 2066 } else { 2067 print_space_single(ast, StatArray[ix].t1_space); 2068 } 2069 ast->print(":"); 2070 if (segment_granules && StatArray[ix].t2_space > 0) { 2071 print_blobType_single(ast, StatArray[ix].type); 2072 } else { 2073 print_space_single(ast, StatArray[ix].t2_space); 2074 } 2075 ast->print(":"); 2076 if (segment_granules && StatArray[ix].stub_space > 0) { 2077 print_blobType_single(ast, StatArray[ix].type); 2078 } else { 2079 print_space_single(ast, StatArray[ix].stub_space); 2080 } 2081 ast->print(" "); 2082 } 2083 ast->print("|"); 2084 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2085 } 2086 } 2087 } 2088 2089 void CodeHeapState::print_age(outputStream* out, CodeHeap* heap) { 2090 if (!initialization_complete) { 2091 return; 2092 } 2093 2094 const char* heapName = get_heapName(heap); 2095 get_HeapStatGlobals(out, heapName); 2096 2097 if ((StatArray == NULL) || (alloc_granules == 0)) { 2098 return; 2099 } 2100 BUFFEREDSTREAM_DECL(ast, out) 2101 2102 unsigned int granules_per_line = 32; 2103 char* low_bound = heap->low_boundary(); 2104 2105 { 2106 printBox(ast, '=', "M E T H O D A G E by CompileID for ", heapName); 2107 ast->print_cr(" The age of a compiled method in the CodeHeap is not available as a\n" 2108 " time stamp. Instead, a relative age is deducted from the method's compilation ID.\n" 2109 " Age information is available for tier1 and tier2 methods only. There is no\n" 2110 " age information for stubs and blobs, because they have no compilation ID assigned.\n" 2111 " Information for the youngest method (highest ID) in the granule is printed.\n" 2112 " Refer to the legend to learn how method age is mapped to the displayed digit."); 2113 print_age_legend(ast); 2114 BUFFEREDSTREAM_FLUSH_LOCKED("") 2115 } 2116 2117 { 2118 printBox(ast, '-', "Age distribution. '0' indicates youngest 1/256, '8': oldest half, ' ': no age information", NULL); 2119 2120 granules_per_line = 128; 2121 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2122 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2123 unsigned int age1 = StatArray[ix].t1_age; 2124 unsigned int age2 = StatArray[ix].t2_age; 2125 unsigned int agex = StatArray[ix].tx_age; 2126 unsigned int age = age1 > age2 ? age1 : age2; 2127 age = age > agex ? age : agex; 2128 print_age_single(ast, age); 2129 } 2130 ast->print("|"); 2131 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2132 } 2133 2134 { 2135 if (nBlocks_t1 > 0) { 2136 printBox(ast, '-', "Tier1 age distribution. '0' indicates youngest 1/256, '8': oldest half, ' ': no age information", NULL); 2137 2138 granules_per_line = 128; 2139 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2140 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2141 print_age_single(ast, StatArray[ix].t1_age); 2142 } 2143 ast->print("|"); 2144 } else { 2145 ast->print("No Tier1 nMethods found in CodeHeap."); 2146 } 2147 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2148 } 2149 2150 { 2151 if (nBlocks_t2 > 0) { 2152 printBox(ast, '-', "Tier2 age distribution. '0' indicates youngest 1/256, '8': oldest half, ' ': no age information", NULL); 2153 2154 granules_per_line = 128; 2155 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2156 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2157 print_age_single(ast, StatArray[ix].t2_age); 2158 } 2159 ast->print("|"); 2160 } else { 2161 ast->print("No Tier2 nMethods found in CodeHeap."); 2162 } 2163 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2164 } 2165 2166 { 2167 if (nBlocks_alive > 0) { 2168 printBox(ast, '-', "not_used/not_entrant/not_installed age distribution. '0' indicates youngest 1/256, '8': oldest half, ' ': no age information", NULL); 2169 2170 granules_per_line = 128; 2171 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2172 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2173 print_age_single(ast, StatArray[ix].tx_age); 2174 } 2175 ast->print("|"); 2176 } else { 2177 ast->print("No Tier2 nMethods found in CodeHeap."); 2178 } 2179 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2180 } 2181 2182 { 2183 if (!segment_granules) { // Prevent totally redundant printouts 2184 printBox(ast, '-', "age distribution by tier <a1>:<a2>. '0' indicates youngest 1/256, '8': oldest half, ' ': no age information", NULL); 2185 2186 granules_per_line = 32; 2187 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2188 print_line_delim(out, ast, low_bound, ix, granules_per_line); 2189 print_age_single(ast, StatArray[ix].t1_age); 2190 ast->print(":"); 2191 print_age_single(ast, StatArray[ix].t2_age); 2192 ast->print(" "); 2193 } 2194 ast->print("|"); 2195 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n\n") 2196 } 2197 } 2198 } 2199 2200 2201 void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) { 2202 if (!initialization_complete) { 2203 return; 2204 } 2205 2206 const char* heapName = get_heapName(heap); 2207 get_HeapStatGlobals(out, heapName); 2208 2209 if ((StatArray == NULL) || (alloc_granules == 0)) { 2210 return; 2211 } 2212 BUFFEREDSTREAM_DECL(ast, out) 2213 2214 unsigned int granules_per_line = 128; 2215 char* low_bound = heap->low_boundary(); 2216 CodeBlob* last_blob = NULL; 2217 bool name_in_addr_range = true; 2218 bool have_locks = holding_required_locks(); 2219 2220 //---< print at least 128K per block (i.e. between headers) >--- 2221 if (granules_per_line*granule_size < 128*K) { 2222 granules_per_line = (unsigned int)((128*K)/granule_size); 2223 } 2224 2225 printBox(ast, '=', "M E T H O D N A M E S for ", heapName); 2226 ast->print_cr(" Method names are dynamically retrieved from the code cache at print time.\n" 2227 " Due to the living nature of the code heap and because the CodeCache_lock\n" 2228 " is not continuously held, the displayed name might be wrong or no name\n" 2229 " might be found at all. The likelihood for that to happen increases\n" 2230 " over time passed between aggregation and print steps.\n"); 2231 BUFFEREDSTREAM_FLUSH_LOCKED("") 2232 2233 for (unsigned int ix = 0; ix < alloc_granules; ix++) { 2234 //---< print a new blob on a new line >--- 2235 if (ix%granules_per_line == 0) { 2236 if (!name_in_addr_range) { 2237 ast->print_cr("No methods, blobs, or stubs found in this address range"); 2238 } 2239 name_in_addr_range = false; 2240 2241 size_t end_ix = (ix+granules_per_line <= alloc_granules) ? ix+granules_per_line : alloc_granules; 2242 ast->cr(); 2243 ast->print_cr("--------------------------------------------------------------------"); 2244 ast->print_cr("Address range [" INTPTR_FORMAT "," INTPTR_FORMAT "), " SIZE_FORMAT "k", p2i(low_bound+ix*granule_size), p2i(low_bound + end_ix*granule_size), (end_ix - ix)*granule_size/(size_t)K); 2245 ast->print_cr("--------------------------------------------------------------------"); 2246 BUFFEREDSTREAM_FLUSH_AUTO("") 2247 } 2248 // Only check granule if it contains at least one blob. 2249 unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count + 2250 StatArray[ix].stub_count + StatArray[ix].dead_count; 2251 if (nBlobs > 0 ) { 2252 for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) { 2253 // heap->find_start() is safe. Only works on _segmap. 2254 // Returns NULL or void*. Returned CodeBlob may be uninitialized. 2255 char* this_seg = low_bound + ix*granule_size + is; 2256 CodeBlob* this_blob = (CodeBlob*)(heap->find_start(this_seg)); 2257 bool blob_is_safe = blob_access_is_safe(this_blob); 2258 // blob could have been flushed, freed, and merged. 2259 // this_blob < last_blob is an indicator for that. 2260 if (blob_is_safe && (this_blob > last_blob)) { 2261 last_blob = this_blob; 2262 2263 //---< get type and name >--- 2264 blobType cbType = noType; 2265 if (segment_granules) { 2266 cbType = (blobType)StatArray[ix].type; 2267 } else { 2268 //---< access these fields only if we own the CodeCache_lock >--- 2269 if (have_locks) { 2270 cbType = get_cbType(this_blob); 2271 } 2272 } 2273 2274 //---< access these fields only if we own the CodeCache_lock >--- 2275 const char* blob_name = "<unavailable>"; 2276 nmethod* nm = NULL; 2277 if (have_locks) { 2278 blob_name = this_blob->name(); 2279 nm = this_blob->as_nmethod_or_null(); 2280 // this_blob->name() could return NULL if no name was given to CTOR. Inlined, maybe invisible on stack 2281 if (blob_name == NULL) { 2282 blob_name = "<unavailable>"; 2283 } 2284 } 2285 2286 //---< print table header for new print range >--- 2287 if (!name_in_addr_range) { 2288 name_in_addr_range = true; 2289 ast->fill_to(51); 2290 ast->print("%9s", "compiler"); 2291 ast->fill_to(61); 2292 ast->print_cr("%6s", "method"); 2293 ast->print_cr("%18s %13s %17s %9s %5s %18s %s", "Addr(module) ", "offset", "size", " type lvl", " temp", "blobType ", "Name"); 2294 BUFFEREDSTREAM_FLUSH_AUTO("") 2295 } 2296 2297 //---< print line prefix (address and offset from CodeHeap start) >--- 2298 ast->print(INTPTR_FORMAT, p2i(this_blob)); 2299 ast->fill_to(19); 2300 ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound)); 2301 ast->fill_to(33); 2302 2303 // access nmethod and Method fields only if we own the CodeCache_lock. 2304 // This fact is implicitly transported via nm != NULL. 2305 if (nmethod_access_is_safe(nm)) { 2306 Method* method = nm->method(); 2307 ResourceMark rm; 2308 //---< collect all data to locals as quickly as possible >--- 2309 unsigned int total_size = nm->total_size(); 2310 int hotness = nm->hotness_counter(); 2311 bool get_name = (cbType == nMethod_inuse) || (cbType == nMethod_notused); 2312 //---< nMethod size in hex >--- 2313 ast->print(PTR32_FORMAT, total_size); 2314 ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K); 2315 //---< compiler information >--- 2316 ast->fill_to(51); 2317 ast->print("%5s %3d", compTypeName[StatArray[ix].compiler], StatArray[ix].level); 2318 //---< method temperature >--- 2319 ast->fill_to(62); 2320 ast->print("%5d", hotness); 2321 //---< name and signature >--- 2322 ast->fill_to(62+6); 2323 ast->print("%s", blobTypeName[cbType]); 2324 ast->fill_to(82+6); 2325 if (cbType == nMethod_dead) { 2326 ast->print("%14s", " zombie method"); 2327 } 2328 2329 if (get_name) { 2330 Symbol* methName = method->name(); 2331 const char* methNameS = (methName == NULL) ? NULL : methName->as_C_string(); 2332 methNameS = (methNameS == NULL) ? "<method name unavailable>" : methNameS; 2333 Symbol* methSig = method->signature(); 2334 const char* methSigS = (methSig == NULL) ? NULL : methSig->as_C_string(); 2335 methSigS = (methSigS == NULL) ? "<method signature unavailable>" : methSigS; 2336 ast->print("%s", methNameS); 2337 ast->print("%s", methSigS); 2338 } else { 2339 ast->print("%s", blob_name); 2340 } 2341 } else if (blob_is_safe) { 2342 ast->fill_to(62+6); 2343 ast->print("%s", blobTypeName[cbType]); 2344 ast->fill_to(82+6); 2345 ast->print("%s", blob_name); 2346 } else { 2347 ast->fill_to(62+6); 2348 ast->print("<stale blob>"); 2349 } 2350 ast->cr(); 2351 BUFFEREDSTREAM_FLUSH_AUTO("") 2352 } else if (!blob_is_safe && (this_blob != last_blob) && (this_blob != NULL)) { 2353 last_blob = this_blob; 2354 } 2355 } 2356 } // nBlobs > 0 2357 } 2358 BUFFEREDSTREAM_FLUSH_LOCKED("\n\n") 2359 } 2360 2361 2362 void CodeHeapState::printBox(outputStream* ast, const char border, const char* text1, const char* text2) { 2363 unsigned int lineLen = 1 + 2 + 2 + 1; 2364 char edge, frame; 2365 2366 if (text1 != NULL) { 2367 lineLen += (unsigned int)strlen(text1); // text1 is much shorter than MAX_INT chars. 2368 } 2369 if (text2 != NULL) { 2370 lineLen += (unsigned int)strlen(text2); // text2 is much shorter than MAX_INT chars. 2371 } 2372 if (border == '-') { 2373 edge = '+'; 2374 frame = '|'; 2375 } else { 2376 edge = border; 2377 frame = border; 2378 } 2379 2380 ast->print("%c", edge); 2381 for (unsigned int i = 0; i < lineLen-2; i++) { 2382 ast->print("%c", border); 2383 } 2384 ast->print_cr("%c", edge); 2385 2386 ast->print("%c ", frame); 2387 if (text1 != NULL) { 2388 ast->print("%s", text1); 2389 } 2390 if (text2 != NULL) { 2391 ast->print("%s", text2); 2392 } 2393 ast->print_cr(" %c", frame); 2394 2395 ast->print("%c", edge); 2396 for (unsigned int i = 0; i < lineLen-2; i++) { 2397 ast->print("%c", border); 2398 } 2399 ast->print_cr("%c", edge); 2400 } 2401 2402 void CodeHeapState::print_blobType_legend(outputStream* out) { 2403 out->cr(); 2404 printBox(out, '-', "Block types used in the following CodeHeap dump", NULL); 2405 for (int type = noType; type < lastType; type += 1) { 2406 out->print_cr(" %c - %s", blobTypeChar[type], blobTypeName[type]); 2407 } 2408 out->print_cr(" -----------------------------------------------------"); 2409 out->cr(); 2410 } 2411 2412 void CodeHeapState::print_space_legend(outputStream* out) { 2413 unsigned int indicator = 0; 2414 unsigned int age_range = 256; 2415 unsigned int range_beg = latest_compilation_id; 2416 out->cr(); 2417 printBox(out, '-', "Space ranges, based on granule occupancy", NULL); 2418 out->print_cr(" - 0%% == occupancy"); 2419 for (int i=0; i<=9; i++) { 2420 out->print_cr(" %d - %3d%% < occupancy < %3d%%", i, 10*i, 10*(i+1)); 2421 } 2422 out->print_cr(" * - 100%% == occupancy"); 2423 out->print_cr(" ----------------------------------------------"); 2424 out->cr(); 2425 } 2426 2427 void CodeHeapState::print_age_legend(outputStream* out) { 2428 unsigned int indicator = 0; 2429 unsigned int age_range = 256; 2430 unsigned int range_beg = latest_compilation_id; 2431 out->cr(); 2432 printBox(out, '-', "Age ranges, based on compilation id", NULL); 2433 while (age_range > 0) { 2434 out->print_cr(" %d - %6d to %6d", indicator, range_beg, latest_compilation_id - latest_compilation_id/age_range); 2435 range_beg = latest_compilation_id - latest_compilation_id/age_range; 2436 age_range /= 2; 2437 indicator += 1; 2438 } 2439 out->print_cr(" -----------------------------------------"); 2440 out->cr(); 2441 } 2442 2443 void CodeHeapState::print_blobType_single(outputStream* out, u2 /* blobType */ type) { 2444 out->print("%c", blobTypeChar[type]); 2445 } 2446 2447 void CodeHeapState::print_count_single(outputStream* out, unsigned short count) { 2448 if (count >= 16) out->print("*"); 2449 else if (count > 0) out->print("%1.1x", count); 2450 else out->print(" "); 2451 } 2452 2453 void CodeHeapState::print_space_single(outputStream* out, unsigned short space) { 2454 size_t space_in_bytes = ((unsigned int)space)<<log2_seg_size; 2455 char fraction = (space == 0) ? ' ' : (space_in_bytes >= granule_size-1) ? '*' : char('0'+10*space_in_bytes/granule_size); 2456 out->print("%c", fraction); 2457 } 2458 2459 void CodeHeapState::print_age_single(outputStream* out, unsigned int age) { 2460 unsigned int indicator = 0; 2461 unsigned int age_range = 256; 2462 if (age > 0) { 2463 while ((age_range > 0) && (latest_compilation_id-age > latest_compilation_id/age_range)) { 2464 age_range /= 2; 2465 indicator += 1; 2466 } 2467 out->print("%c", char('0'+indicator)); 2468 } else { 2469 out->print(" "); 2470 } 2471 } 2472 2473 void CodeHeapState::print_line_delim(outputStream* out, outputStream* ast, char* low_bound, unsigned int ix, unsigned int gpl) { 2474 if (ix % gpl == 0) { 2475 if (ix > 0) { 2476 ast->print("|"); 2477 } 2478 ast->cr(); 2479 assert(out == ast, "must use the same stream!"); 2480 2481 ast->print(INTPTR_FORMAT, p2i(low_bound + ix*granule_size)); 2482 ast->fill_to(19); 2483 ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size)); 2484 } 2485 } 2486 2487 void CodeHeapState::print_line_delim(outputStream* out, bufferedStream* ast, char* low_bound, unsigned int ix, unsigned int gpl) { 2488 assert(out != ast, "must not use the same stream!"); 2489 if (ix % gpl == 0) { 2490 if (ix > 0) { 2491 ast->print("|"); 2492 } 2493 ast->cr(); 2494 2495 // can't use BUFFEREDSTREAM_FLUSH_IF("", 512) here. 2496 // can't use this expression. bufferedStream::capacity() does not exist. 2497 // if ((ast->capacity() - ast->size()) < 512) { 2498 // Assume instead that default bufferedStream capacity (4K) was used. 2499 if (ast->size() > 3*K) { 2500 ttyLocker ttyl; 2501 out->print("%s", ast->as_string()); 2502 ast->reset(); 2503 } 2504 2505 ast->print(INTPTR_FORMAT, p2i(low_bound + ix*granule_size)); 2506 ast->fill_to(19); 2507 ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size)); 2508 } 2509 } 2510 2511 // Find out which blob type we have at hand. 2512 // Return "noType" if anything abnormal is detected. 2513 CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) { 2514 if (cb != NULL) { 2515 if (cb->is_runtime_stub()) return runtimeStub; 2516 if (cb->is_deoptimization_stub()) return deoptimizationStub; 2517 if (cb->is_uncommon_trap_stub()) return uncommonTrapStub; 2518 if (cb->is_exception_stub()) return exceptionStub; 2519 if (cb->is_safepoint_stub()) return safepointStub; 2520 if (cb->is_adapter_blob()) return adapterBlob; 2521 if (cb->is_method_handles_adapter_blob()) return mh_adapterBlob; 2522 if (cb->is_buffer_blob()) return bufferBlob; 2523 2524 //---< access these fields only if we own CodeCache_lock and Compile_lock >--- 2525 // Should be ensured by caller. aggregate() and print_names() do that. 2526 if (holding_required_locks()) { 2527 nmethod* nm = cb->as_nmethod_or_null(); 2528 if (nm != NULL) { // no is_readable check required, nm = (nmethod*)cb. 2529 if (nm->is_zombie()) return nMethod_dead; 2530 if (nm->is_unloaded()) return nMethod_unloaded; 2531 if (nm->is_in_use()) return nMethod_inuse; 2532 if (nm->is_alive() && !(nm->is_not_entrant())) return nMethod_notused; 2533 if (nm->is_alive()) return nMethod_alive; 2534 return nMethod_dead; 2535 } 2536 } 2537 } 2538 return noType; 2539 } 2540 2541 // make sure the blob at hand is not garbage. 2542 bool CodeHeapState::blob_access_is_safe(CodeBlob* this_blob) { 2543 return (this_blob != NULL) && // a blob must have been found, obviously 2544 (this_blob->header_size() >= 0) && 2545 (this_blob->relocation_size() >= 0) && 2546 ((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) && 2547 ((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin())); 2548 } 2549 2550 // make sure the nmethod at hand (and the linked method) is not garbage. 2551 bool CodeHeapState::nmethod_access_is_safe(nmethod* nm) { 2552 Method* method = (nm == NULL) ? NULL : nm->method(); // nm->method() was found to be uninitialized, i.e. != NULL, but invalid. 2553 return (nm != NULL) && (method != NULL) && nm->is_alive() && (method->signature() != NULL); 2554 } 2555 2556 bool CodeHeapState::holding_required_locks() { 2557 return SafepointSynchronize::is_at_safepoint() || 2558 (CodeCache_lock->owned_by_self() && Compile_lock->owned_by_self()); 2559 }