mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8198691: CodeHeap State Analytics
Reviewed-by: kvn, thartmann
This commit is contained in:
parent
9b9d9308ed
commit
b7cb1a07e4
14 changed files with 2832 additions and 19 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
2322
src/hotspot/share/code/codeHeapState.cpp
Normal file
2322
src/hotspot/share/code/codeHeapState.cpp
Normal file
File diff suppressed because it is too large
Load diff
229
src/hotspot/share/code/codeHeapState.hpp
Normal file
229
src/hotspot/share/code/codeHeapState.hpp
Normal 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
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue