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