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) {
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
stringStream tempst;
|
stringStream tempst;
|
||||||
|
@ -112,7 +112,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
|||||||
|
|
||||||
static void verify_dictionary();
|
static void verify_dictionary();
|
||||||
static void print_dictionary(outputStream* st);
|
static void print_dictionary(outputStream* st);
|
||||||
static void print_dictionary_statistics(outputStream* st);
|
static void print_table_statistics(outputStream* st);
|
||||||
|
|
||||||
// CMS support.
|
// CMS support.
|
||||||
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
|
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,
|
void StringTable::print_table_statistics(outputStream* st,
|
||||||
const char* table_name) {
|
const char* table_name) {
|
||||||
SizeFunc sz;
|
SizeFunc sz;
|
||||||
|
@ -99,6 +99,7 @@ private:
|
|||||||
// The string table
|
// The string table
|
||||||
static StringTable* the_table() { return _the_table; }
|
static StringTable* the_table() { return _the_table; }
|
||||||
size_t table_size();
|
size_t table_size();
|
||||||
|
TableStatistics get_table_statistics();
|
||||||
|
|
||||||
static OopStorage* weak_storage() { return the_table()->_weak_handles; }
|
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,
|
void SymbolTable::print_table_statistics(outputStream* st,
|
||||||
const char* table_name) {
|
const char* table_name) {
|
||||||
SizeFunc sz;
|
SizeFunc sz;
|
||||||
|
@ -171,6 +171,7 @@ public:
|
|||||||
// The symbol table
|
// The symbol table
|
||||||
static SymbolTable* the_table() { return _the_table; }
|
static SymbolTable* the_table() { return _the_table; }
|
||||||
size_t table_size();
|
size_t table_size();
|
||||||
|
TableStatistics get_table_statistics();
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
symbol_alloc_batch_size = 8,
|
symbol_alloc_batch_size = 8,
|
||||||
|
@ -2849,13 +2849,25 @@ void SystemDictionary::dump(outputStream *st, bool verbose) {
|
|||||||
print_on(st);
|
print_on(st);
|
||||||
} else {
|
} else {
|
||||||
CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
|
CDS_ONLY(SystemDictionaryShared::print_table_statistics(st));
|
||||||
ClassLoaderDataGraph::print_dictionary_statistics(st);
|
ClassLoaderDataGraph::print_table_statistics(st);
|
||||||
placeholders()->print_table_statistics(st, "Placeholder Table");
|
placeholders()->print_table_statistics(st, "Placeholder Table");
|
||||||
constraints()->print_table_statistics(st, "LoaderConstraints 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.
|
// Utility for dumping dictionaries.
|
||||||
SystemDictionaryDCmd::SystemDictionaryDCmd(outputStream* output, bool heap) :
|
SystemDictionaryDCmd::SystemDictionaryDCmd(outputStream* output, bool heap) :
|
||||||
DCmdWithParser(output, heap),
|
DCmdWithParser(output, heap),
|
||||||
|
@ -681,6 +681,11 @@ private:
|
|||||||
static oop _java_platform_loader;
|
static oop _java_platform_loader;
|
||||||
|
|
||||||
static bool _has_checkPackageAccess;
|
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
|
#endif // SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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.
|
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
|
||||||
This code is free software; you can redistribute it and/or modify it
|
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)" />
|
description="Total size of all allocated metaspace blocks for unsafe anonymous classes (each chunk has several blocks)" />
|
||||||
</Event>
|
</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">
|
<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="ulong" contentType="bytes" name="allocated" label="Allocated" description="Approximate number of bytes allocated since thread start" />
|
||||||
<Field type="Thread" name="thread" label="Thread" />
|
<Field type="Thread" name="thread" label="Thread" />
|
||||||
|
@ -27,6 +27,9 @@
|
|||||||
#include "classfile/classLoaderDataGraph.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderStats.hpp"
|
#include "classfile/classLoaderStats.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
|
#include "classfile/stringTable.hpp"
|
||||||
|
#include "classfile/symbolTable.hpp"
|
||||||
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
#include "gc/g1/g1HeapRegionEventSender.hpp"
|
#include "gc/g1/g1HeapRegionEventSender.hpp"
|
||||||
@ -506,6 +509,46 @@ TRACE_REQUEST_FUNC(ClassLoaderStatistics) {
|
|||||||
VMThread::execute(&op);
|
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) {
|
TRACE_REQUEST_FUNC(CompilerStatistics) {
|
||||||
EventCompilerStatistics event;
|
EventCompilerStatistics event;
|
||||||
event.set_compileCount(CompileBroker::get_total_compile_count());
|
event.set_compileCount(CompileBroker::get_total_compile_count());
|
||||||
|
@ -130,6 +130,7 @@ class AllocatedObj {
|
|||||||
f(mtTest, "Test") /* Test type for verifying NMT */ \
|
f(mtTest, "Test") /* Test type for verifying NMT */ \
|
||||||
f(mtTracing, "Tracing") \
|
f(mtTracing, "Tracing") \
|
||||||
f(mtLogging, "Logging") \
|
f(mtLogging, "Logging") \
|
||||||
|
f(mtStatistics, "Statistics") \
|
||||||
f(mtArguments, "Arguments") \
|
f(mtArguments, "Arguments") \
|
||||||
f(mtModule, "Module") \
|
f(mtModule, "Module") \
|
||||||
f(mtSafepoint, "Safepoint") \
|
f(mtSafepoint, "Safepoint") \
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "utilities/globalCounter.hpp"
|
#include "utilities/globalCounter.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
#include "utilities/tableStatistics.hpp"
|
||||||
|
|
||||||
// A mostly concurrent-hash-table where the read-side is wait-free, inserts are
|
// 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
|
// CAS and deletes mutual exclude each other on per bucket-basis. VALUE is the
|
||||||
@ -380,6 +381,8 @@ class ConcurrentHashTable : public CHeapObj<F> {
|
|||||||
|
|
||||||
~ConcurrentHashTable();
|
~ConcurrentHashTable();
|
||||||
|
|
||||||
|
TableRateStatistics _stats_rate;
|
||||||
|
|
||||||
size_t get_size_log2(Thread* thread);
|
size_t get_size_log2(Thread* thread);
|
||||||
size_t get_node_size() const { return sizeof(Node); }
|
size_t get_node_size() const { return sizeof(Node); }
|
||||||
bool is_max_size_reached() { return _size_limit_reached; }
|
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>
|
template <typename EVALUATE_FUNC, typename DELETE_FUNC>
|
||||||
void bulk_delete(Thread* thread, EVALUATE_FUNC& eval_f, DELETE_FUNC& del_f);
|
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
|
// Writes statistics to the outputStream. Item sizes are calculated with
|
||||||
// VALUE_SIZE_FUNC.
|
// VALUE_SIZE_FUNC.
|
||||||
template <typename VALUE_SIZE_FUNC>
|
template <typename VALUE_SIZE_FUNC>
|
||||||
|
@ -485,6 +485,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
GlobalCounter::write_synchronize();
|
GlobalCounter::write_synchronize();
|
||||||
delete_f(rem_n->value());
|
delete_f(rem_n->value());
|
||||||
Node::destroy_node(rem_n);
|
Node::destroy_node(rem_n);
|
||||||
|
JFR_ONLY(_stats_rate.remove();)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,6 +534,7 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
for (size_t node_it = 0; node_it < nd; node_it++) {
|
for (size_t node_it = 0; node_it < nd; node_it++) {
|
||||||
del_f(ndel[node_it]->value());
|
del_f(ndel[node_it]->value());
|
||||||
Node::destroy_node(ndel[node_it]);
|
Node::destroy_node(ndel[node_it]);
|
||||||
|
JFR_ONLY(_stats_rate.remove();)
|
||||||
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
||||||
}
|
}
|
||||||
cs_context = GlobalCounter::critical_section_begin(thread);
|
cs_context = GlobalCounter::critical_section_begin(thread);
|
||||||
@ -571,6 +573,7 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
GlobalCounter::write_synchronize();
|
GlobalCounter::write_synchronize();
|
||||||
for (size_t node_it = 0; node_it < dels; node_it++) {
|
for (size_t node_it = 0; node_it < dels; node_it++) {
|
||||||
Node::destroy_node(ndel[node_it]);
|
Node::destroy_node(ndel[node_it]);
|
||||||
|
JFR_ONLY(_stats_rate.remove();)
|
||||||
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
DEBUG_ONLY(ndel[node_it] = (Node*)POISON_PTR;)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -900,6 +903,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
if (old == NULL) {
|
if (old == NULL) {
|
||||||
new_node->set_next(first_at_start);
|
new_node->set_next(first_at_start);
|
||||||
if (bucket->cas_first(new_node, first_at_start)) {
|
if (bucket->cas_first(new_node, first_at_start)) {
|
||||||
|
JFR_ONLY(_stats_rate.add();)
|
||||||
new_node = NULL;
|
new_node = NULL;
|
||||||
ret = true;
|
ret = true;
|
||||||
break; /* leave critical section */
|
break; /* leave critical section */
|
||||||
@ -1008,6 +1012,7 @@ inline ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
_size_limit_reached(false), _resize_lock_owner(NULL),
|
_size_limit_reached(false), _resize_lock_owner(NULL),
|
||||||
_invisible_epoch(0)
|
_invisible_epoch(0)
|
||||||
{
|
{
|
||||||
|
_stats_rate = TableRateStatistics();
|
||||||
_resize_lock =
|
_resize_lock =
|
||||||
new Mutex(Mutex::leaf, "ConcurrentHashTable", false,
|
new Mutex(Mutex::leaf, "ConcurrentHashTable", false,
|
||||||
Monitor::_safepoint_check_never);
|
Monitor::_safepoint_check_never);
|
||||||
@ -1081,6 +1086,7 @@ inline bool ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
if (!bucket->cas_first(new_node, bucket->first())) {
|
if (!bucket->cas_first(new_node, bucket->first())) {
|
||||||
assert(false, "bad");
|
assert(false, "bad");
|
||||||
}
|
}
|
||||||
|
JFR_ONLY(_stats_rate.add();)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,24 +1188,18 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
|
|
||||||
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||||
template <typename VALUE_SIZE_FUNC>
|
template <typename VALUE_SIZE_FUNC>
|
||||||
inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
inline TableStatistics ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||||
statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f,
|
statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f)
|
||||||
outputStream* st, const char* table_name)
|
|
||||||
{
|
{
|
||||||
NumberSeq summary;
|
NumberSeq summary;
|
||||||
size_t literal_bytes = 0;
|
size_t literal_bytes = 0;
|
||||||
if (!try_resize_lock(thread)) {
|
|
||||||
st->print_cr("statistics unavailable at this moment");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InternalTable* table = get_table();
|
InternalTable* table = get_table();
|
||||||
for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
|
for (size_t bucket_it = 0; bucket_it < table->_size; bucket_it++) {
|
||||||
ScopedCS cs(thread, this);
|
ScopedCS cs(thread, this);
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
Bucket* bucket = table->get_bucket(bucket_it);
|
Bucket* bucket = table->get_bucket(bucket_it);
|
||||||
if (bucket->have_redirect() || bucket->is_locked()) {
|
if (bucket->have_redirect() || bucket->is_locked()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Node* current_node = bucket->first();
|
Node* current_node = bucket->first();
|
||||||
while (current_node != NULL) {
|
while (current_node != NULL) {
|
||||||
@ -1210,37 +1210,39 @@ inline void ConcurrentHashTable<VALUE, CONFIG, F>::
|
|||||||
summary.add((double)count);
|
summary.add((double)count);
|
||||||
}
|
}
|
||||||
|
|
||||||
double num_buckets = summary.num();
|
return TableStatistics(_stats_rate, summary, literal_bytes, sizeof(Bucket), sizeof(Node));
|
||||||
double num_entries = summary.sum();
|
}
|
||||||
|
|
||||||
size_t bucket_bytes = num_buckets * sizeof(Bucket);
|
template <typename VALUE, typename CONFIG, MEMFLAGS F>
|
||||||
size_t entry_bytes = num_entries * sizeof(Node);
|
template <typename VALUE_SIZE_FUNC>
|
||||||
size_t total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
inline TableStatistics ConcurrentHashTable<VALUE, CONFIG, F>::
|
||||||
|
statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old)
|
||||||
size_t bucket_size = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
|
{
|
||||||
size_t entry_size = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
|
if (!try_resize_lock(thread)) {
|
||||||
|
return old;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
st->print_cr("Total footprsize_t : %9s = %9" PRIuPTR " bytes", ""
|
|
||||||
, total_bytes);
|
TableStatistics ts = statistics_calculate(thread, vs_f);
|
||||||
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());
|
|
||||||
unlock_resize_lock(thread);
|
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>
|
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
|
template <class T, MEMFLAGS F> TableStatistics Hashtable<T, F>::statistics_calculate(T (*literal_load_barrier)(HashtableEntry<T, F>*)) {
|
||||||
//
|
|
||||||
// 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>*)) {
|
|
||||||
NumberSeq summary;
|
NumberSeq summary;
|
||||||
int literal_bytes = 0;
|
int literal_bytes = 0;
|
||||||
for (int i = 0; i < this->table_size(); ++i) {
|
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);
|
summary.add((double)count);
|
||||||
}
|
}
|
||||||
double num_buckets = summary.num();
|
return TableStatistics(this->_stats_rate, summary, literal_bytes, sizeof(HashtableBucket<F>), sizeof(HashtableEntry<T, F>));
|
||||||
double num_entries = summary.sum();
|
}
|
||||||
|
|
||||||
int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket<F>);
|
// Dump footprint and bucket length statistics
|
||||||
int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
|
//
|
||||||
int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
// 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)
|
||||||
int bucket_size = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets);
|
// because I can't get template <class T> int literal_size(T) to pick the specializations for Symbol and oop.
|
||||||
int entry_size = (num_entries <= 0) ? 0 : (entry_bytes / num_entries);
|
template <class T, MEMFLAGS F> void Hashtable<T, F>::print_table_statistics(outputStream* st,
|
||||||
|
const char *table_name,
|
||||||
st->print_cr("%s statistics:", table_name);
|
T (*literal_load_barrier)(HashtableEntry<T, F>*)) {
|
||||||
st->print_cr("Number of buckets : %9d = %9d bytes, each %d", (int)num_buckets, bucket_bytes, bucket_size);
|
TableStatistics ts = statistics_calculate(literal_load_barrier);
|
||||||
st->print_cr("Number of entries : %9d = %9d bytes, each %d", (int)num_entries, entry_bytes, entry_size);
|
ts.print(st, table_name);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
#include "runtime/handles.hpp"
|
#include "runtime/handles.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
|
#include "utilities/tableStatistics.hpp"
|
||||||
|
|
||||||
// This is a generic hashtable, designed to be used for the symbol
|
// This is a generic hashtable, designed to be used for the symbol
|
||||||
// and string tables.
|
// and string tables.
|
||||||
@ -168,6 +169,8 @@ private:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
TableRateStatistics _stats_rate;
|
||||||
|
|
||||||
void initialize(int table_size, int entry_size, int number_of_entries);
|
void initialize(int table_size, int entry_size, int number_of_entries);
|
||||||
|
|
||||||
// Accessor
|
// Accessor
|
||||||
@ -245,6 +248,7 @@ public:
|
|||||||
return this->hash_to_index(compute_hash(name));
|
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);
|
void print_table_statistics(outputStream* st, const char *table_name, T (*literal_load_barrier)(HashtableEntry<T, F>*) = NULL);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -43,6 +43,7 @@ template <MEMFLAGS F> inline BasicHashtable<F>::BasicHashtable(int table_size, i
|
|||||||
for (int index = 0; index < _table_size; index++) {
|
for (int index = 0; index < _table_size; index++) {
|
||||||
_buckets[index].clear();
|
_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
|
// Called on startup, no locking needed
|
||||||
initialize(table_size, entry_size, number_of_entries);
|
initialize(table_size, entry_size, number_of_entries);
|
||||||
_buckets = buckets;
|
_buckets = buckets;
|
||||||
|
_stats_rate = TableRateStatistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <MEMFLAGS F> inline BasicHashtable<F>::~BasicHashtable() {
|
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) {
|
template <MEMFLAGS F> inline void BasicHashtable<F>::set_entry(int index, BasicHashtableEntry<F>* entry) {
|
||||||
_buckets[index].set_entry(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));
|
entry->set_next(bucket(index));
|
||||||
_buckets[index].set_entry(entry);
|
_buckets[index].set_entry(entry);
|
||||||
++_number_of_entries;
|
++_number_of_entries;
|
||||||
|
JFR_ONLY(_stats_rate.add();)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <MEMFLAGS F> inline void BasicHashtable<F>::free_entry(BasicHashtableEntry<F>* entry) {
|
template <MEMFLAGS F> inline void BasicHashtable<F>::free_entry(BasicHashtableEntry<F>* entry) {
|
||||||
entry->set_next(_free_list);
|
entry->set_next(_free_list);
|
||||||
_free_list = entry;
|
_free_list = entry;
|
||||||
--_number_of_entries;
|
--_number_of_entries;
|
||||||
|
JFR_ONLY(_stats_rate.remove();)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SHARE_UTILITIES_HASHTABLE_INLINE_HPP
|
#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>
|
<setting name="period">1000 ms</setting>
|
||||||
</event>
|
</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">
|
<event name="jdk.ThreadStart">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
</event>
|
</event>
|
||||||
|
@ -27,6 +27,31 @@
|
|||||||
<setting name="period">1000 ms</setting>
|
<setting name="period">1000 ms</setting>
|
||||||
</event>
|
</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">
|
<event name="jdk.ThreadStart">
|
||||||
<setting name="enabled">true</setting>
|
<setting name="enabled">true</setting>
|
||||||
</event>
|
</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 BiasedLockRevocation = PREFIX + "BiasedLockRevocation";
|
||||||
public final static String BiasedLockSelfRevocation = PREFIX + "BiasedLockSelfRevocation";
|
public final static String BiasedLockSelfRevocation = PREFIX + "BiasedLockSelfRevocation";
|
||||||
public final static String BiasedLockClassRevocation = PREFIX + "BiasedLockClassRevocation";
|
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
|
// This event is hard to test
|
||||||
public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation";
|
public final static String ReservedStackActivation = PREFIX + "ReservedStackActivation";
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user