commit 686b567e20888aa7b64c190090a2d24bda3befd2 Author: Oli Gillespie Date: Tue Oct 24 11:44:31 2023 +0000 Keep temp symbols alive in queue diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 6162be7c0fe..a67278ab4d1 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -41,6 +41,7 @@ #include "services/diagnosticCommand.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/nonblockingQueue.inline.hpp" #include "utilities/utf8.hpp" // We used to not resize at all, so let's be conservative @@ -54,6 +55,8 @@ const size_t REHASH_LEN = 100; const size_t ON_STACK_BUFFER_LENGTH = 128; +const int32_t CLEANUP_DELAY_QUEUE_LEN = 100; + // -------------------------------------------------------------------------- inline bool symbol_equals_compact_hashtable_entry(Symbol* value, const char* key, int len) { @@ -91,6 +94,9 @@ static volatile size_t _items_count = 0; static volatile bool _has_items_to_clean = false; +static NonblockingQueue _cleanup_delay; +static volatile int32_t _cleanup_delay_len = 0; + static volatile bool _alt_hash = false; #ifdef USE_LIBRARY_BASED_TLS_ONLY @@ -343,6 +349,7 @@ Symbol* SymbolTable::new_symbol(const char* name, int len) { Symbol* sym = lookup_common(name, len, hash); if (sym == nullptr) { sym = do_add_if_needed(name, len, hash, /* is_permanent */ false); + add_to_cleanup_delay_queue(sym); // TODO: only temp symbols? } assert(sym->refcount() != 0, "lookup should have incremented the count"); assert(sym->equals(name, len), "symbol must be properly initialized"); @@ -517,7 +524,7 @@ Symbol* SymbolTable::do_add_if_needed(const char* name, int len, uintx hash, boo update_needs_rehash(rehash_warning); - if (clean_hint) { + if (clean_hint) { // || _cleanup_delay_len >= 0) { // TODO: trigger based on delay queue? mark_has_items_to_clean(); check_concurrent_work(); } @@ -783,6 +790,7 @@ void SymbolTable::check_concurrent_work() { } void SymbolTable::do_concurrent_work(JavaThread* jt) { + drain_cleanup_delay_queue(); double load_factor = get_load_factor(); log_debug(symboltable, perf)("Concurrent work, live factor: %g", load_factor); // We prefer growing, since that also removes dead items @@ -794,6 +802,31 @@ void SymbolTable::do_concurrent_work(JavaThread* jt) { _has_work = false; } +// Keep this symbol alive for some time to allow for reuse. +// Temp symbols for the same string can often be created in quick succession, +// and this queue allows them to be reused instead of churning. +void SymbolTable::add_to_cleanup_delay_queue(Symbol* sym) { + QueueNode* node = new QueueNode(sym); + _cleanup_delay.push(*node); + + // If the queue is now full, implement a one-in, one-out policy. + if (Atomic::add(&_cleanup_delay_len, 1, memory_order_relaxed) >= CLEANUP_DELAY_QUEUE_LEN) { + QueueNode* result = _cleanup_delay.pop(); + if (result != nullptr) { + delete result; + Atomic::dec(&_cleanup_delay_len); + } + } +} + +void SymbolTable::drain_cleanup_delay_queue() { + QueueNode* curr; + while ((curr = _cleanup_delay.pop()) != nullptr) { + delete curr; + Atomic::dec(&_cleanup_delay_len); + } +} + // Rehash bool SymbolTable::do_rehash() { if (!_local_table->is_safepoint_safe()) { diff --git a/src/hotspot/share/classfile/symbolTable.hpp b/src/hotspot/share/classfile/symbolTable.hpp index 282dd574c68..0f8897fdb3c 100644 --- a/src/hotspot/share/classfile/symbolTable.hpp +++ b/src/hotspot/share/classfile/symbolTable.hpp @@ -46,6 +46,29 @@ class SymbolTableCreateEntry; class constantPoolHandle; class SymbolClosure; +class QueueNode : public CHeapObj { +private: + Symbol* const _val; + QueueNode* volatile _next; + +public: + static QueueNode* volatile* next(QueueNode& node) { + return &node._next; + } + + QueueNode(Symbol* val) : _val(val), _next(nullptr) { + _val->increment_refcount(); + } + + ~QueueNode() { + _val->decrement_refcount(); + } + + QueueNode* next() { + return _next; + } +}; + class SymbolTable : public AllStatic { friend class VMStructs; friend class Symbol; @@ -98,6 +121,8 @@ class SymbolTable : public AllStatic { static void print_table_statistics(outputStream* st); static void try_rehash_table(); + static void add_to_cleanup_delay_queue(Symbol* sym); + static void drain_cleanup_delay_queue(); static bool do_rehash(); public: