8185525: Add JFR event for DictionarySizes
Added TableStatistics event Reviewed-by: egahlin, coleenp
This commit is contained in:
parent
c5fc45ee08
commit
d988e67b89
@ -443,7 +443,7 @@ void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
|
||||
void ClassLoaderDataGraph::print_table_statistics(outputStream* st) {
|
||||
FOR_ALL_DICTIONARY(cld) {
|
||||
ResourceMark rm;
|
||||
stringStream tempst;
|
||||
|
@ -112,7 +112,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
|
||||
static void verify_dictionary();
|
||||
static void print_dictionary(outputStream* st);
|
||||
static void print_dictionary_statistics(outputStream* st);
|
||||
static void print_table_statistics(outputStream* st);
|
||||
|
||||
// CMS support.
|
||||
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
|
||||
|
@ -579,6 +579,13 @@ struct SizeFunc : StackObj {
|
||||
};
|
||||
};
|
||||
|
||||
TableStatistics StringTable::get_table_statistics() {
|
||||
static TableStatistics ts;
|
||||
SizeFunc sz;
|
||||
ts = _local_table->statistics_get(Thread::current(), sz, ts);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void StringTable::print_table_statistics(outputStream* st,
|
||||
const char* table_name) {
|
||||
SizeFunc sz;
|
||||
|
@ -99,6 +99,7 @@ private:
|
||||
// The string table
|
||||
static StringTable* the_table() { return _the_table; }
|
||||
size_t table_size();
|
||||
TableStatistics get_table_statistics();
|
||||
|
||||
static OopStorage* weak_storage() { return the_table()->_weak_handles; }
|
||||
|
||||
|
@ -503,6 +503,13 @@ struct SizeFunc : StackObj {
|
||||
};
|
||||
};
|
||||
|
||||
TableStatistics SymbolTable::get_table_statistics() {
|
||||
static TableStatistics ts;
|
||||
SizeFunc sz;
|
||||
ts = _local_table->statistics_get(Thread::current(), sz, ts);
|
||||
return ts;
|
||||
}
|
||||
|
||||
void SymbolTable::print_table_statistics(outputStream* st,
|
||||
const char* table_name) {
|
||||
SizeFunc sz;
|
||||
|
@ -171,6 +171,7 @@ public:
|
||||
// The symbol table
|
||||
static SymbolTable* the_table() { return _the_table; }
|
||||
size_t table_size();
|
||||
TableStatistics get_table_statistics();
|
||||
|
||||
enum {
|
||||
symbol_alloc_batch_size = 8,
|
||||
|
@ -2849,13 +2849,25 @@ void SystemDictionary::dump(outputStream *st, bool verbose) {
|
||||
print_on(st);
|
||||
} else {
|
||||
CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
|
||||
ClassLoaderDataGraph::print_dictionary_statistics(st);
|
||||
ClassLoaderDataGraph::print_table_statistics(st);
|
||||
placeholders()->print_table_statistics(st, "Placeholder Table");
|
||||
constraints()->print_table_statistics(st, "LoaderConstraints Table");
|
||||
_pd_cache_table->print_table_statistics(st, "ProtectionDomainCache Table");
|
||||
pd_cache_table()->print_table_statistics(st, "ProtectionDomainCache Table");
|
||||
}
|
||||
}
|
||||
|
||||
TableStatistics SystemDictionary::placeholders_statistics() {
|
||||
return placeholders()->statistics_calculate();
|
||||
}
|
||||
|
||||
TableStatistics SystemDictionary::loader_constraints_statistics() {
|
||||
return constraints()->statistics_calculate();
|
||||
}
|
||||
|
||||
TableStatistics SystemDictionary::protection_domain_cache_statistics() {
|
||||
return pd_cache_table()->statistics_calculate();
|
||||
}
|
||||
|
||||
// Utility for dumping dictionaries.
|
||||
SystemDictionaryDCmd::SystemDictionaryDCmd(outputStream* output, bool heap) :
|
||||
DCmdWithParser(output, heap),
|
||||
|
@ -681,6 +681,11 @@ private:
|
||||
static oop _java_platform_loader;
|
||||
|
||||
static bool _has_checkPackageAccess;
|
||||
|
||||
public:
|
||||
static TableStatistics placeholders_statistics();
|
||||
static TableStatistics loader_constraints_statistics();
|
||||
static TableStatistics protection_domain_cache_statistics();
|
||||
};
|
||||
|
||||
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2012, 2019, 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
|
||||
@ -692,6 +692,66 @@
|
||||
description="Total size of all allocated metaspace blocks for unsafe anonymous classes (each chunk has several blocks)" />
|
||||
</Event>
|
||||
|
||||
<Event name="SymbolTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="Symbol Table Statistics" period="everyChunk">
|
||||
<Field type="ulong" name="bucketCount" label="Bucket Count" description="Number of buckets" />
|
||||
<Field type="ulong" name="entryCount" label="Entry Count" description="Number of all entries" />
|
||||
<Field type="ulong" contentType="bytes" name="totalFootprint" label="Total Footprint" description="Total memory footprint (the table itself plus all of the entries)" />
|
||||
<Field type="ulong" name="bucketCountMaximum" label="Maximum Bucket Count" description="The maximum bucket length (entries in a single bucket)" />
|
||||
<Field type="float" name="bucketCountAverage" label="Average Bucket Count" description="The average bucket length" />
|
||||
<Field type="float" name="bucketCountVariance" label="Bucket Count Variance" description="How far bucket lengths are spread out from their average value" />
|
||||
<Field type="float" name="bucketCountStandardDeviation" label="Bucket Count Standard Deviation" description="How far bucket lengths are spread out from their mean (expected) value" />
|
||||
<Field type="float" name="insertionRate" label="Insertion Rate" description="How many items were added since last event (per second)" />
|
||||
<Field type="float" name="removalRate" label="Removal Rate" description="How many items were removed since last event (per second)" />
|
||||
</Event>
|
||||
|
||||
<Event name="StringTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="String Table Statistics" period="everyChunk">
|
||||
<Field type="ulong" name="bucketCount" label="Bucket Count" description="Number of buckets" />
|
||||
<Field type="ulong" name="entryCount" label="Entry Count" description="Number of all entries" />
|
||||
<Field type="ulong" contentType="bytes" name="totalFootprint" label="Total Footprint" description="Total memory footprint (the table itself plus all of the entries)" />
|
||||
<Field type="ulong" name="bucketCountMaximum" label="Maximum Bucket Count" description="The maximum bucket length (entries in a single bucket)" />
|
||||
<Field type="float" name="bucketCountAverage" label="Average Bucket Count" description="The average bucket length" />
|
||||
<Field type="float" name="bucketCountVariance" label="Bucket Count Variance" description="How far bucket lengths are spread out from their average value" />
|
||||
<Field type="float" name="bucketCountStandardDeviation" label="Bucket Count Standard Deviation" description="How far bucket lengths are spread out from their mean (expected) value" />
|
||||
<Field type="float" name="insertionRate" label="Insertion Rate" description="How many items were added since last event (per second)" />
|
||||
<Field type="float" name="removalRate" label="Removal Rate" description="How many items were removed since last event (per second)" />
|
||||
</Event>
|
||||
|
||||
<Event name="PlaceholderTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="Placeholder Table Statistics" period="everyChunk">
|
||||
<Field type="ulong" name="bucketCount" label="Bucket Count" description="Number of buckets" />
|
||||
<Field type="ulong" name="entryCount" label="Entry Count" description="Number of all entries" />
|
||||
<Field type="ulong" contentType="bytes" name="totalFootprint" label="Total Footprint" description="Total memory footprint (the table itself plus all of the entries)" />
|
||||
<Field type="ulong" name="bucketCountMaximum" label="Maximum Bucket Count" description="The maximum bucket length (entries in a single bucket)" />
|
||||
<Field type="float" name="bucketCountAverage" label="Average Bucket Count" description="The average bucket length" />
|
||||
<Field type="float" name="bucketCountVariance" label="Bucket Count Variance" description="How far bucket lengths are spread out from their average value" />
|
||||
<Field type="float" name="bucketCountStandardDeviation" label="Bucket Count Standard Deviation" description="How far bucket lengths are spread out from their mean (expected) value" />
|
||||
<Field type="float" name="insertionRate" label="Insertion Rate" description="How many items were added since last event (per second)" />
|
||||
<Field type="float" name="removalRate" label="Removal Rate" description="How many items were removed since last event (per second)" />
|
||||
</Event>
|
||||
|
||||
<Event name="LoaderConstraintsTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="Loader Constraints Table Statistics" period="everyChunk">
|
||||
<Field type="ulong" name="bucketCount" label="Bucket Count" />
|
||||
<Field type="ulong" name="entryCount" label="Entry Count" description="Number of all entries" />
|
||||
<Field type="ulong" contentType="bytes" name="totalFootprint" label="Total Footprint" description="Total memory footprint (the table itself plus all of the entries)" />
|
||||
<Field type="ulong" name="bucketCountMaximum" label="Maximum Bucket Count" description="The maximum bucket length (entries in a single bucket)" />
|
||||
<Field type="float" name="bucketCountAverage" label="Average Bucket Count" description="The average bucket length" />
|
||||
<Field type="float" name="bucketCountVariance" label="Bucket Count Variance" description="How far bucket lengths are spread out from their average value" />
|
||||
<Field type="float" name="bucketCountStandardDeviation" label="Bucket Count Standard Deviation" description="How far bucket lengths are spread out from their mean (expected) value" />
|
||||
<Field type="float" name="insertionRate" label="Insertion Rate" description="How many items were added since last event (per second)" />
|
||||
<Field type="float" name="removalRate" label="Removal Rate" description="How many items were removed since last event (per second)" />
|
||||
</Event>
|
||||
|
||||
<Event name="ProtectionDomainCacheTableStatistics" category="Java Virtual Machine, Runtime, Tables" label="Protection Domain Cache Table Statistics" period="everyChunk">
|
||||
<Field type="ulong" name="bucketCount" label="Bucket Count" description="Number of buckets" />
|
||||
<Field type="ulong" name="entryCount" label="Entry Count" description="Number of all entries" />
|
||||
<Field type="ulong" contentType="bytes" name="totalFootprint" label="Total Footprint" description="Total memory footprint (the table itself plus all of the entries)" />
|
||||
<Field type="ulong" name="bucketCountMaximum" label="Maximum Bucket Count" description="The maximum bucket length (entries in a single bucket)" />
|
||||
<Field type="float" name="bucketCountAverage" label="Average Bucket Count" description="The average bucket length" />
|
||||
<Field type="float" name="bucketCountVariance" label="Bucket Count Variance" description="How far bucket lengths are spread out from their average value" />
|
||||
<Field type="float" name="bucketCountStandardDeviation" label="Bucket Count Standard Deviation" description="How far bucket lengths are spread out from their mean (expected) value" />
|
||||
<Field type="float" name="insertionRate" label="Insertion Rate" description="How many items were added since last event (per second)" />
|
||||
<Field type="float" name="removalRate" label="Removal Rate" description="How many items were removed since last event (per second)" />
|
||||
</Event>
|
||||
|
||||
<Event name="ThreadAllocationStatistics" category="Java Application, Statistics" label="Thread Allocation Statistics" period="everyChunk">
|
||||
<Field type="ulong" contentType="bytes" name="allocated" label="Allocated" description="Approximate number of bytes allocated since thread start" />
|
||||
<Field type="Thread" name="thread" label="Thread" />
|
||||
|
@ -27,6 +27,9 @@
|
||||
#include "classfile/classLoaderDataGraph.hpp"
|
||||
#include "classfile/classLoaderStats.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "gc/g1/g1HeapRegionEventSender.hpp"
|
||||
@ -506,6 +509,46 @@ TRACE_REQUEST_FUNC(ClassLoaderStatistics) {
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
|
||||
template<typename EVENT>
|
||||
static void emit_table_statistics(TableStatistics statistics) {
|
||||
EVENT event;
|
||||
event.set_bucketCount(statistics._number_of_buckets);
|
||||
event.set_entryCount(statistics._number_of_entries);
|
||||
event.set_totalFootprint(statistics._total_footprint);
|
||||
event.set_bucketCountMaximum(statistics._maximum_bucket_size);
|
||||
event.set_bucketCountAverage(statistics._average_bucket_size);
|
||||
event.set_bucketCountVariance(statistics._variance_of_bucket_size);
|
||||
event.set_bucketCountStandardDeviation(statistics._stddev_of_bucket_size);
|
||||
event.set_insertionRate(statistics._add_rate);
|
||||
event.set_removalRate(statistics._remove_rate);
|
||||
event.commit();
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(SymbolTableStatistics) {
|
||||
TableStatistics statistics = SymbolTable::the_table()->get_table_statistics();
|
||||
emit_table_statistics<EventSymbolTableStatistics>(statistics);
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(StringTableStatistics) {
|
||||
TableStatistics statistics = StringTable::the_table()->get_table_statistics();
|
||||
emit_table_statistics<EventStringTableStatistics>(statistics);
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(PlaceholderTableStatistics) {
|
||||
TableStatistics statistics = SystemDictionary::placeholders_statistics();
|
||||
emit_table_statistics<EventPlaceholderTableStatistics>(statistics);
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(LoaderConstraintsTableStatistics) {
|
||||
TableStatistics statistics = SystemDictionary::loader_constraints_statistics();
|
||||
emit_table_statistics<EventLoaderConstraintsTableStatistics>(statistics);
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(ProtectionDomainCacheTableStatistics) {
|
||||
TableStatistics statistics = SystemDictionary::protection_domain_cache_statistics();
|
||||
emit_table_statistics<EventProtectionDomainCacheTableStatistics>(statistics);
|
||||
}
|
||||
|
||||
TRACE_REQUEST_FUNC(CompilerStatistics) {
|
||||
EventCompilerStatistics event;
|
||||
event.set_compileCount(CompileBroker::get_total_compile_count());
|
||||
|
@ -130,6 +130,7 @@ class AllocatedObj {
|
||||
f(mtTest, "Test") /* Test type for verifying NMT */ \
|
||||
f(mtTracing, "Tracing") \
|
||||
f(mtLogging, "Logging") \
|
||||
f(mtStatistics, "Statistics") \
|
||||
f(mtArguments, "Arguments") \
|
||||
f(mtModule, "Module") \
|
||||
f(mtSafepoint, "Safepoint") \
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalCounter.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/tableStatistics.hpp"
|
||||
|
||||
// A mostly concurrent-hash-table where the read-side is wait-free, inserts are
|
||||
// CAS and deletes mutual exclude each other on per bucket-basis. VALUE is the
|
||||
@ -380,6 +381,8 @@ class ConcurrentHashTable : public CHeapObj<F> {
|
||||
|
||||
~ConcurrentHashTable();
|
||||
|
||||
TableRateStatistics _stats_rate;
|
||||
|
||||
size_t get_size_log2(Thread* thread);
|
||||
size_t get_node_size() const { return sizeof(Node); }
|
||||
bool is_max_size_reached() { return _size_limit_reached; }
|
||||
@ -454,6 +457,15 @@ class ConcurrentHashTable : public CHeapObj<F> {
|
||||
template <typename EVALUATE_FUNC, typename DELETE_FUNC>
|
||||
void bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f);
|
||||
|
||||
// Calcuate statistics. Item sizes are calculated with VALUE_SIZE_FUNC.
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
TableStatistics statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f);
|
||||
|
||||
// Gets statistics if available, if not return old one. Item sizes are calculated with
|
||||
// VALUE_SIZE_FUNC.
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
TableStatistics statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old);
|
||||
|
||||
// Writes statistics to the outputStream. Item sizes are calculated with
|
||||
// VALUE_SIZE_FUNC.
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
|
@ -485,6 +485,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
GlobalCounter::write_synchronize();
|
||||
delete_f(rem_n->value());
|
||||
Node::destroy_node(rem_n);
|
||||
JFR_ONLY(_stats_rate.remove();)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -533,6 +534,7 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
for (size_t node_it = 0; node_it < nd; node_it++) {
|
||||
del_f(ndel[node_it]->value());
|
||||
Node::destroy_node(ndel[node_it]);
|
||||
JFR_ONLY(_stats_rate.remove();)
|
||||
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
||||
}
|
||||
cs_context = GlobalCounter::critical_section_begin(thread);
|
||||
@ -571,6 +573,7 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
GlobalCounter::write_synchronize();
|
||||
for (size_t node_it = 0; node_it < dels; node_it++) {
|
||||
Node::destroy_node(ndel[node_it]);
|
||||
JFR_ONLY(_stats_rate.remove();)
|
||||
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
||||
}
|
||||
}
|
||||
@ -900,6 +903,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
if (old == NULL) {
|
||||
new_node->set_next(first_at_start);
|
||||
if (bucket->cas_first(new_node, first_at_start)) {
|
||||
JFR_ONLY(_stats_rate.add();)
|
||||
new_node = NULL;
|
||||
ret = true;
|
||||
break; /* leave critical section */
|
||||
@ -1008,6 +1012,7 @@ inline ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
_size_limit_reached(false), _resize_lock_owner(NULL),
|
||||
_invisible_epoch(0)
|
||||
{
|
||||
_stats_rate = TableRateStatistics();
|
||||
_resize_lock =
|
||||
new Mutex(Mutex::leaf, "ConcurrentHashTable", false,
|
||||
Monitor::_safepoint_check_never);
|
||||
@ -1081,6 +1086,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
if (!bucket->cas_first(new_node, bucket->first())) {
|
||||
assert(false, "bad");
|
||||
}
|
||||
JFR_ONLY(_stats_rate.add();)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1182,24 +1188,18 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f,
|
||||
outputStream* st, const char* table_name)
|
||||
inline TableStatistics ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f)
|
||||
{
|
||||
NumberSeq summary;
|
||||
size_t literal_bytes = 0;
|
||||
if (!try_resize_lock(thread)) {
|
||||
st->print_cr("statistics unavailable at this moment");
|
||||
return;
|
||||
}
|
||||
|
||||
InternalTable* table = get_table();
|
||||
for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
|
||||
ScopedCS cs(thread, this);
|
||||
size_t count = 0;
|
||||
Bucket* bucket = table->get_bucket(bucket_it);
|
||||
if (bucket->have_redirect() || bucket->is_locked()) {
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
Node* current_node = bucket->first();
|
||||
while (current_node != NULL) {
|
||||
@ -1210,37 +1210,39 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
summary.add((double)count);
|
||||
}
|
||||
|
||||
double num_buckets = summary.num();
|
||||
double num_entries = summary.sum();
|
||||
return TableStatistics(_stats_rate, summary, literal_bytes, sizeof(Bucket), sizeof(Node));
|
||||
}
|
||||
|
||||
size_t bucket_bytes = num_buckets * sizeof(Bucket);
|
||||
size_t entry_bytes = num_entries * sizeof(Node);
|
||||
size_t total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
||||
|
||||
size_t bucket_size = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
|
||||
size_t entry_size = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
|
||||
|
||||
st->print_cr("%s statistics:", table_name);
|
||||
st->print_cr("Number of buckets : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, each " SIZE_FORMAT,
|
||||
(size_t)num_buckets, bucket_bytes, bucket_size);
|
||||
st->print_cr("Number of entries : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, each " SIZE_FORMAT,
|
||||
(size_t)num_entries, entry_bytes, entry_size);
|
||||
if (literal_bytes != 0) {
|
||||
double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries);
|
||||
st->print_cr("Number of literals : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, avg %7.3f",
|
||||
(size_t)num_entries, literal_bytes, literal_avg);
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
inline TableStatistics ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old)
|
||||
{
|
||||
if (!try_resize_lock(thread)) {
|
||||
return old;
|
||||
}
|
||||
st->print_cr("Total footprsize_t : %9s = %9" PRIuPTR " bytes", ""
|
||||
, total_bytes);
|
||||
st->print_cr("Average bucket size : %9.3f", summary.avg());
|
||||
st->print_cr("Variance of bucket size : %9.3f", summary.variance());
|
||||
st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd());
|
||||
st->print_cr("Maximum bucket size : %9" PRIuPTR,
|
||||
(size_t)summary.maximum());
|
||||
|
||||
TableStatistics ts = statistics_calculate(thread, vs_f);
|
||||
unlock_resize_lock(thread);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
template <typename VALUE_SIZE_FUNC>
|
||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||
statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f,
|
||||
outputStream* st, const char* table_name)
|
||||
{
|
||||
if (!try_resize_lock(thread)) {
|
||||
st->print_cr("statistics unavailable at this moment");
|
||||
return;
|
||||
}
|
||||
|
||||
TableStatistics ts = statistics_calculate(thread, vs_f);
|
||||
unlock_resize_lock(thread);
|
||||
|
||||
ts.print(st, table_name);
|
||||
}
|
||||
|
||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||
|
@ -191,18 +191,7 @@ template <MEMFLAGS F> bool BasicHashtable<F>::maybe_grow(int max_size, int load_
|
||||
}
|
||||
}
|
||||
|
||||
// Dump footprint and bucket length statistics
|
||||
//
|
||||
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to
|
||||
// add a new function static int literal_size(MyNewType lit)
|
||||
// because I can't get template <class T> int literal_size(T) to pick the specializations for Symbol and oop.
|
||||
//
|
||||
// The StringTable and SymbolTable dumping print how much footprint is used by the String and Symbol
|
||||
// literals.
|
||||
|
||||
template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outputStream* st,
|
||||
const char *table_name,
|
||||
T (*literal_load_barrier)(HashtableEntry<T, F>*)) {
|
||||
template <class T, MEMFLAGS F> TableStatistics Hashtable<T, F>::statistics_calculate(T (*literal_load_barrier)(HashtableEntry<T, F>*)) {
|
||||
NumberSeq summary;
|
||||
int literal_bytes = 0;
|
||||
for (int i = 0; i < this->table_size(); ++i) {
|
||||
@ -215,28 +204,19 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outp
|
||||
}
|
||||
summary.add((double)count);
|
||||
}
|
||||
double num_buckets = summary.num();
|
||||
double num_entries = summary.sum();
|
||||
return TableStatistics(this->_stats_rate, summary, literal_bytes, sizeof(HashtableBucket<F>), sizeof(HashtableEntry<T, F>));
|
||||
}
|
||||
|
||||
int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket<F>);
|
||||
int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
|
||||
int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
||||
|
||||
int bucket_size = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
|
||||
int entry_size = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
|
||||
|
||||
st->print_cr("%s statistics:", table_name);
|
||||
st->print_cr("Number of buckets : %9d = %9d bytes, each %d", (int)num_buckets, bucket_bytes, bucket_size);
|
||||
st->print_cr("Number of entries : %9d = %9d bytes, each %d", (int)num_entries, entry_bytes, entry_size);
|
||||
if (literal_bytes != 0) {
|
||||
double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries);
|
||||
st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg);
|
||||
}
|
||||
st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes);
|
||||
st->print_cr("Average bucket size : %9.3f", summary.avg());
|
||||
st->print_cr("Variance of bucket size : %9.3f", summary.variance());
|
||||
st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd());
|
||||
st->print_cr("Maximum bucket size : %9d", (int)summary.maximum());
|
||||
// Dump footprint and bucket length statistics
|
||||
//
|
||||
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to
|
||||
// add a new function static int literal_size(MyNewType lit)
|
||||
// because I can't get template <class T> int literal_size(T) to pick the specializations for Symbol and oop.
|
||||
template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outputStream* st,
|
||||
const char *table_name,
|
||||
T (*literal_load_barrier)(HashtableEntry<T, F>*)) {
|
||||
TableStatistics ts = statistics_calculate(literal_load_barrier);
|
||||
ts.print(st, table_name);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "oops/symbol.hpp"
|
||||
#include "runtime/handles.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
#include "utilities/tableStatistics.hpp"
|
||||
|
||||
// This is a generic hashtable, designed to be used for the symbol
|
||||
// and string tables.
|
||||
@ -168,6 +169,8 @@ private:
|
||||
|
||||
protected:
|
||||
|
||||
TableRateStatistics _stats_rate;
|
||||
|
||||
void initialize(int table_size, int entry_size, int number_of_entries);
|
||||
|
||||
// Accessor
|
||||
@ -245,6 +248,7 @@ public:
|
||||
return this->hash_to_index(compute_hash(name));
|
||||
}
|
||||
|
||||
TableStatistics statistics_calculate(T (*literal_load_barrier)(HashtableEntry<T, F>*) = NULL);
|
||||
void print_table_statistics(outputStream* st, const char *table_name, T (*literal_load_barrier)(HashtableEntry<T, F>*) = NULL);
|
||||
|
||||
protected:
|
||||
|
@ -43,6 +43,7 @@ template <MEMFLAGS F> inline BasicHashtable<F>::BasicHashtable(int table_size, i
|
||||
for (int index = 0; index < _table_size; index++) {
|
||||
_buckets[index].clear();
|
||||
}
|
||||
_stats_rate = TableRateStatistics();
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +53,7 @@ template <MEMFLAGS F> inline BasicHashtable<F>::BasicHashtable(int table_size, i
|
||||
// Called on startup, no locking needed
|
||||
initialize(table_size, entry_size, number_of_entries);
|
||||
_buckets = buckets;
|
||||
_stats_rate = TableRateStatistics();
|
||||
}
|
||||
|
||||
template <MEMFLAGS F> inline BasicHashtable<F>::~BasicHashtable() {
|
||||
@ -101,6 +103,11 @@ template <MEMFLAGS F> inline BasicHashtableEntry<F>* HashtableBucket<F>::get_ent
|
||||
|
||||
template <MEMFLAGS F> inline void BasicHashtable<F>::set_entry(int index, BasicHashtableEntry<F>* entry) {
|
||||
_buckets[index].set_entry(entry);
|
||||
if (entry != NULL) {
|
||||
JFR_ONLY(_stats_rate.add();)
|
||||
} else {
|
||||
JFR_ONLY(_stats_rate.remove();)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -108,12 +115,14 @@ template <MEMFLAGS F> inline void BasicHashtable<F>::add_entry(int index, BasicH
|
||||
entry->set_next(bucket(index));
|
||||
_buckets[index].set_entry(entry);
|
||||
++_number_of_entries;
|
||||
JFR_ONLY(_stats_rate.add();)
|
||||
}
|
||||
|
||||
template <MEMFLAGS F> inline void BasicHashtable<F>::free_entry(BasicHashtableEntry<F>* entry) {
|
||||
entry->set_next(_free_list);
|
||||
_free_list = entry;
|
||||
--_number_of_entries;
|
||||
JFR_ONLY(_stats_rate.remove();)
|
||||
}
|
||||
|
||||
#endif // SHARE_UTILITIES_HASHTABLE_INLINE_HPP
|
||||
|
140
src/hotspot/share/utilities/tableStatistics.cpp
Normal file
140
src/hotspot/share/utilities/tableStatistics.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/tableStatistics.hpp"
|
||||
|
||||
TableRateStatistics::TableRateStatistics() :
|
||||
_added_items(0), _removed_items(0),
|
||||
_time_stamp(0), _seconds_stamp(0),
|
||||
_added_items_stamp(0), _added_items_stamp_prev(0),
|
||||
_removed_items_stamp(0), _removed_items_stamp_prev(0) {}
|
||||
|
||||
TableRateStatistics::~TableRateStatistics() { };
|
||||
|
||||
void TableRateStatistics::add() {
|
||||
if (Jfr::is_recording()) {
|
||||
Atomic::inc(&_added_items);
|
||||
}
|
||||
}
|
||||
|
||||
void TableRateStatistics::remove() {
|
||||
if (Jfr::is_recording()) {
|
||||
Atomic::inc(&_removed_items);
|
||||
}
|
||||
}
|
||||
|
||||
void TableRateStatistics::stamp() {
|
||||
jlong now = os::javaTimeNanos();
|
||||
|
||||
_added_items_stamp_prev = _added_items_stamp;
|
||||
_removed_items_stamp_prev = _removed_items_stamp;
|
||||
|
||||
_added_items_stamp = _added_items;
|
||||
_removed_items_stamp = _removed_items;
|
||||
|
||||
if (_time_stamp == 0) {
|
||||
_time_stamp = now - 1000000000;
|
||||
}
|
||||
jlong diff = (now - _time_stamp);
|
||||
_seconds_stamp = (float)diff / 1000000000.0;
|
||||
_time_stamp = now;
|
||||
}
|
||||
|
||||
float TableRateStatistics::get_add_rate() {
|
||||
return (float)((_added_items_stamp - _added_items_stamp_prev) / _seconds_stamp);
|
||||
}
|
||||
|
||||
float TableRateStatistics::get_remove_rate() {
|
||||
return (float)((_removed_items_stamp - _removed_items_stamp_prev) / _seconds_stamp);
|
||||
}
|
||||
|
||||
TableStatistics::TableStatistics() :
|
||||
_literal_bytes(0),
|
||||
_number_of_buckets(0), _number_of_entries(0),
|
||||
_maximum_bucket_size(0), _average_bucket_size(0),
|
||||
_variance_of_bucket_size(0), _stddev_of_bucket_size(0),
|
||||
_bucket_bytes(0), _entry_bytes(0), _total_footprint(0),
|
||||
_bucket_size(0), _entry_size(0),
|
||||
_add_rate(0), _remove_rate(0) {
|
||||
}
|
||||
|
||||
TableStatistics::TableStatistics(TableRateStatistics& rate_stats, NumberSeq summary, size_t literal_bytes, size_t bucket_bytes, size_t node_bytes) :
|
||||
_literal_bytes(literal_bytes),
|
||||
_number_of_buckets(0), _number_of_entries(0),
|
||||
_maximum_bucket_size(0), _average_bucket_size(0),
|
||||
_variance_of_bucket_size(0), _stddev_of_bucket_size(0),
|
||||
_bucket_bytes(0), _entry_bytes(0), _total_footprint(0),
|
||||
_bucket_size(0), _entry_size(0),
|
||||
_add_rate(0), _remove_rate(0) {
|
||||
|
||||
_number_of_buckets = summary.num();
|
||||
_number_of_entries = summary.sum();
|
||||
|
||||
_maximum_bucket_size = summary.maximum();
|
||||
_average_bucket_size = summary.avg();
|
||||
_variance_of_bucket_size = summary.variance();
|
||||
_stddev_of_bucket_size = summary.sd();
|
||||
|
||||
_bucket_bytes = _number_of_buckets * bucket_bytes;
|
||||
_entry_bytes = _number_of_entries * node_bytes;
|
||||
_total_footprint = _literal_bytes + _bucket_bytes + _entry_bytes;
|
||||
|
||||
_bucket_size = (_number_of_buckets <= 0) ? 0 : (_bucket_bytes / _number_of_buckets);
|
||||
_entry_size = (_number_of_entries <= 0) ? 0 : (_entry_bytes / _number_of_entries);
|
||||
|
||||
if (Jfr::is_recording()) {
|
||||
rate_stats.stamp();
|
||||
_add_rate = rate_stats.get_add_rate();
|
||||
_remove_rate = rate_stats.get_remove_rate();
|
||||
}
|
||||
}
|
||||
|
||||
TableStatistics::~TableStatistics() { }
|
||||
|
||||
void TableStatistics::print(outputStream* st, const char *table_name) {
|
||||
st->print_cr("%s statistics:", table_name);
|
||||
st->print_cr("Number of buckets : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, each " SIZE_FORMAT,
|
||||
_number_of_buckets, _bucket_bytes, _bucket_size);
|
||||
st->print_cr("Number of entries : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, each " SIZE_FORMAT,
|
||||
_number_of_entries, _entry_bytes, _entry_size);
|
||||
if (_literal_bytes != 0) {
|
||||
float literal_avg = (_number_of_entries <= 0) ? 0 : (_literal_bytes / _number_of_entries);
|
||||
st->print_cr("Number of literals : %9" PRIuPTR " = %9" PRIuPTR
|
||||
" bytes, avg %7.3f",
|
||||
_number_of_entries, _literal_bytes, literal_avg);
|
||||
}
|
||||
st->print_cr("Total footprint : %9s = %9" PRIuPTR " bytes", "", _total_footprint);
|
||||
st->print_cr("Average bucket size : %9.3f", _average_bucket_size);
|
||||
st->print_cr("Variance of bucket size : %9.3f", _variance_of_bucket_size);
|
||||
st->print_cr("Std. dev. of bucket size: %9.3f", _stddev_of_bucket_size);
|
||||
st->print_cr("Maximum bucket size : %9" PRIuPTR, _maximum_bucket_size);
|
||||
}
|
||||
|
91
src/hotspot/share/utilities/tableStatistics.hpp
Normal file
91
src/hotspot/share/utilities/tableStatistics.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* 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_UTILITIES_TABLE_STATISTICS_HPP
|
||||
#define SHARE_UTILITIES_TABLE_STATISTICS_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/numberSeq.hpp"
|
||||
|
||||
class TableRateStatistics : CHeapObj<mtStatistics> {
|
||||
|
||||
friend class TableStatistics;
|
||||
|
||||
private:
|
||||
volatile size_t _added_items;
|
||||
volatile size_t _removed_items;
|
||||
|
||||
jlong _time_stamp;
|
||||
double _seconds_stamp;
|
||||
size_t _added_items_stamp;
|
||||
size_t _added_items_stamp_prev;
|
||||
size_t _removed_items_stamp;
|
||||
size_t _removed_items_stamp_prev;
|
||||
|
||||
public:
|
||||
TableRateStatistics();
|
||||
~TableRateStatistics();
|
||||
|
||||
void add();
|
||||
void remove();
|
||||
|
||||
protected:
|
||||
void stamp();
|
||||
float get_add_rate();
|
||||
float get_remove_rate();
|
||||
};
|
||||
|
||||
class TableStatistics : CHeapObj<mtStatistics> {
|
||||
|
||||
public:
|
||||
size_t _literal_bytes;
|
||||
|
||||
size_t _number_of_buckets;
|
||||
size_t _number_of_entries;
|
||||
|
||||
size_t _maximum_bucket_size;
|
||||
float _average_bucket_size;
|
||||
float _variance_of_bucket_size;
|
||||
float _stddev_of_bucket_size;
|
||||
|
||||
size_t _bucket_bytes;
|
||||
size_t _entry_bytes;
|
||||
size_t _total_footprint;
|
||||
|
||||
size_t _bucket_size;
|
||||
size_t _entry_size;
|
||||
|
||||
float _add_rate;
|
||||
float _remove_rate;
|
||||
|
||||
TableStatistics();
|
||||
TableStatistics(TableRateStatistics& rate_stats, NumberSeq summary, size_t literal_bytes, size_t bucket_bytes, size_t node_bytes);
|
||||
~TableStatistics();
|
||||
|
||||
void print(outputStream* st, const char *table_name);
|
||||
};
|
||||
|
||||
#endif // SHARE_UTILITIES_TABLE_STATISTICS_HPP
|
@ -27,6 +27,31 @@
|
||||
<setting name="period">1000 ms</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.SymbolTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.StringTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.PlaceholderTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.LoaderConstraintsTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ProtectionDomainCacheTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ThreadStart">
|
||||
<setting name="enabled">true</setting>
|
||||
</event>
|
||||
|
@ -27,6 +27,31 @@
|
||||
<setting name="period">1000 ms</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.SymbolTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.StringTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.PlaceholderTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.LoaderConstraintsTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ProtectionDomainCacheTableStatistics">
|
||||
<setting name="enabled">true</setting>
|
||||
<setting name="period">10 s</setting>
|
||||
</event>
|
||||
|
||||
<event name="jdk.ThreadStart">
|
||||
<setting name="enabled">true</setting>
|
||||
</event>
|
||||
|
89
test/jdk/jdk/jfr/event/runtime/TestTableStatisticsEvent.java
Normal file
89
test/jdk/jdk/jfr/event/runtime/TestTableStatisticsEvent.java
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedClass;
|
||||
import jdk.jfr.consumer.RecordedClassLoader;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
import jdk.test.lib.jfr.Events;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib /test/jdk
|
||||
* @build jdk.jfr.event.runtime.TestClasses
|
||||
* @run main/othervm jdk.jfr.event.runtime.TestTableStatisticsEvent
|
||||
* @bug 8185525
|
||||
*/
|
||||
public final class TestTableStatisticsEvent {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try (Recording recording = new Recording()) {
|
||||
recording.enable(EventNames.SymbolTableStatistics);
|
||||
recording.enable(EventNames.StringTableStatistics);
|
||||
recording.enable(EventNames.PlaceholderTableStatistics);
|
||||
recording.enable(EventNames.LoaderConstraintsTableStatistics);
|
||||
recording.enable(EventNames.ProtectionDomainCacheTableStatistics);
|
||||
recording.start();
|
||||
recording.stop();
|
||||
|
||||
List<RecordedEvent> events = Events.fromRecording(recording);
|
||||
verifyTable(events, EventNames.SymbolTableStatistics);
|
||||
verifyTable(events, EventNames.StringTableStatistics);
|
||||
verifyTable(events, EventNames.PlaceholderTableStatistics);
|
||||
verifyTable(events, EventNames.LoaderConstraintsTableStatistics);
|
||||
verifyTable(events, EventNames.ProtectionDomainCacheTableStatistics);
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyTable(List<RecordedEvent> allEvents, String eventName) throws Exception {
|
||||
List<RecordedEvent> eventsForTable = allEvents.stream().filter(e -> e.getEventType().getName().equals(eventName)).collect(Collectors.toList());
|
||||
if (eventsForTable.isEmpty()) {
|
||||
throw new Exception("No events for " + eventName);
|
||||
}
|
||||
for (RecordedEvent event : eventsForTable) {
|
||||
Events.assertField(event, "bucketCount").atLeast(0L);
|
||||
long entryCount = Events.assertField(event, "entryCount").atLeast(0L).getValue();
|
||||
Events.assertField(event, "totalFootprint").atLeast(0L);
|
||||
float averageBucketCount = Events.assertField(event, "bucketCountAverage").atLeast(0.0f).getValue();
|
||||
Events.assertField(event, "bucketCountMaximum").atLeast((long)averageBucketCount);
|
||||
Events.assertField(event, "bucketCountVariance").atLeast(0.0f);
|
||||
Events.assertField(event, "bucketCountStandardDeviation").atLeast(0.0f);
|
||||
float insertionRate = Events.assertField(event, "insertionRate").atLeast(0.0f).getValue();
|
||||
float removalRate = Events.assertField(event, "removalRate").atLeast(0.0f).getValue();
|
||||
if ((insertionRate > 0.0f) && (insertionRate > removalRate)) {
|
||||
Asserts.assertGreaterThan(entryCount, 0L, "Entries marked as added, but no entries found for " + eventName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -82,6 +82,11 @@ public class EventNames {
|
||||
public final static String BiasedLockRevocation = PREFIX + "BiasedLockRevocation";
|
||||
public final static String BiasedLockSelfRevocation = PREFIX + "BiasedLockSelfRevocation";
|
||||
public final static String BiasedLockClassRevocation = PREFIX + "BiasedLockClassRevocation";
|
||||
public final static String SymbolTableStatistics = PREFIX + "SymbolTableStatistics";
|
||||
public final static String StringTableStatistics = PREFIX + "StringTableStatistics";
|
||||
public final static String PlaceholderTableStatistics = PREFIX + "PlaceholderTableStatistics";
|
||||
public final static String LoaderConstraintsTableStatistics = PREFIX + "LoaderConstraintsTableStatistics";
|
||||
public final static String ProtectionDomainCacheTableStatistics = PREFIX + "ProtectionDomainCacheTableStatistics";
|
||||
// This event is hard to test
|
||||
public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user