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