8198691: CodeHeap State Analytics

Reviewed-by: kvn, thartmann
This commit is contained in:
Lutz Schmidt 2018-03-26 12:59:45 -07:00
parent 9b9d9308ed
commit b7cb1a07e4
14 changed files with 2832 additions and 19 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,12 +26,15 @@
#include "aot/aotLoader.hpp"
#include "code/codeBlob.hpp"
#include "code/codeCache.hpp"
#include "code/codeHeapState.hpp"
#include "code/compiledIC.hpp"
#include "code/dependencies.hpp"
#include "code/icBuffer.hpp"
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
#include "compiler/compileBroker.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/iterator.hpp"
#include "memory/resourceArea.hpp"
@ -1363,10 +1366,19 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
print_summary(&s);
}
{
ttyLocker ttyl;
tty->print("%s", s.as_string());
}
if (heap->full_count() == 0) {
LogTarget(Debug, codecache) lt;
if (lt.is_enabled()) {
CompileBroker::print_heapinfo(tty, "all", "4096"); // details, may be a lot!
}
}
}
heap->report_full();
EventCodeCacheFull event;
@ -1639,3 +1651,54 @@ void CodeCache::log_state(outputStream* st) {
blob_count(), nmethod_count(), adapter_count(),
unallocated_capacity());
}
//---< BEGIN >--- CodeHeap State Analytics.
void CodeCache::aggregate(outputStream *out, const char* granularity) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::aggregate(out, (*heap), granularity);
}
}
void CodeCache::discard(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::discard(out, (*heap));
}
}
void CodeCache::print_usedSpace(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_usedSpace(out, (*heap));
}
}
void CodeCache::print_freeSpace(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_freeSpace(out, (*heap));
}
}
void CodeCache::print_count(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_count(out, (*heap));
}
}
void CodeCache::print_space(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_space(out, (*heap));
}
}
void CodeCache::print_age(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_age(out, (*heap));
}
}
void CodeCache::print_names(outputStream *out) {
FOR_ALL_ALLOCABLE_HEAPS(heap) {
CodeHeapState::print_names(out, (*heap));
}
}
//---< END >--- CodeHeap State Analytics.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -296,6 +296,17 @@ class CodeCache : AllStatic {
CodeHeap* heap = get_code_heap(code_blob_type);
return (heap != NULL) ? heap->full_count() : 0;
}
// CodeHeap State Analytics.
// interface methods for CodeHeap printing, called by CompileBroker
static void aggregate(outputStream *out, const char* granularity);
static void discard(outputStream *out);
static void print_usedSpace(outputStream *out);
static void print_freeSpace(outputStream *out);
static void print_count(outputStream *out);
static void print_space(outputStream *out);
static void print_age(outputStream *out);
static void print_names(outputStream *out);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_CODE_CODEHEAPSTATE_HPP
#define SHARE_CODE_CODEHEAPSTATE_HPP
#include "memory/heap.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
class CodeHeapState : public CHeapObj<mtCode> {
public:
enum compType {
noComp = 0, // must be! due to initialization by memset to zero
c1,
c2,
jvmci,
lastComp
};
enum blobType {
noType = 0, // must be! due to initialization by memset to zero
// The nMethod_* values correspond 1:1 to the CompiledMethod enum values.
nMethod_inuse, // executable. This is the "normal" state for a nmethod.
nMethod_notused, // assumed inactive, marked not entrant. Could be revived if necessary.
nMethod_notentrant, // no new activations allowed, marked for deoptimization. Old activations may still exist.
// Will transition to "zombie" after all activations are gone.
nMethod_zombie, // No more activations exist, ready for purge (remove from code cache).
nMethod_unloaded, // No activations exist, should not be called. Transient state on the way to "zombie".
nMethod_alive = nMethod_notentrant, // Combined state: nmethod may have activations, thus can't be purged.
nMethod_dead = nMethod_zombie, // Combined state: nmethod does not have any activations.
runtimeStub = nMethod_unloaded + 1,
ricochetStub,
deoptimizationStub,
uncommonTrapStub,
exceptionStub,
safepointStub,
adapterBlob,
mh_adapterBlob,
bufferBlob,
lastType
};
private:
static void prepare_StatArray(outputStream* out, size_t nElem, size_t granularity, const char* heapName);
static void prepare_FreeArray(outputStream* out, unsigned int nElem, const char* heapName);
static void prepare_TopSizeArray(outputStream* out, unsigned int nElem, const char* heapName);
static void prepare_SizeDistArray(outputStream* out, unsigned int nElem, const char* heapName);
static void discard_StatArray(outputStream* out);
static void discard_FreeArray(outputStream* out);
static void discard_TopSizeArray(outputStream* out);
static void discard_SizeDistArray(outputStream* out);
static void update_SizeDistArray(outputStream* out, unsigned int len);
static const char* get_heapName(CodeHeap* heap);
static unsigned int findHeapIndex(outputStream* out, const char* heapName);
static void get_HeapStatGlobals(outputStream* out, const char* heapName);
static void set_HeapStatGlobals(outputStream* out, const char* heapName);
static void printBox(outputStream* out, const char border, const char* text1, const char* text2);
static void print_blobType_legend(outputStream* out);
static void print_space_legend(outputStream* out);
static void print_age_legend(outputStream* out);
static void print_blobType_single(outputStream *ast, u2 /* blobType */ type);
static void print_count_single(outputStream *ast, unsigned short count);
static void print_space_single(outputStream *ast, unsigned short space);
static void print_age_single(outputStream *ast, unsigned int age);
static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
static blobType get_cbType(CodeBlob* cb);
public:
static void discard(outputStream* out, CodeHeap* heap);
static void aggregate(outputStream* out, CodeHeap* heap, const char* granularity);
static void print_usedSpace(outputStream* out, CodeHeap* heap);
static void print_freeSpace(outputStream* out, CodeHeap* heap);
static void print_count(outputStream* out, CodeHeap* heap);
static void print_space(outputStream* out, CodeHeap* heap);
static void print_age(outputStream* out, CodeHeap* heap);
static void print_names(outputStream* out, CodeHeap* heap);
};
//----------------
// StatElement
//----------------
// Each analysis granule is represented by an instance of
// this StatElement struct. It collects and aggregates all
// information describing the allocated contents of the granule.
// Free (unallocated) contents is not considered (see FreeBlk for that).
// All StatElements of a heap segment are stored in the related StatArray.
// Current size: 40 bytes + 8 bytes class header.
class StatElement : public CHeapObj<mtCode> {
public:
// A note on ages: The compilation_id easily overflows unsigned short in large systems
unsigned int t1_age; // oldest compilation_id of tier1 nMethods.
unsigned int t2_age; // oldest compilation_id of tier2 nMethods.
unsigned int tx_age; // oldest compilation_id of inactive/not entrant nMethods.
unsigned short t1_space; // in units of _segment_size to "prevent" overflow
unsigned short t2_space; // in units of _segment_size to "prevent" overflow
unsigned short tx_space; // in units of _segment_size to "prevent" overflow
unsigned short dead_space; // in units of _segment_size to "prevent" overflow
unsigned short stub_space; // in units of _segment_size to "prevent" overflow
unsigned short t1_count;
unsigned short t2_count;
unsigned short tx_count;
unsigned short dead_count;
unsigned short stub_count;
CompLevel level; // optimization level (see globalDefinitions.hpp)
//---< replaced the correct enum typing with u2 to save space.
u2 compiler; // compiler which generated this blob. Type is CodeHeapState::compType
u2 type; // used only if granularity == segment_size. Type is CodeHeapState::blobType
};
//-----------
// FreeBlk
//-----------
// Each free block in the code heap is represented by an instance
// of this FreeBlk struct. It collects all information we need to
// know about each free block.
// All FreeBlks of a heap segment are stored in the related FreeArray.
struct FreeBlk : public CHeapObj<mtCode> {
HeapBlock* start; // address of free block
unsigned int len; // length of free block
unsigned int gap; // gap to next free block
unsigned int index; // sequential number of free block
unsigned short n_gapBlocks; // # used blocks in gap
bool stubs_in_gap; // The occupied space between this and the next free block contains (unmovable) stubs or blobs.
};
//--------------
// TopSizeBlk
//--------------
// The n largest blocks in the code heap are represented in an instance
// of this TopSizeBlk struct. It collects all information we need to
// know about those largest blocks.
// All TopSizeBlks of a heap segment are stored in the related TopSizeArray.
struct TopSizeBlk : public CHeapObj<mtCode> {
HeapBlock* start; // address of block
unsigned int len; // length of block, in _segment_size units. Will never overflow int.
unsigned int index; // ordering index, 0 is largest block
// contains array index of next smaller block
// -1 indicates end of list
CompLevel level; // optimization level (see globalDefinitions.hpp)
u2 compiler; // compiler which generated this blob
u2 type; // blob type
};
//---------------------------
// SizeDistributionElement
//---------------------------
// During CodeHeap analysis, each allocated code block is associated with a
// SizeDistributionElement according to its size. Later on, the array of
// SizeDistributionElements is used to print a size distribution bar graph.
// All SizeDistributionElements of a heap segment are stored in the related SizeDistributionArray.
struct SizeDistributionElement : public CHeapObj<mtCode> {
// Range is [rangeStart..rangeEnd).
unsigned int rangeStart; // start of length range, in _segment_size units.
unsigned int rangeEnd; // end of length range, in _segment_size units.
unsigned int lenSum; // length of block, in _segment_size units. Will never overflow int.
unsigned int count; // number of blocks assigned to this range.
};
//----------------
// CodeHeapStat
//----------------
// Because we have to deal with multiple CodeHeaps, we need to
// collect "global" information in a segment-specific way as well.
// Thats what the CodeHeapStat and CodeHeapStatArray are used for.
// Before a heap segment is processed, the contents of the CodeHeapStat
// element is copied to the global variables (get_HeapStatGlobals).
// When processing is done, the possibly modified global variables are
// copied back (set_HeapStatGlobals) to the CodeHeapStat element.
struct CodeHeapStat {
StatElement* StatArray;
struct FreeBlk* FreeArray;
struct TopSizeBlk* TopSizeArray;
struct SizeDistributionElement* SizeDistributionArray;
const char* heapName;
size_t segment_size;
// StatElement data
size_t alloc_granules;
size_t granule_size;
bool segment_granules;
unsigned int nBlocks_t1;
unsigned int nBlocks_t2;
unsigned int nBlocks_alive;
unsigned int nBlocks_dead;
unsigned int nBlocks_unloaded;
unsigned int nBlocks_stub;
// FreeBlk data
unsigned int alloc_freeBlocks;
// UsedBlk data
unsigned int alloc_topSizeBlocks;
unsigned int used_topSizeBlocks;
// method hotness data. Temperature range is [-reset_val..+reset_val]
int avgTemp;
int maxTemp;
int minTemp;
};
#endif // SHARE_CODE_CODEHEAPSTATE_HPP

View file

@ -28,6 +28,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "code/codeHeapState.hpp"
#include "code/dependencyContext.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
@ -2424,3 +2425,111 @@ void CompileBroker::print_last_compile() {
}
}
}
// Print general/accumulated JIT information.
void CompileBroker::print_info(outputStream *out) {
if (out == NULL) out = tty;
out->cr();
out->print_cr("======================");
out->print_cr(" General JIT info ");
out->print_cr("======================");
out->cr();
out->print_cr(" JIT is : %7s", should_compile_new_jobs() ? "on" : "off");
out->print_cr(" Compiler threads : %7d", (int)CICompilerCount);
out->cr();
out->print_cr("CodeCache overview");
out->print_cr("--------------------------------------------------------");
out->cr();
out->print_cr(" Reserved size : " SIZE_FORMAT_W(7) " KB", CodeCache::max_capacity() / K);
out->print_cr(" Committed size : " SIZE_FORMAT_W(7) " KB", CodeCache::capacity() / K);
out->print_cr(" Unallocated capacity : " SIZE_FORMAT_W(7) " KB", CodeCache::unallocated_capacity() / K);
out->cr();
out->cr();
out->print_cr("CodeCache cleaning overview");
out->print_cr("--------------------------------------------------------");
out->cr();
NMethodSweeper::print(out);
out->print_cr("--------------------------------------------------------");
out->cr();
}
// Note: tty_lock must not be held upon entry to this function.
// Print functions called from herein do "micro-locking" on tty_lock.
// That's a tradeoff which keeps together important blocks of output.
// At the same time, continuous tty_lock hold time is kept in check,
// preventing concurrently printing threads from stalling a long time.
void CompileBroker::print_heapinfo(outputStream* out, const char* function, const char* granularity) {
TimeStamp ts_total;
TimeStamp ts;
bool allFun = !strcmp(function, "all");
bool aggregate = !strcmp(function, "aggregate") || !strcmp(function, "analyze") || allFun;
bool usedSpace = !strcmp(function, "UsedSpace") || allFun;
bool freeSpace = !strcmp(function, "FreeSpace") || allFun;
bool methodCount = !strcmp(function, "MethodCount") || allFun;
bool methodSpace = !strcmp(function, "MethodSpace") || allFun;
bool methodAge = !strcmp(function, "MethodAge") || allFun;
bool methodNames = !strcmp(function, "MethodNames") || allFun;
bool discard = !strcmp(function, "discard") || allFun;
if (out == NULL) {
out = tty;
}
if (!(aggregate || usedSpace || freeSpace || methodCount || methodSpace || methodAge || methodNames || discard)) {
out->print_cr("\n__ CodeHeapStateAnalytics: Function %s is not supported", function);
out->cr();
return;
}
ts_total.update(); // record starting point
if (aggregate) {
print_info(out);
}
// We hold the CodeHeapStateAnalytics_lock all the time, from here until we leave this function.
// That helps us getting a consistent view on the CodeHeap, at least for the "all" function.
// When we request individual parts of the analysis via the jcmd interface, it is possible
// that in between another thread (another jcmd user or the vm running into CodeCache OOM)
// updated the aggregated data. That's a tolerable tradeoff because we can't hold a lock
// across user interaction.
ts.update(); // record starting point
MutexLockerEx mu1(CodeHeapStateAnalytics_lock, Mutex::_no_safepoint_check_flag);
out->cr();
out->print_cr("__ CodeHeapStateAnalytics lock wait took %10.3f seconds _________", ts.seconds());
out->cr();
if (aggregate) {
// It is sufficient to hold the CodeCache_lock only for the aggregate step.
// All other functions operate on aggregated data - except MethodNames, but that should be safe.
// The separate CodeHeapStateAnalytics_lock protects the printing functions against
// concurrent aggregate steps. Acquire this lock before acquiring the CodeCache_lock.
// CodeHeapStateAnalytics_lock could be held by a concurrent thread for a long time,
// leading to an unnecessarily long hold time of the CodeCache_lock.
ts.update(); // record starting point
MutexLockerEx mu2(CodeCache_lock, Mutex::_no_safepoint_check_flag);
out->cr();
out->print_cr("__ CodeCache lock wait took %10.3f seconds _________", ts.seconds());
out->cr();
ts.update(); // record starting point
CodeCache::aggregate(out, granularity);
out->cr();
out->print_cr("__ CodeCache lock hold took %10.3f seconds _________", ts.seconds());
out->cr();
}
if (usedSpace) CodeCache::print_usedSpace(out);
if (freeSpace) CodeCache::print_freeSpace(out);
if (methodCount) CodeCache::print_count(out);
if (methodSpace) CodeCache::print_space(out);
if (methodAge) CodeCache::print_age(out);
if (methodNames) CodeCache::print_names(out);
if (discard) CodeCache::discard(out);
out->cr();
out->print_cr("__ CodeHeapStateAnalytics total duration %10.3f seconds _________", ts_total.seconds());
out->cr();
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -381,6 +381,10 @@ public:
// Log that compilation profiling is skipped because metaspace is full.
static void log_metaspace_failure();
// CodeHeap State Analytics.
static void print_info(outputStream *out);
static void print_heapinfo(outputStream *out, const char* function, const char* granularity );
};
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP

View file

@ -129,8 +129,6 @@ class CodeHeap : public CHeapObj<mtCode> {
// Iteration helpers
void* next_used(HeapBlock* b) const;
HeapBlock* first_block() const;
HeapBlock* next_block(HeapBlock* b) const;
HeapBlock* block_start(void* p) const;
// to perform additional actions on creation of executable code
@ -179,6 +177,12 @@ class CodeHeap : public CHeapObj<mtCode> {
size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit
static size_t header_size(); // returns the header size for each heap block
size_t segment_size() const { return _segment_size; } // for CodeHeapState
HeapBlock* first_block() const; // for CodeHeapState
HeapBlock* next_block(HeapBlock* b) const; // for CodeHeapState
FreeBlock* freelist() const { return _freelist; } // for CodeHeapState
size_t allocated_in_freelist() const { return _freelist_segments * CodeCacheSegmentSize; }
int freelist_length() const { return _freelist_length; } // number of elements in the freelist

View file

@ -316,8 +316,13 @@ void print_statistics() {
CodeCache::print();
}
if (PrintMethodFlushingStatistics) {
NMethodSweeper::print();
// CodeHeap State Analytics.
// Does also call NMethodSweeper::print(tty)
LogTarget(Trace, codecache) lt;
if (lt.is_enabled()) {
CompileBroker::print_heapinfo(NULL, "all", "4096"); // details
} else if (PrintMethodFlushingStatistics) {
NMethodSweeper::print(tty);
}
if (PrintCodeCache2) {
@ -379,8 +384,13 @@ void print_statistics() {
CodeCache::print();
}
if (PrintMethodFlushingStatistics) {
NMethodSweeper::print();
// CodeHeap State Analytics.
// Does also call NMethodSweeper::print(tty)
LogTarget(Trace, codecache) lt;
if (lt.is_enabled()) {
CompileBroker::print_heapinfo(NULL, "all", "4096"); // details
} else if (PrintMethodFlushingStatistics) {
NMethodSweeper::print(tty);
}
#ifdef COMPILER2

View file

@ -137,6 +137,7 @@ Mutex* JfrStream_lock = NULL;
#ifndef SUPPORTS_NATIVE_CX8
Mutex* UnsafeJlong_lock = NULL;
#endif
Monitor* CodeHeapStateAnalytics_lock = NULL;
Mutex* MetaspaceExpand_lock = NULL;
@ -301,6 +302,8 @@ void mutex_init() {
#ifndef SUPPORTS_NATIVE_CX8
def(UnsafeJlong_lock , PaddedMutex , special, false, Monitor::_safepoint_check_never);
#endif
def(CodeHeapStateAnalytics_lock , PaddedMutex , leaf, true, Monitor::_safepoint_check_never);
}
GCMutexLocker::GCMutexLocker(Monitor * mutex) {

View file

@ -140,6 +140,9 @@ extern Mutex* UnsafeJlong_lock; // provides Unsafe atomic updat
extern Mutex* MetaspaceExpand_lock; // protects Metaspace virtualspace and chunk expansions
extern Monitor* CodeHeapStateAnalytics_lock; // lock print functions against concurrent analyze functions.
// Only used locally in PrintCodeCacheLayout processing.
// A MutexLocker provides mutual exclusion with respect to a given mutex
// for the scope which contains the locker. The lock is an OS lock, not
// an object lock, and the two do not interoperate. Do not use Mutex-based

View file

@ -824,12 +824,13 @@ void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {
}
}
void NMethodSweeper::print() {
void NMethodSweeper::print(outputStream* out) {
ttyLocker ttyl;
tty->print_cr("Code cache sweeper statistics:");
tty->print_cr(" Total sweep time: %1.0lfms", (double)_total_time_sweeping.value()/1000000);
tty->print_cr(" Total number of full sweeps: %ld", _total_nof_code_cache_sweeps);
tty->print_cr(" Total number of flushed methods: %ld(%ld C2 methods)", _total_nof_methods_reclaimed,
out = (out == NULL) ? tty : out;
out->print_cr("Code cache sweeper statistics:");
out->print_cr(" Total sweep time: %1.0lf ms", (double)_total_time_sweeping.value()/1000000);
out->print_cr(" Total number of full sweeps: %ld", _total_nof_code_cache_sweeps);
out->print_cr(" Total number of flushed methods: %ld (thereof %ld C2 methods)", _total_nof_methods_reclaimed,
_total_nof_c2_methods_reclaimed);
tty->print_cr(" Total size of flushed methods: " SIZE_FORMAT "kB", _total_flushed_size/K);
out->print_cr(" Total size of flushed methods: " SIZE_FORMAT " kB", _total_flushed_size/K);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -125,7 +125,8 @@ class NMethodSweeper : public AllStatic {
static void report_state_change(nmethod* nm);
static void possibly_enable_sweeper();
static void possibly_flush(nmethod* nm);
static void print(); // Printing/debugging
static void print(outputStream* out); // Printing/debugging
static void print() { print(tty); }
};
#endif // SHARE_VM_RUNTIME_SWEEPER_HPP

View file

@ -104,6 +104,7 @@ void DCmdRegistrant::register_dcmds(){
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeHeapAnalyticsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesPrintDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesAddDCmd>(full_export, true, false));
@ -920,6 +921,31 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
CodeCache::print_layout(output());
}
//---< BEGIN >--- CodeHeap State Analytics.
CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_function("function", "Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, discard", "STRING", false, "all"),
_granularity("granularity", "Detail level - smaller value -> more detail", "STRING", false, "4096") {
_dcmdparser.add_dcmd_argument(&_function);
_dcmdparser.add_dcmd_argument(&_granularity);
}
void CodeHeapAnalyticsDCmd::execute(DCmdSource source, TRAPS) {
CompileBroker::print_heapinfo(output(), _function.value(), _granularity.value());
}
int CodeHeapAnalyticsDCmd::num_arguments() {
ResourceMark rm;
CodeHeapAnalyticsDCmd* dcmd = new CodeHeapAnalyticsDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
//---< END >--- CodeHeap State Analytics.
void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) {
DirectivesStack::print(output());
}

View file

@ -641,6 +641,33 @@ public:
virtual void execute(DCmdSource source, TRAPS);
};
//---< BEGIN >--- CodeHeap State Analytics.
class CodeHeapAnalyticsDCmd : public DCmdWithParser {
protected:
DCmdArgument<char*> _function;
DCmdArgument<char*> _granularity;
public:
CodeHeapAnalyticsDCmd(outputStream* output, bool heap);
static const char* name() {
return "Compiler.CodeHeap_Analytics";
}
static const char* description() {
return "Print CodeHeap analytics";
}
static const char* impact() {
return "Low: Depends on code heap size and content. "
"Holds CodeCache_lock during analysis step, usually sub-second duration.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
//---< END >--- CodeHeap State Analytics.
class CompilerDirectivesPrintDCmd : public DCmd {
public:
CompilerDirectivesPrintDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}