8325871: Move StringTable and SymbolTable rehashing calls
Reviewed-by: eosterlund, aboldtch
This commit is contained in:
parent
9e98118f28
commit
7734466c46
@ -55,6 +55,7 @@
|
|||||||
#include "runtime/safepointVerifiers.hpp"
|
#include "runtime/safepointVerifiers.hpp"
|
||||||
#include "runtime/timerTrace.hpp"
|
#include "runtime/timerTrace.hpp"
|
||||||
#include "runtime/trimNativeHeap.hpp"
|
#include "runtime/trimNativeHeap.hpp"
|
||||||
|
#include "runtime/vmOperations.hpp"
|
||||||
#include "services/diagnosticCommand.hpp"
|
#include "services/diagnosticCommand.hpp"
|
||||||
#include "utilities/concurrentHashTable.inline.hpp"
|
#include "utilities/concurrentHashTable.inline.hpp"
|
||||||
#include "utilities/concurrentHashTableTasks.inline.hpp"
|
#include "utilities/concurrentHashTableTasks.inline.hpp"
|
||||||
@ -267,10 +268,17 @@ size_t StringTable::table_size() {
|
|||||||
return ((size_t)1) << _local_table->get_size_log2(Thread::current());
|
return ((size_t)1) << _local_table->get_size_log2(Thread::current());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StringTable::has_work() {
|
||||||
|
return Atomic::load_acquire(&_has_work);
|
||||||
|
}
|
||||||
|
|
||||||
void StringTable::trigger_concurrent_work() {
|
void StringTable::trigger_concurrent_work() {
|
||||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
// Avoid churn on ServiceThread
|
||||||
Atomic::store(&_has_work, true);
|
if (!has_work()) {
|
||||||
Service_lock->notify_all();
|
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
Atomic::store(&_has_work, true);
|
||||||
|
Service_lock->notify_all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probing
|
// Probing
|
||||||
@ -308,6 +316,13 @@ class StringTableGet : public StackObj {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void StringTable::update_needs_rehash(bool rehash) {
|
||||||
|
if (rehash) {
|
||||||
|
_needs_rehashing = true;
|
||||||
|
trigger_concurrent_work();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
|
oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
|
||||||
Thread* thread = Thread::current();
|
Thread* thread = Thread::current();
|
||||||
StringTableLookupJchar lookup(thread, hash, name, len);
|
StringTableLookupJchar lookup(thread, hash, name, len);
|
||||||
@ -499,15 +514,20 @@ void StringTable::gc_notification(size_t num_dead) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringTable::has_work() {
|
bool StringTable::should_grow() {
|
||||||
return Atomic::load_acquire(&_has_work);
|
return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringTable::do_concurrent_work(JavaThread* jt) {
|
void StringTable::do_concurrent_work(JavaThread* jt) {
|
||||||
double load_factor = get_load_factor();
|
// Rehash if needed. Rehashing goes to a safepoint but the rest of this
|
||||||
log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor);
|
// work is concurrent.
|
||||||
|
if (needs_rehashing() && maybe_rehash_table()) {
|
||||||
|
Atomic::release_store(&_has_work, false);
|
||||||
|
return; // done, else grow
|
||||||
|
}
|
||||||
|
log_debug(stringtable, perf)("Concurrent work, live factor: %g", get_load_factor());
|
||||||
// We prefer growing, since that also removes dead items
|
// We prefer growing, since that also removes dead items
|
||||||
if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
|
if (should_grow()) {
|
||||||
grow(jt);
|
grow(jt);
|
||||||
} else {
|
} else {
|
||||||
clean_dead_entries(jt);
|
clean_dead_entries(jt);
|
||||||
@ -515,85 +535,48 @@ void StringTable::do_concurrent_work(JavaThread* jt) {
|
|||||||
Atomic::release_store(&_has_work, false);
|
Atomic::release_store(&_has_work, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rehash
|
// Called at VM_Operation safepoint
|
||||||
bool StringTable::do_rehash() {
|
void StringTable::rehash_table() {
|
||||||
if (!_local_table->is_safepoint_safe()) {
|
assert(SafepointSynchronize::is_at_safepoint(), "must be called at safepoint");
|
||||||
return false;
|
// The ServiceThread initiates the rehashing so it is not resizing.
|
||||||
}
|
assert (_local_table->is_safepoint_safe(), "Should not be resizing now");
|
||||||
|
|
||||||
|
_alt_hash_seed = AltHashing::compute_seed();
|
||||||
|
|
||||||
// We use current size, not max size.
|
// We use current size, not max size.
|
||||||
size_t new_size = _local_table->get_size_log2(Thread::current());
|
size_t new_size = _local_table->get_size_log2(Thread::current());
|
||||||
StringTableHash* new_table = new StringTableHash(new_size, END_SIZE, REHASH_LEN, true);
|
StringTableHash* new_table = new StringTableHash(new_size, END_SIZE, REHASH_LEN, true);
|
||||||
// Use alt hash from now on
|
// Use alt hash from now on
|
||||||
_alt_hash = true;
|
_alt_hash = true;
|
||||||
if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) {
|
_local_table->rehash_nodes_to(Thread::current(), new_table);
|
||||||
_alt_hash = false;
|
|
||||||
delete new_table;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// free old table
|
// free old table
|
||||||
delete _local_table;
|
delete _local_table;
|
||||||
_local_table = new_table;
|
_local_table = new_table;
|
||||||
|
|
||||||
return true;
|
_rehashed = true;
|
||||||
|
_needs_rehashing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringTable::should_grow() {
|
bool StringTable::maybe_rehash_table() {
|
||||||
return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StringTable::rehash_table_expects_safepoint_rehashing() {
|
|
||||||
// No rehashing required
|
|
||||||
if (!needs_rehashing()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grow instead of rehash
|
|
||||||
if (should_grow()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already rehashed
|
|
||||||
if (_rehashed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resizing in progress
|
|
||||||
if (!_local_table->is_safepoint_safe()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StringTable::rehash_table() {
|
|
||||||
log_debug(stringtable)("Table imbalanced, rehashing called.");
|
log_debug(stringtable)("Table imbalanced, rehashing called.");
|
||||||
|
|
||||||
// Grow instead of rehash.
|
// Grow instead of rehash.
|
||||||
if (should_grow()) {
|
if (should_grow()) {
|
||||||
log_debug(stringtable)("Choosing growing over rehashing.");
|
log_debug(stringtable)("Choosing growing over rehashing.");
|
||||||
trigger_concurrent_work();
|
|
||||||
_needs_rehashing = false;
|
_needs_rehashing = false;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// Already rehashed.
|
// Already rehashed.
|
||||||
if (_rehashed) {
|
if (_rehashed) {
|
||||||
log_warning(stringtable)("Rehashing already done, still long lists.");
|
log_warning(stringtable)("Rehashing already done, still long lists.");
|
||||||
trigger_concurrent_work();
|
|
||||||
_needs_rehashing = false;
|
_needs_rehashing = false;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_alt_hash_seed = AltHashing::compute_seed();
|
VM_RehashStringTable op;
|
||||||
{
|
VMThread::execute(&op);
|
||||||
if (do_rehash()) {
|
return true; // return true because we tried.
|
||||||
_rehashed = true;
|
|
||||||
} else {
|
|
||||||
log_info(stringtable)("Resizes in progress rehashing skipped.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_needs_rehashing = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -71,8 +71,6 @@ class StringTable : AllStatic {
|
|||||||
|
|
||||||
static void print_table_statistics(outputStream* st);
|
static void print_table_statistics(outputStream* st);
|
||||||
|
|
||||||
static bool do_rehash();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static size_t table_size();
|
static size_t table_size();
|
||||||
static TableStatistics get_table_statistics();
|
static TableStatistics get_table_statistics();
|
||||||
@ -94,16 +92,11 @@ class StringTable : AllStatic {
|
|||||||
// Rehash the string table if it gets out of balance
|
// Rehash the string table if it gets out of balance
|
||||||
private:
|
private:
|
||||||
static bool should_grow();
|
static bool should_grow();
|
||||||
|
static bool maybe_rehash_table();
|
||||||
public:
|
public:
|
||||||
static bool rehash_table_expects_safepoint_rehashing();
|
|
||||||
static void rehash_table();
|
static void rehash_table();
|
||||||
static bool needs_rehashing() { return _needs_rehashing; }
|
static bool needs_rehashing() { return _needs_rehashing; }
|
||||||
static inline void update_needs_rehash(bool rehash) {
|
static inline void update_needs_rehash(bool rehash);
|
||||||
if (rehash) {
|
|
||||||
_needs_rehashing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sharing
|
// Sharing
|
||||||
#if INCLUDE_CDS_JAVA_HEAP
|
#if INCLUDE_CDS_JAVA_HEAP
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -246,10 +246,15 @@ size_t SymbolTable::table_size() {
|
|||||||
return ((size_t)1) << _local_table->get_size_log2(Thread::current());
|
return ((size_t)1) << _local_table->get_size_log2(Thread::current());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SymbolTable::has_work() { return Atomic::load_acquire(&_has_work); }
|
||||||
|
|
||||||
void SymbolTable::trigger_cleanup() {
|
void SymbolTable::trigger_cleanup() {
|
||||||
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
// Avoid churn on ServiceThread
|
||||||
_has_work = true;
|
if (!has_work()) {
|
||||||
Service_lock->notify_all();
|
MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
_has_work = true;
|
||||||
|
Service_lock->notify_all();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SymbolsDo : StackObj {
|
class SymbolsDo : StackObj {
|
||||||
@ -413,6 +418,13 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void SymbolTable::update_needs_rehash(bool rehash) {
|
||||||
|
if (rehash) {
|
||||||
|
_needs_rehashing = true;
|
||||||
|
trigger_cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) {
|
Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) {
|
||||||
Thread* thread = Thread::current();
|
Thread* thread = Thread::current();
|
||||||
SymbolTableLookup lookup(name, len, hash);
|
SymbolTableLookup lookup(name, len, hash);
|
||||||
@ -772,7 +784,7 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SymbolTable::check_concurrent_work() {
|
void SymbolTable::check_concurrent_work() {
|
||||||
if (_has_work) {
|
if (has_work()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// We should clean/resize if we have
|
// We should clean/resize if we have
|
||||||
@ -785,98 +797,70 @@ void SymbolTable::check_concurrent_work() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SymbolTable::should_grow() {
|
||||||
|
return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached();
|
||||||
|
}
|
||||||
|
|
||||||
void SymbolTable::do_concurrent_work(JavaThread* jt) {
|
void SymbolTable::do_concurrent_work(JavaThread* jt) {
|
||||||
double load_factor = get_load_factor();
|
// Rehash if needed. Rehashing goes to a safepoint but the rest of this
|
||||||
log_debug(symboltable, perf)("Concurrent work, live factor: %g", load_factor);
|
// work is concurrent.
|
||||||
|
if (needs_rehashing() && maybe_rehash_table()) {
|
||||||
|
Atomic::release_store(&_has_work, false);
|
||||||
|
return; // done, else grow
|
||||||
|
}
|
||||||
|
log_debug(symboltable, perf)("Concurrent work, live factor: %g", get_load_factor());
|
||||||
// We prefer growing, since that also removes dead items
|
// We prefer growing, since that also removes dead items
|
||||||
if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
|
if (should_grow()) {
|
||||||
grow(jt);
|
grow(jt);
|
||||||
} else {
|
} else {
|
||||||
clean_dead_entries(jt);
|
clean_dead_entries(jt);
|
||||||
}
|
}
|
||||||
_has_work = false;
|
Atomic::release_store(&_has_work, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rehash
|
// Called at VM_Operation safepoint
|
||||||
bool SymbolTable::do_rehash() {
|
void SymbolTable::rehash_table() {
|
||||||
if (!_local_table->is_safepoint_safe()) {
|
assert(SafepointSynchronize::is_at_safepoint(), "must be called at safepoint");
|
||||||
return false;
|
// The ServiceThread initiates the rehashing so it is not resizing.
|
||||||
}
|
assert (_local_table->is_safepoint_safe(), "Should not be resizing now");
|
||||||
|
|
||||||
|
_alt_hash_seed = AltHashing::compute_seed();
|
||||||
|
|
||||||
// We use current size
|
// We use current size
|
||||||
size_t new_size = _local_table->get_size_log2(Thread::current());
|
size_t new_size = _local_table->get_size_log2(Thread::current());
|
||||||
SymbolTableHash* new_table = new SymbolTableHash(new_size, END_SIZE, REHASH_LEN, true);
|
SymbolTableHash* new_table = new SymbolTableHash(new_size, END_SIZE, REHASH_LEN, true);
|
||||||
// Use alt hash from now on
|
// Use alt hash from now on
|
||||||
_alt_hash = true;
|
_alt_hash = true;
|
||||||
if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) {
|
_local_table->rehash_nodes_to(Thread::current(), new_table);
|
||||||
_alt_hash = false;
|
|
||||||
delete new_table;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// free old table
|
// free old table
|
||||||
delete _local_table;
|
delete _local_table;
|
||||||
_local_table = new_table;
|
_local_table = new_table;
|
||||||
|
|
||||||
return true;
|
_rehashed = true;
|
||||||
|
_needs_rehashing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SymbolTable::should_grow() {
|
bool SymbolTable::maybe_rehash_table() {
|
||||||
return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SymbolTable::rehash_table_expects_safepoint_rehashing() {
|
|
||||||
// No rehashing required
|
|
||||||
if (!needs_rehashing()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grow instead of rehash
|
|
||||||
if (should_grow()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already rehashed
|
|
||||||
if (_rehashed) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resizing in progress
|
|
||||||
if (!_local_table->is_safepoint_safe()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SymbolTable::rehash_table() {
|
|
||||||
log_debug(symboltable)("Table imbalanced, rehashing called.");
|
log_debug(symboltable)("Table imbalanced, rehashing called.");
|
||||||
|
|
||||||
// Grow instead of rehash.
|
// Grow instead of rehash.
|
||||||
if (should_grow()) {
|
if (should_grow()) {
|
||||||
log_debug(symboltable)("Choosing growing over rehashing.");
|
log_debug(symboltable)("Choosing growing over rehashing.");
|
||||||
trigger_cleanup();
|
|
||||||
_needs_rehashing = false;
|
_needs_rehashing = false;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Already rehashed.
|
// Already rehashed.
|
||||||
if (_rehashed) {
|
if (_rehashed) {
|
||||||
log_warning(symboltable)("Rehashing already done, still long lists.");
|
log_warning(symboltable)("Rehashing already done, still long lists.");
|
||||||
trigger_cleanup();
|
|
||||||
_needs_rehashing = false;
|
_needs_rehashing = false;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_alt_hash_seed = AltHashing::compute_seed();
|
VM_RehashSymbolTable op;
|
||||||
|
VMThread::execute(&op);
|
||||||
if (do_rehash()) {
|
return true;
|
||||||
_rehashed = true;
|
|
||||||
} else {
|
|
||||||
log_info(symboltable)("Resizes in progress rehashing skipped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_needs_rehashing = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -98,7 +98,6 @@ class SymbolTable : public AllStatic {
|
|||||||
static void print_table_statistics(outputStream* st);
|
static void print_table_statistics(outputStream* st);
|
||||||
|
|
||||||
static void try_rehash_table();
|
static void try_rehash_table();
|
||||||
static bool do_rehash();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// The symbol table
|
// The symbol table
|
||||||
@ -114,7 +113,7 @@ public:
|
|||||||
static void create_table();
|
static void create_table();
|
||||||
|
|
||||||
static void do_concurrent_work(JavaThread* jt);
|
static void do_concurrent_work(JavaThread* jt);
|
||||||
static bool has_work() { return _has_work; }
|
static bool has_work();
|
||||||
static void trigger_cleanup();
|
static void trigger_cleanup();
|
||||||
|
|
||||||
// Probing
|
// Probing
|
||||||
@ -146,16 +145,12 @@ public:
|
|||||||
// Rehash the string table if it gets out of balance
|
// Rehash the string table if it gets out of balance
|
||||||
private:
|
private:
|
||||||
static bool should_grow();
|
static bool should_grow();
|
||||||
|
static bool maybe_rehash_table();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool rehash_table_expects_safepoint_rehashing();
|
|
||||||
static void rehash_table();
|
static void rehash_table();
|
||||||
static bool needs_rehashing() { return _needs_rehashing; }
|
static bool needs_rehashing() { return _needs_rehashing; }
|
||||||
static inline void update_needs_rehash(bool rehash) {
|
static inline void update_needs_rehash(bool rehash);
|
||||||
if (rehash) {
|
|
||||||
_needs_rehashing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Heap dumper and CDS
|
// Heap dumper and CDS
|
||||||
static void symbols_do(SymbolClosure *cl);
|
static void symbols_do(SymbolClosure *cl);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -23,9 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderDataGraph.hpp"
|
|
||||||
#include "classfile/stringTable.hpp"
|
|
||||||
#include "classfile/symbolTable.hpp"
|
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "code/nmethod.hpp"
|
#include "code/nmethod.hpp"
|
||||||
#include "code/pcDesc.hpp"
|
#include "code/pcDesc.hpp"
|
||||||
@ -510,13 +507,6 @@ void SafepointSynchronize::end() {
|
|||||||
post_safepoint_end_event(event, safepoint_id());
|
post_safepoint_end_event(event, safepoint_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafepointSynchronize::is_cleanup_needed() {
|
|
||||||
// Need a safepoint if some inline cache buffers is non-empty
|
|
||||||
if (StringTable::needs_rehashing()) return true;
|
|
||||||
if (SymbolTable::needs_rehashing()) return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ParallelCleanupTask : public WorkerTask {
|
class ParallelCleanupTask : public WorkerTask {
|
||||||
private:
|
private:
|
||||||
SubTasksDone _subtasks;
|
SubTasksDone _subtasks;
|
||||||
@ -548,14 +538,6 @@ public:
|
|||||||
uint expected_num_workers() const {
|
uint expected_num_workers() const {
|
||||||
uint workers = 0;
|
uint workers = 0;
|
||||||
|
|
||||||
if (SymbolTable::rehash_table_expects_safepoint_rehashing()) {
|
|
||||||
workers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringTable::rehash_table_expects_safepoint_rehashing()) {
|
|
||||||
workers++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_do_lazy_roots) {
|
if (_do_lazy_roots) {
|
||||||
workers++;
|
workers++;
|
||||||
}
|
}
|
||||||
@ -564,21 +546,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void work(uint worker_id) {
|
void work(uint worker_id) {
|
||||||
// These tasks are ordered by relative length of time to execute so that potentially longer tasks start first.
|
|
||||||
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH)) {
|
|
||||||
if (SymbolTable::needs_rehashing()) {
|
|
||||||
Tracer t("rehashing symbol table");
|
|
||||||
SymbolTable::rehash_table();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_STRING_TABLE_REHASH)) {
|
|
||||||
if (StringTable::needs_rehashing()) {
|
|
||||||
Tracer t("rehashing string table");
|
|
||||||
StringTable::rehash_table();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING)) {
|
if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING)) {
|
||||||
if (_do_lazy_roots) {
|
if (_do_lazy_roots) {
|
||||||
Tracer t("lazy partial thread root processing");
|
Tracer t("lazy partial thread root processing");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -71,8 +71,6 @@ class SafepointSynchronize : AllStatic {
|
|||||||
// The enums are listed in the order of the tasks when done serially.
|
// The enums are listed in the order of the tasks when done serially.
|
||||||
enum SafepointCleanupTasks {
|
enum SafepointCleanupTasks {
|
||||||
SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING,
|
SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING,
|
||||||
SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH,
|
|
||||||
SAFEPOINT_CLEANUP_STRING_TABLE_REHASH,
|
|
||||||
SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP,
|
SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP,
|
||||||
// Leave this one last.
|
// Leave this one last.
|
||||||
SAFEPOINT_CLEANUP_NUM_TASKS
|
SAFEPOINT_CLEANUP_NUM_TASKS
|
||||||
@ -158,7 +156,6 @@ public:
|
|||||||
// Exception handling for page polling
|
// Exception handling for page polling
|
||||||
static void handle_polling_page_exception(JavaThread *thread);
|
static void handle_polling_page_exception(JavaThread *thread);
|
||||||
|
|
||||||
static bool is_cleanup_needed();
|
|
||||||
static void do_cleanup_tasks();
|
static void do_cleanup_tasks();
|
||||||
|
|
||||||
static void set_is_at_safepoint() { _state = _synchronized; }
|
static void set_is_at_safepoint() { _state = _synchronized; }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -37,7 +37,6 @@
|
|||||||
#define VM_OPS_DO(template) \
|
#define VM_OPS_DO(template) \
|
||||||
template(Halt) \
|
template(Halt) \
|
||||||
template(SafepointALot) \
|
template(SafepointALot) \
|
||||||
template(Cleanup) \
|
|
||||||
template(ThreadDump) \
|
template(ThreadDump) \
|
||||||
template(PrintThreads) \
|
template(PrintThreads) \
|
||||||
template(FindDeadlocks) \
|
template(FindDeadlocks) \
|
||||||
@ -106,6 +105,8 @@
|
|||||||
template(ClassLoaderHierarchyOperation) \
|
template(ClassLoaderHierarchyOperation) \
|
||||||
template(DumpHashtable) \
|
template(DumpHashtable) \
|
||||||
template(CleanClassLoaderDataMetaspaces) \
|
template(CleanClassLoaderDataMetaspaces) \
|
||||||
|
template(RehashStringTable) \
|
||||||
|
template(RehashSymbolTable) \
|
||||||
template(PrintCompileQueue) \
|
template(PrintCompileQueue) \
|
||||||
template(PrintClassHierarchy) \
|
template(PrintClassHierarchy) \
|
||||||
template(PrintClasses) \
|
template(PrintClasses) \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderDataGraph.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
|
#include "classfile/stringTable.hpp"
|
||||||
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/vmSymbols.hpp"
|
#include "classfile/vmSymbols.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "compiler/compileBroker.hpp"
|
#include "compiler/compileBroker.hpp"
|
||||||
@ -103,6 +105,14 @@ void VM_CleanClassLoaderDataMetaspaces::doit() {
|
|||||||
ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces();
|
ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VM_RehashStringTable::doit() {
|
||||||
|
StringTable::rehash_table();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VM_RehashSymbolTable::doit() {
|
||||||
|
SymbolTable::rehash_table();
|
||||||
|
}
|
||||||
|
|
||||||
VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) {
|
VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) {
|
||||||
_thread = thread;
|
_thread = thread;
|
||||||
_id = id;
|
_id = id;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2024, 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
|
||||||
@ -54,11 +54,6 @@ class VM_SafepointALot: public VM_EmptyOperation {
|
|||||||
VMOp_Type type() const { return VMOp_SafepointALot; }
|
VMOp_Type type() const { return VMOp_SafepointALot; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VM_Cleanup: public VM_EmptyOperation {
|
|
||||||
public:
|
|
||||||
VMOp_Type type() const { return VMOp_Cleanup; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// empty vm op, evaluated just to force a safepoint
|
// empty vm op, evaluated just to force a safepoint
|
||||||
class VM_ForceSafepoint: public VM_EmptyOperation {
|
class VM_ForceSafepoint: public VM_EmptyOperation {
|
||||||
public:
|
public:
|
||||||
@ -98,6 +93,20 @@ class VM_CleanClassLoaderDataMetaspaces : public VM_Operation {
|
|||||||
void doit();
|
void doit();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VM_RehashStringTable : public VM_Operation {
|
||||||
|
public:
|
||||||
|
VM_RehashStringTable() {}
|
||||||
|
VMOp_Type type() const { return VMOp_RehashStringTable; }
|
||||||
|
void doit();
|
||||||
|
};
|
||||||
|
|
||||||
|
class VM_RehashSymbolTable : public VM_Operation {
|
||||||
|
public:
|
||||||
|
VM_RehashSymbolTable() {}
|
||||||
|
VMOp_Type type() const { return VMOp_RehashSymbolTable; }
|
||||||
|
void doit();
|
||||||
|
};
|
||||||
|
|
||||||
// Deopt helper that can deoptimize frames in threads other than the
|
// Deopt helper that can deoptimize frames in threads other than the
|
||||||
// current thread. Only used through Deoptimization::deoptimize_frame.
|
// current thread. Only used through Deoptimization::deoptimize_frame.
|
||||||
class VM_DeoptimizeFrame: public VM_Operation {
|
class VM_DeoptimizeFrame: public VM_Operation {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2024, 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
|
||||||
@ -98,14 +98,14 @@ void VMOperationTimeoutTask::disarm() {
|
|||||||
// Implementation of VMThread stuff
|
// Implementation of VMThread stuff
|
||||||
|
|
||||||
static VM_SafepointALot safepointALot_op;
|
static VM_SafepointALot safepointALot_op;
|
||||||
static VM_Cleanup cleanup_op;
|
static VM_ForceSafepoint no_op;
|
||||||
|
|
||||||
bool VMThread::_should_terminate = false;
|
bool VMThread::_should_terminate = false;
|
||||||
bool VMThread::_terminated = false;
|
bool VMThread::_terminated = false;
|
||||||
Monitor* VMThread::_terminate_lock = nullptr;
|
Monitor* VMThread::_terminate_lock = nullptr;
|
||||||
VMThread* VMThread::_vm_thread = nullptr;
|
VMThread* VMThread::_vm_thread = nullptr;
|
||||||
VM_Operation* VMThread::_cur_vm_operation = nullptr;
|
VM_Operation* VMThread::_cur_vm_operation = nullptr;
|
||||||
VM_Operation* VMThread::_next_vm_operation = &cleanup_op; // Prevent any thread from setting an operation until VM thread is ready.
|
VM_Operation* VMThread::_next_vm_operation = &no_op; // Prevent any thread from setting an operation until VM thread is ready.
|
||||||
PerfCounter* VMThread::_perf_accumulated_vm_operation_time = nullptr;
|
PerfCounter* VMThread::_perf_accumulated_vm_operation_time = nullptr;
|
||||||
VMOperationTimeoutTask* VMThread::_timeout_task = nullptr;
|
VMOperationTimeoutTask* VMThread::_timeout_task = nullptr;
|
||||||
|
|
||||||
@ -337,9 +337,7 @@ void VMThread::setup_periodic_safepoint_if_needed() {
|
|||||||
if (!max_time_exceeded) {
|
if (!max_time_exceeded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (SafepointSynchronize::is_cleanup_needed()) {
|
if (SafepointALot) {
|
||||||
_next_vm_operation = &cleanup_op;
|
|
||||||
} else if (SafepointALot) {
|
|
||||||
_next_vm_operation = &safepointALot_op;
|
_next_vm_operation = &safepointALot_op;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -499,7 +497,7 @@ void VMThread::loop() {
|
|||||||
|
|
||||||
// Need to set a calling thread for ops not passed
|
// Need to set a calling thread for ops not passed
|
||||||
// via the normal way.
|
// via the normal way.
|
||||||
cleanup_op.set_calling_thread(_vm_thread);
|
no_op.set_calling_thread(_vm_thread);
|
||||||
safepointALot_op.set_calling_thread(_vm_thread);
|
safepointALot_op.set_calling_thread(_vm_thread);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -524,8 +524,9 @@ class ConcurrentHashTable : public CHeapObj<F> {
|
|||||||
void statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, outputStream* st,
|
void statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, outputStream* st,
|
||||||
const char* table_name);
|
const char* table_name);
|
||||||
|
|
||||||
// Moves all nodes from this table to to_cht
|
// Moves all nodes from this table to to_cht with new hash code.
|
||||||
bool try_move_nodes_to(Thread* thread, ConcurrentHashTable<CONFIG, F>* to_cht);
|
// Must be done at a safepoint.
|
||||||
|
void rehash_nodes_to(Thread* thread, ConcurrentHashTable<CONFIG, F>* to_cht);
|
||||||
|
|
||||||
// Scoped multi getter.
|
// Scoped multi getter.
|
||||||
class MultiGetHandle : private ScopedCS {
|
class MultiGetHandle : private ScopedCS {
|
||||||
|
@ -1288,12 +1288,10 @@ inline void ConcurrentHashTable<CONFIG, F>::
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename CONFIG, MEMFLAGS F>
|
template <typename CONFIG, MEMFLAGS F>
|
||||||
inline bool ConcurrentHashTable<CONFIG, F>::
|
inline void ConcurrentHashTable<CONFIG, F>::
|
||||||
try_move_nodes_to(Thread* thread, ConcurrentHashTable<CONFIG, F>* to_cht)
|
rehash_nodes_to(Thread* thread, ConcurrentHashTable<CONFIG, F>* to_cht)
|
||||||
{
|
{
|
||||||
if (!try_resize_lock(thread)) {
|
assert(is_safepoint_safe(), "rehashing is at a safepoint - cannot be resizing");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(_new_table == nullptr || _new_table == POISON_PTR, "Must be null");
|
assert(_new_table == nullptr || _new_table == POISON_PTR, "Must be null");
|
||||||
for (size_t bucket_it = 0; bucket_it < _table->_size; bucket_it++) {
|
for (size_t bucket_it = 0; bucket_it < _table->_size; bucket_it++) {
|
||||||
Bucket* bucket = _table->get_bucket(bucket_it);
|
Bucket* bucket = _table->get_bucket(bucket_it);
|
||||||
@ -1313,8 +1311,6 @@ inline bool ConcurrentHashTable<CONFIG, F>::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock_resize_lock(thread);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // SHARE_UTILITIES_CONCURRENTHASHTABLE_INLINE_HPP
|
#endif // SHARE_UTILITIES_CONCURRENTHASHTABLE_INLINE_HPP
|
||||||
|
@ -399,7 +399,8 @@ static void cht_move_to(Thread* thr) {
|
|||||||
EXPECT_TRUE(from_cht->insert(thr, stl3, val3)) << "Insert unique value failed.";
|
EXPECT_TRUE(from_cht->insert(thr, stl3, val3)) << "Insert unique value failed.";
|
||||||
|
|
||||||
SimpleTestTable* to_cht = new SimpleTestTable();
|
SimpleTestTable* to_cht = new SimpleTestTable();
|
||||||
EXPECT_TRUE(from_cht->try_move_nodes_to(thr, to_cht)) << "Moving nodes to new table failed";
|
// This is single threaded and not shared
|
||||||
|
from_cht->rehash_nodes_to(thr, to_cht);
|
||||||
|
|
||||||
ChtCountScan scan_old;
|
ChtCountScan scan_old;
|
||||||
EXPECT_TRUE(from_cht->try_scan(thr, scan_old)) << "Scanning table should work.";
|
EXPECT_TRUE(from_cht->try_scan(thr, scan_old)) << "Scanning table should work.";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user