8185525: Add JFR event for DictionarySizes
authorgziemski
Wed, 08 May 2019 11:11:50 -0500
changeset 54764 865ec913f916
parent 54763 2584e5772546
child 54765 cc6053cbd811
8185525: Add JFR event for DictionarySizes Summary: Added TableStatistics event Reviewed-by: egahlin, coleenp
src/hotspot/share/classfile/classLoaderDataGraph.cpp
src/hotspot/share/classfile/classLoaderDataGraph.hpp
src/hotspot/share/classfile/stringTable.cpp
src/hotspot/share/classfile/stringTable.hpp
src/hotspot/share/classfile/symbolTable.cpp
src/hotspot/share/classfile/symbolTable.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/classfile/systemDictionary.hpp
src/hotspot/share/jfr/metadata/metadata.xml
src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
src/hotspot/share/memory/allocation.hpp
src/hotspot/share/utilities/concurrentHashTable.hpp
src/hotspot/share/utilities/concurrentHashTable.inline.hpp
src/hotspot/share/utilities/hashtable.cpp
src/hotspot/share/utilities/hashtable.hpp
src/hotspot/share/utilities/hashtable.inline.hpp
src/hotspot/share/utilities/tableStatistics.cpp
src/hotspot/share/utilities/tableStatistics.hpp
src/jdk.jfr/share/conf/jfr/default.jfc
src/jdk.jfr/share/conf/jfr/profile.jfc
test/jdk/jdk/jfr/event/runtime/TestTableStatisticsEvent.java
test/lib/jdk/test/lib/jfr/EventNames.java
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp	Wed May 08 11:11:50 2019 -0500
@@ -443,7 +443,7 @@
   }
 }
 
-void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
+void ClassLoaderDataGraph::print_table_statistics(outputStream* st) {
   FOR_ALL_DICTIONARY(cld) {
     ResourceMark rm;
     stringStream tempst;
--- a/src/hotspot/share/classfile/classLoaderDataGraph.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.hpp	Wed May 08 11:11:50 2019 -0500
@@ -112,7 +112,7 @@
 
   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); }
--- a/src/hotspot/share/classfile/stringTable.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/stringTable.cpp	Wed May 08 11:11:50 2019 -0500
@@ -579,6 +579,13 @@
   };
 };
 
+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;
--- a/src/hotspot/share/classfile/stringTable.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/stringTable.hpp	Wed May 08 11:11:50 2019 -0500
@@ -99,6 +99,7 @@
   // 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; }
 
--- a/src/hotspot/share/classfile/symbolTable.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/symbolTable.cpp	Wed May 08 11:11:50 2019 -0500
@@ -503,6 +503,13 @@
   };
 };
 
+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;
--- a/src/hotspot/share/classfile/symbolTable.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/symbolTable.hpp	Wed May 08 11:11:50 2019 -0500
@@ -171,6 +171,7 @@
   // The symbol table
   static SymbolTable* the_table() { return _the_table; }
   size_t table_size();
+  TableStatistics get_table_statistics();
 
   enum {
     symbol_alloc_batch_size = 8,
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed May 08 11:11:50 2019 -0500
@@ -2849,13 +2849,25 @@
     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),
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Wed May 08 11:11:50 2019 -0500
@@ -681,6 +681,11 @@
   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
--- a/src/hotspot/share/jfr/metadata/metadata.xml	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/jfr/metadata/metadata.xml	Wed May 08 11:11:50 2019 -0500
@@ -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" />
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp	Wed May 08 11:11:50 2019 -0500
@@ -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 @@
   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());
--- a/src/hotspot/share/memory/allocation.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/memory/allocation.hpp	Wed May 08 11:11:50 2019 -0500
@@ -130,6 +130,7 @@
   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")                                                   \
--- a/src/hotspot/share/utilities/concurrentHashTable.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/utilities/concurrentHashTable.hpp	Wed May 08 11:11:50 2019 -0500
@@ -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 @@
 
   ~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 @@
   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>
--- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp	Wed May 08 11:11:50 2019 -0500
@@ -485,6 +485,7 @@
   GlobalCounter::write_synchronize();
   delete_f(rem_n->value());
   Node::destroy_node(rem_n);
+  JFR_ONLY(_stats_rate.remove();)
   return true;
 }
 
@@ -533,6 +534,7 @@
     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 @@
     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 @@
       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 @@
        _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 @@
   if (!bucket->cas_first(new_node, bucket->first())) {
     assert(false, "bad");
   }
+  JFR_ONLY(_stats_rate.add();)
   return true;
 }
 
@@ -1182,24 +1188,18 @@
 
 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 @@
     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;
+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;
+  }
 
-  size_t bucket_size  = (num_buckets <= 0) ? 0 : (bucket_bytes  / num_buckets);
-  size_t entry_size   = (num_entries <= 0) ? 0 : (entry_bytes   / num_entries);
+  TableStatistics ts = statistics_calculate(thread, vs_f);
+  unlock_resize_lock(thread);
 
-  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);
+  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;
   }
-  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);
+
+  ts.print(st, table_name);
 }
 
 template <typename VALUE, typename CONFIG, MEMFLAGS F>
--- a/src/hotspot/share/utilities/hashtable.cpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/utilities/hashtable.cpp	Wed May 08 11:11:50 2019 -0500
@@ -191,18 +191,7 @@
   }
 }
 
-// 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 @@
     }
     summary.add((double)count);
   }
-  double num_buckets = summary.num();
-  double num_entries = summary.sum();
-
-  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);
+  return TableStatistics(this->_stats_rate, summary, literal_bytes, sizeof(HashtableBucket<F>), sizeof(HashtableEntry<T, F>));
+}
 
-  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
--- a/src/hotspot/share/utilities/hashtable.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/utilities/hashtable.hpp	Wed May 08 11:11:50 2019 -0500
@@ -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 @@
 
 protected:
 
+  TableRateStatistics _stats_rate;
+
   void initialize(int table_size, int entry_size, int number_of_entries);
 
   // Accessor
@@ -245,6 +248,7 @@
     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:
--- a/src/hotspot/share/utilities/hashtable.inline.hpp	Wed May 08 20:57:12 2019 +0800
+++ b/src/hotspot/share/utilities/hashtable.inline.hpp	Wed May 08 11:11:50 2019 -0500
@@ -43,6 +43,7 @@
   for (int index = 0; index < _table_size; index++) {
     _buckets[index].clear();
   }
+  _stats_rate = TableRateStatistics();
 }
 
 
@@ -52,6 +53,7 @@
   // 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 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 @@
   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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/tableStatistics.cpp	Wed May 08 11:11:50 2019 -0500
@@ -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);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/tableStatistics.hpp	Wed May 08 11:11:50 2019 -0500
@@ -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
--- a/src/jdk.jfr/share/conf/jfr/default.jfc	Wed May 08 20:57:12 2019 +0800
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc	Wed May 08 11:11:50 2019 -0500
@@ -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>
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc	Wed May 08 20:57:12 2019 +0800
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc	Wed May 08 11:11:50 2019 -0500
@@ -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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/runtime/TestTableStatisticsEvent.java	Wed May 08 11:11:50 2019 -0500
@@ -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);
+      }
+    }
+  }
+}
--- a/test/lib/jdk/test/lib/jfr/EventNames.java	Wed May 08 20:57:12 2019 +0800
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java	Wed May 08 11:11:50 2019 -0500
@@ -82,6 +82,11 @@
     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";