Skip to content

Commit 1e18fff

Browse files
committed
8328473: StringTable and SymbolTable statistics delay time to safepoint
Reviewed-by: shade, eosterlund
1 parent a0dd565 commit 1e18fff

File tree

5 files changed

+122
-69
lines changed

5 files changed

+122
-69
lines changed

src/hotspot/share/classfile/stringTable.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -744,13 +744,29 @@ struct SizeFunc : StackObj {
744744
TableStatistics StringTable::get_table_statistics() {
745745
static TableStatistics ts;
746746
SizeFunc sz;
747-
ts = _local_table->statistics_get(Thread::current(), sz, ts);
747+
748+
Thread* jt = Thread::current();
749+
StringTableHash::StatisticsTask sts(_local_table);
750+
if (!sts.prepare(jt)) {
751+
return ts; // return old table statistics
752+
}
753+
{
754+
TraceTime timer("GetStatistics", TRACETIME_LOG(Debug, stringtable, perf));
755+
while (sts.do_task(jt, sz)) {
756+
sts.pause(jt);
757+
if (jt->is_Java_thread()) {
758+
ThreadBlockInVM tbivm(JavaThread::cast(jt));
759+
}
760+
sts.cont(jt);
761+
}
762+
}
763+
ts = sts.done(jt);
748764
return ts;
749765
}
750766

751767
void StringTable::print_table_statistics(outputStream* st) {
752-
SizeFunc sz;
753-
_local_table->statistics_to(Thread::current(), sz, st, "StringTable");
768+
TableStatistics ts = get_table_statistics();
769+
ts.print(st, "StringTable");
754770
#if INCLUDE_CDS_JAVA_HEAP
755771
if (!_shared_table.empty()) {
756772
_shared_table.print_table_statistics(st, "Shared String Table");

src/hotspot/share/classfile/symbolTable.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -572,23 +572,35 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name) {
572572
return sym;
573573
}
574574

575-
struct SizeFunc : StackObj {
576-
size_t operator()(Symbol* value) {
575+
TableStatistics SymbolTable::get_table_statistics() {
576+
static TableStatistics ts;
577+
auto sz = [&](Symbol* value) {
577578
assert(value != nullptr, "expected valid value");
578579
return (value)->size() * HeapWordSize;
579580
};
580-
};
581581

582-
TableStatistics SymbolTable::get_table_statistics() {
583-
static TableStatistics ts;
584-
SizeFunc sz;
585-
ts = _local_table->statistics_get(Thread::current(), sz, ts);
582+
Thread* jt = Thread::current();
583+
SymbolTableHash::StatisticsTask sts(_local_table);
584+
if (!sts.prepare(jt)) {
585+
return ts; // return old table statistics
586+
}
587+
{
588+
TraceTime timer("GetStatistics", TRACETIME_LOG(Debug, symboltable, perf));
589+
while (sts.do_task(jt, sz)) {
590+
sts.pause(jt);
591+
if (jt->is_Java_thread()) {
592+
ThreadBlockInVM tbivm(JavaThread::cast(jt));
593+
}
594+
sts.cont(jt);
595+
}
596+
}
597+
ts = sts.done(jt);
586598
return ts;
587-
}
599+
};
588600

589601
void SymbolTable::print_table_statistics(outputStream* st) {
590-
SizeFunc sz;
591-
_local_table->statistics_to(Thread::current(), sz, st, "SymbolTable");
602+
TableStatistics ts = get_table_statistics();
603+
ts.print(st, "SymbolTable");
592604

593605
if (!_shared_table.empty()) {
594606
_shared_table.print_table_statistics(st, "Shared Symbol Table");

src/hotspot/share/utilities/concurrentHashTable.hpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -56,9 +56,12 @@ class ConcurrentHashTable : public CHeapObj<MT> {
5656
_stats_rate->remove();
5757
}
5858
}
59-
// Calculate statistics. Item sizes are calculated with VALUE_SIZE_FUNC.
59+
// Calculate statistics. Item sizes are calculated with VALUE_SIZE_FUNC, and accumulated in summary and literal_size.
6060
template <typename VALUE_SIZE_FUNC>
61-
TableStatistics statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f);
61+
void internal_statistics_range(Thread* thread, size_t start, size_t stop,
62+
VALUE_SIZE_FUNC& sts_f, NumberSeq& summary, size_t& literal_size);
63+
64+
TableStatistics internal_statistics_epilog(Thread* thread, NumberSeq summary, size_t literal_size);
6265

6366
// This is the internal node structure.
6467
// Only constructed with placement new from memory allocated with MemTag of
@@ -531,12 +534,6 @@ class ConcurrentHashTable : public CHeapObj<MT> {
531534
template <typename VALUE_SIZE_FUNC>
532535
TableStatistics statistics_get(Thread* thread, VALUE_SIZE_FUNC& vs_f, TableStatistics old);
533536

534-
// Writes statistics to the outputStream. Item sizes are calculated with
535-
// VALUE_SIZE_FUNC.
536-
template <typename VALUE_SIZE_FUNC>
537-
void statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, outputStream* st,
538-
const char* table_name);
539-
540537
// Moves all nodes from this table to to_cht with new hash code.
541538
// Must be done at a safepoint.
542539
void rehash_nodes_to(Thread* thread, ConcurrentHashTable<CONFIG, MT>* to_cht);
@@ -559,6 +556,7 @@ class ConcurrentHashTable : public CHeapObj<MT> {
559556
public:
560557
class BulkDeleteTask;
561558
class GrowTask;
559+
class StatisticsTask;
562560
class ScanTask;
563561
};
564562

src/hotspot/share/utilities/concurrentHashTable.inline.hpp

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,35 +1232,34 @@ inline void ConcurrentHashTable<CONFIG, MT>::
12321232

12331233
template <typename CONFIG, MemTag MT>
12341234
template <typename VALUE_SIZE_FUNC>
1235-
inline TableStatistics ConcurrentHashTable<CONFIG, MT>::
1236-
statistics_calculate(Thread* thread, VALUE_SIZE_FUNC& vs_f)
1235+
inline void ConcurrentHashTable<CONFIG, MT>::
1236+
internal_statistics_range(Thread* thread, size_t start, size_t stop,
1237+
VALUE_SIZE_FUNC& vs_f, NumberSeq& summary, size_t& literal_size)
12371238
{
1238-
constexpr size_t batch_size = 128;
1239-
NumberSeq summary;
1240-
size_t literal_bytes = 0;
1241-
InternalTable* table = get_table();
1242-
size_t num_batches = table->_size / batch_size;
1243-
for (size_t batch_start = 0; batch_start < _table->_size; batch_start += batch_size) {
1244-
// We batch the use of ScopedCS here as it has been found to be quite expensive to
1245-
// invoke it for every single bucket.
1246-
size_t batch_end = MIN2(batch_start + batch_size, _table->_size);
1247-
ScopedCS cs(thread, this);
1248-
for (size_t bucket_it = batch_start; bucket_it < batch_end; bucket_it++) {
1249-
size_t count = 0;
1250-
Bucket* bucket = table->get_bucket(bucket_it);
1251-
if (bucket->have_redirect() || bucket->is_locked()) {
1252-
continue;
1253-
}
1254-
Node* current_node = bucket->first();
1255-
while (current_node != nullptr) {
1256-
++count;
1257-
literal_bytes += vs_f(current_node->value());
1258-
current_node = current_node->next();
1259-
}
1260-
summary.add((double)count);
1239+
// We batch the use of ScopedCS here as it has been found to be quite expensive to
1240+
// invoke it for every single bucket.
1241+
ScopedCS cs(thread, this);
1242+
for (size_t bucket_it = start; bucket_it < stop; bucket_it++) {
1243+
size_t count = 0;
1244+
Bucket* bucket = _table->get_bucket(bucket_it);
1245+
if (bucket->have_redirect() || bucket->is_locked()) {
1246+
continue;
12611247
}
1248+
Node* current_node = bucket->first();
1249+
while (current_node != nullptr) {
1250+
++count;
1251+
literal_size += vs_f(current_node->value());
1252+
current_node = current_node->next();
1253+
}
1254+
summary.add((double)count);
12621255
}
1256+
}
12631257

1258+
template <typename CONFIG, MemTag MT>
1259+
inline TableStatistics ConcurrentHashTable<CONFIG, MT>::
1260+
internal_statistics_epilog(Thread* thread, NumberSeq summary, size_t literal_bytes)
1261+
{
1262+
unlock_resize_lock(thread);
12641263
if (_stats_rate == nullptr) {
12651264
return TableStatistics(summary, literal_bytes, sizeof(Bucket), sizeof(Node));
12661265
} else {
@@ -1276,28 +1275,12 @@ inline TableStatistics ConcurrentHashTable<CONFIG, MT>::
12761275
if (!try_resize_lock(thread)) {
12771276
return old;
12781277
}
1278+
InternalTable* table = get_table();
1279+
NumberSeq summary;
1280+
size_t literal_bytes = 0;
12791281

1280-
TableStatistics ts = statistics_calculate(thread, vs_f);
1281-
unlock_resize_lock(thread);
1282-
1283-
return ts;
1284-
}
1285-
1286-
template <typename CONFIG, MemTag MT>
1287-
template <typename VALUE_SIZE_FUNC>
1288-
inline void ConcurrentHashTable<CONFIG, MT>::
1289-
statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f,
1290-
outputStream* st, const char* table_name)
1291-
{
1292-
if (!try_resize_lock(thread)) {
1293-
st->print_cr("statistics unavailable at this moment");
1294-
return;
1295-
}
1296-
1297-
TableStatistics ts = statistics_calculate(thread, vs_f);
1298-
unlock_resize_lock(thread);
1299-
1300-
ts.print(st, table_name);
1282+
internal_statistics_range(thread, 0, table->_size, vs_f, summary, literal_bytes);
1283+
return internal_statistics_epilog(thread, summary, literal_bytes);
13011284
}
13021285

13031286
template <typename CONFIG, MemTag MT>

src/hotspot/share/utilities/concurrentHashTableTasks.inline.hpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -229,6 +229,50 @@ class ConcurrentHashTable<CONFIG, MT>::GrowTask :
229229
}
230230
};
231231

232+
template <typename CONFIG, MemTag MT>
233+
class ConcurrentHashTable<CONFIG, MT>::StatisticsTask :
234+
public BucketsOperation
235+
{
236+
NumberSeq _summary;
237+
size_t _literal_bytes;
238+
public:
239+
StatisticsTask(ConcurrentHashTable<CONFIG, MT>* cht) : BucketsOperation(cht), _literal_bytes(0) { }
240+
241+
// Before start prepare must be called.
242+
bool prepare(Thread* thread) {
243+
bool lock = BucketsOperation::_cht->try_resize_lock(thread);
244+
if (!lock) {
245+
return false;
246+
}
247+
248+
this->setup(thread);
249+
return true;
250+
}
251+
252+
// Scans part of the table adding to statistics.
253+
template <typename VALUE_SIZE_FUNC>
254+
bool do_task(Thread* thread, VALUE_SIZE_FUNC& sz) {
255+
size_t start, stop;
256+
assert(BucketsOperation::_cht->_resize_lock_owner != nullptr,
257+
"Should be locked");
258+
if (!this->claim(&start, &stop)) {
259+
return false;
260+
}
261+
BucketsOperation::_cht->internal_statistics_range(thread, start, stop, sz, _summary, _literal_bytes);
262+
assert(BucketsOperation::_cht->_resize_lock_owner != nullptr,
263+
"Should be locked");
264+
return true;
265+
}
266+
267+
// Must be called after do_task returns false.
268+
TableStatistics done(Thread* thread) {
269+
this->thread_owns_resize_lock(thread);
270+
TableStatistics ts = BucketsOperation::_cht->internal_statistics_epilog(thread, _summary, _literal_bytes);
271+
this->thread_do_not_own_resize_lock(thread);
272+
return ts;
273+
}
274+
};
275+
232276
template <typename CONFIG, MemTag MT>
233277
class ConcurrentHashTable<CONFIG, MT>::ScanTask :
234278
public BucketsOperation

0 commit comments

Comments
 (0)