Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8315149: Add hsperf counters for CPU time of internal GC threads #15082

Closed
wants to merge 61 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6c32e93
Add hsperf counters for CPU time of JVM internal threads
jjoo172 Jul 31, 2023
557dbfa
address dholmes@ comments
jjoo172 Aug 30, 2023
eb911ee
address remainder of dholmes' comments
jjoo172 Sep 7, 2023
74b6db2
address partial comments from Volker and Man
jjoo172 Sep 8, 2023
d2e4867
rename counters to be *.cpu_time
jjoo172 Sep 8, 2023
bcfe151
Properly initialize concurrent dedup thread counter
jjoo172 Sep 8, 2023
780dfd3
Move ThreadTotalCPUTimeClosure to thread.hpp
jjoo172 Sep 8, 2023
2f44b81
Fix includes
jjoo172 Sep 8, 2023
27c45a3
Merge branch 'openjdk:master' into master
jjoo172 Sep 11, 2023
43e2de1
Resolve some simple comments
jjoo172 Sep 11, 2023
18c8f9c
Address counte update correctness
jjoo172 Sep 12, 2023
dc7ff00
Partial commit attempting to add total cpu tracker
jjoo172 Sep 13, 2023
f07bf70
Update total gc cpu implementation (still not finished)
jjoo172 Sep 13, 2023
6ba441e
Update to improve total time tracking
jjoo172 Sep 14, 2023
9ed97e8
comment out lines that cause segfault
jjoo172 Sep 14, 2023
8b6c553
Fix segfaults on build
jjoo172 Sep 14, 2023
4e51426
Add unit test to check existence of GC CPU counters
jjoo172 Sep 14, 2023
7e1812e
Clean up test and improve total counter name
jjoo172 Sep 14, 2023
0a2565d
Address dholmes@ comments
jjoo172 Sep 16, 2023
d45e54d
Add header for failing build check
jjoo172 Sep 18, 2023
fed27c0
Add more header files for broken debug build
jjoo172 Sep 18, 2023
9c6e072
Fix more broken headers for sanity checks
jjoo172 Sep 19, 2023
0fbfa00
Fix logic for publishing total cpu time and convert atomic jlong to long
jjoo172 Sep 19, 2023
3eae6bb
Fix build issues
jjoo172 Sep 19, 2023
9b5772f
Update logic to use cmpxchg rather than add
jjoo172 Oct 3, 2023
2807c19
Remove header and fix long to jlong
jjoo172 Oct 4, 2023
590df03
add comment and change if defined to ifdef
jjoo172 Oct 5, 2023
1e8c1a4
Fix test
jjoo172 Oct 12, 2023
fc5cf3d
Add Copyright header to test and formatting changes
jjoo172 Oct 12, 2023
19fe9b3
Add call to publish in parallel gc and update counter names
jjoo172 Oct 13, 2023
b57aa46
Merge branch 'openjdk:master' into master
jjoo172 Oct 25, 2023
ebafa2b
Use 64-bit atomic add for incrementing counters
jjoo172 Oct 25, 2023
2fc508f
Remove StringDedup from GC thread list
jjoo172 Oct 26, 2023
0ef7046
Implement hsperf counter for G1ServiceThread
jjoo172 Oct 31, 2023
be104e1
Replace NULL with nullptr
jjoo172 Oct 31, 2023
2446149
Merge branch 'openjdk:master' into master
jjoo172 Nov 1, 2023
ba3c280
Attempt to fix broken test
jjoo172 Nov 1, 2023
9fb36a9
revert gitignore change
jjoo172 Nov 1, 2023
ac780c5
Attempt to fix duplicate name error in test
jjoo172 Nov 7, 2023
22ccb90
Refactor changes to counters, successful build
jjoo172 Nov 9, 2023
41771db
Add missing cpuTimeCounters files
jjoo172 Nov 9, 2023
2f3de0b
Make CPUTimeCounters a singleton class
jjoo172 Nov 10, 2023
533af85
Refactor ConcurrentRefine logic
jjoo172 Nov 11, 2023
189d185
Update parallel workers time after Remark
jjoo172 Nov 14, 2023
5bcafa6
Revert test changes and fix whitespace issues
jjoo172 Nov 15, 2023
4db8f09
Move vm and conc_dedup counters to cpuTimeCounters class
jjoo172 Nov 15, 2023
ce7dbfc
Fix whitespace
jjoo172 Nov 15, 2023
17a8eaf
Address comments and refactor TTTC class for simplification
jjoo172 Nov 21, 2023
46a2c55
Fix assertion logic
jjoo172 Nov 21, 2023
4ca30f3
Update memory tracking type for CPUTimeCounters
jjoo172 Nov 21, 2023
fcc7e47
Cleanup and address comments
jjoo172 Nov 22, 2023
0b79bce
Fix namespace issues
jjoo172 Nov 28, 2023
abb9025
Fix namespace issues (2)
jjoo172 Nov 28, 2023
91100e8
Change APIs to be all-static, address other comments
jjoo172 Nov 30, 2023
d11d696
remove whitespace
jjoo172 Nov 30, 2023
63adf78
Merge branch 'openjdk:master' into master
jjoo172 Nov 30, 2023
e6726ab
fix whitespace again
jjoo172 Nov 30, 2023
7e4cdcd
Add missing include
jjoo172 Nov 30, 2023
fcf00cf
Return after ShouldNotReachHere
jjoo172 Nov 30, 2023
c2e6619
Ensure TTTC is destructed before publishing
jjoo172 Dec 2, 2023
242fef8
Only create CPUTimeCounters if supported
jjoo172 Dec 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions src/hotspot/share/gc/g1/g1CollectedHeap.cpp
Original file line number Diff line number Diff line change
@@ -104,6 +104,7 @@
#include "oops/compressedOops.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/cpuTimeCounters.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/java.hpp"
@@ -1516,11 +1517,10 @@ jint G1CollectedHeap::initialize() {
evac_failure_injector()->reset();

CPUTimeCounters* instance = CPUTimeCounters::get_instance();
assert(instance != nullptr, "no instance found");
instance->create_counter(CPUTimeGroups::gc_parallel_workers);
instance->create_counter(CPUTimeGroups::gc_conc_mark);
instance->create_counter(CPUTimeGroups::gc_conc_refine);
instance->create_counter(CPUTimeGroups::gc_service);
instance->create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers);
instance->create_counter(CPUTimeGroups::CPUTimeType::gc_conc_mark);
instance->create_counter(CPUTimeGroups::CPUTimeType::gc_conc_refine);
instance->create_counter(CPUTimeGroups::CPUTimeType::gc_service);

G1InitLogger::print();

@@ -2431,15 +2431,14 @@ void G1CollectedHeap::update_parallel_gc_threads_cpu_time() {
}
WorkerThreads* worker_threads = workers();
if (worker_threads != nullptr) {
ThreadTotalCPUTimeClosure tttc(CPUTimeCounters::get_instance(),
CPUTimeGroups::gc_parallel_workers);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_parallel_workers);
// Currently parallel worker threads never terminate (JDK-8081682), so it is
// safe for VMThread to read their CPU times. However, if JDK-8087340 is
// resolved so they terminate, we should rethink if it is still safe.
worker_threads->threads_do(&tttc);
}

CPUTimeCounters::get_instance()->publish_total_cpu_time();
CPUTimeCounters::get_instance()->publish_gc_total_cpu_time();
}

void G1CollectedHeap::start_new_collection_set() {
1 change: 0 additions & 1 deletion src/hotspot/share/gc/g1/g1CollectedHeap.hpp
Original file line number Diff line number Diff line change
@@ -56,7 +56,6 @@
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
#include "memory/memRegion.hpp"
#include "runtime/cpuTimeCounters.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/threadSMR.hpp"
#include "utilities/bitMap.hpp"
3 changes: 2 additions & 1 deletion src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@
#include "gc/shared/suspendibleThreadSet.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/cpuTimeCounters.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/debug.hpp"
@@ -346,7 +347,7 @@ void G1ConcurrentMarkThread::update_threads_cpu_time() {
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
return;
}
ThreadTotalCPUTimeClosure tttc(CPUTimeCounters::get_instance(), CPUTimeGroups::gc_conc_mark);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_mark);
tttc.do_thread(this);
_cm->threads_do(&tttc);
}
3 changes: 1 addition & 2 deletions src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp
Original file line number Diff line number Diff line change
@@ -184,8 +184,7 @@ void G1PrimaryConcurrentRefineThread::track_usage() {
G1ConcurrentRefineThread::track_usage();
// The primary thread is responsible for updating the CPU time for all workers.
if (UsePerfData && os::is_thread_cpu_time_supported()) {
CPUTimeCounters* counters = CPUTimeCounters::get_instance();
ThreadTotalCPUTimeClosure tttc(counters, CPUTimeGroups::gc_conc_refine);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_refine);
cr()->threads_do(&tttc);
}
}
8 changes: 4 additions & 4 deletions src/hotspot/share/gc/g1/g1ServiceThread.cpp
Original file line number Diff line number Diff line change
@@ -132,7 +132,7 @@ void G1ServiceThread::run_task(G1ServiceTask* task) {

task->execute();

update_thread_cpu_time(task);
update_thread_cpu_time();

log_debug(gc, task)("G1 Service Thread (%s) (run: %1.3fms) (cpu: %1.3fms)",
task->name(),
@@ -155,10 +155,10 @@ void G1ServiceThread::stop_service() {
ml.notify();
}

void G1ServiceThread::update_thread_cpu_time(G1ServiceTask* task) {
void G1ServiceThread::update_thread_cpu_time() {
if (UsePerfData && os::is_thread_cpu_time_supported()) {
ThreadTotalCPUTimeClosure tttc(CPUTimeCounters::get_instance(), CPUTimeGroups::gc_service);
tttc.do_thread(task->_service_thread);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_service);
tttc.do_thread(this);
}
}

2 changes: 1 addition & 1 deletion src/hotspot/share/gc/g1/g1ServiceThread.hpp
Original file line number Diff line number Diff line change
@@ -122,7 +122,7 @@ class G1ServiceThread: public ConcurrentGCThread {
void schedule(G1ServiceTask* task, jlong delay, bool notify);

// Update the perf data counter for service thread.
void update_thread_cpu_time(G1ServiceTask* task);
void update_thread_cpu_time();

public:
G1ServiceThread();
7 changes: 3 additions & 4 deletions src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
Original file line number Diff line number Diff line change
@@ -129,7 +129,7 @@ jint ParallelScavengeHeap::initialize() {
}

// Create CPU time counter
CPUTimeCounters::get_instance()->create_counter(CPUTimeGroups::gc_parallel_workers);
CPUTimeCounters::get_instance()->create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers);

ParallelInitLogger::print();

@@ -896,12 +896,11 @@ void ParallelScavengeHeap::update_parallel_worker_threads_cpu_time() {
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
return;
}
ThreadTotalCPUTimeClosure tttc(CPUTimeCounters::get_instance(),
CPUTimeGroups::gc_parallel_workers);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_parallel_workers);
// Currently parallel worker threads in GCTaskManager never terminate, so it
// is safe for VMThread to read their CPU times. If upstream changes this
// behavior, we should rethink if it is still safe.
gc_threads_do(&tttc);

CPUTimeCounters::get_instance()->publish_total_cpu_time();
CPUTimeCounters::get_instance()->publish_gc_total_cpu_time();
}
Original file line number Diff line number Diff line change
@@ -49,7 +49,6 @@

OopStorage* StringDedup::Processor::_storages[2] = {};

PerfCounter* StringDedup::Processor::_concurrent_dedup_thread_cpu_time = nullptr;
StringDedup::StorageUse* volatile StringDedup::Processor::_storage_for_requests = nullptr;
StringDedup::StorageUse* StringDedup::Processor::_storage_for_processing = nullptr;

@@ -70,9 +69,7 @@ void StringDedup::Processor::initialize() {
_processor = new Processor();
if (UsePerfData && os::is_thread_cpu_time_supported()) {
EXCEPTION_MARK;
CPUTimeCounters* instance = CPUTimeCounters::get_instance();
instance->create_counter(CPUTimeGroups::conc_dedup);
_concurrent_dedup_thread_cpu_time = instance->get_counter(CPUTimeGroups::conc_dedup);
CPUTimeCounters::get_instance()->create_counter(CPUTimeGroups::CPUTimeType::conc_dedup);
}
}

@@ -198,7 +195,7 @@ void StringDedup::Processor::run(JavaThread* thread) {
_cur_stat.report_active_end();
log_statistics();
if (UsePerfData && os::is_thread_cpu_time_supported()) {
ThreadTotalCPUTimeClosure tttc(_concurrent_dedup_thread_cpu_time);
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::conc_dedup);
tttc.do_thread(thread);
}
}
Original file line number Diff line number Diff line change
@@ -48,9 +48,6 @@ class StringDedup::Processor : public CHeapObj<mtGC> {

NONCOPYABLE(Processor);

// Perf data for CPU time consumed by the string dedup thread.
static PerfCounter* _concurrent_dedup_thread_cpu_time;

static OopStorage* _storages[2];
static StorageUse* volatile _storage_for_requests;
static StorageUse* _storage_for_processing;
4 changes: 4 additions & 0 deletions src/hotspot/share/memory/universe.cpp
Original file line number Diff line number Diff line change
@@ -68,6 +68,7 @@
#include "prims/resolvedMethodTable.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/cpuTimeCounters.hpp"
#include "runtime/flags/jvmFlagLimit.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
@@ -781,6 +782,9 @@ jint universe_init() {

GCLogPrecious::initialize();

// Initialize CPUTimeCounters object, which must be done before creation of the heap.
CPUTimeCounters::initialize();

#ifdef _LP64
MetaspaceShared::adjust_heap_sizes_for_dumping();
#endif // _LP64
53 changes: 27 additions & 26 deletions src/hotspot/share/runtime/cpuTimeCounters.cpp
Original file line number Diff line number Diff line change
@@ -30,24 +30,23 @@

const char* CPUTimeGroups::to_string(CPUTimeType val) {
switch (val) {
case total:
case CPUTimeType::gc_total:
return "total_gc_cpu_time";
case gc_parallel_workers:
case CPUTimeType::gc_parallel_workers:
return "gc_parallel_workers";
case gc_conc_mark:
case CPUTimeType::gc_conc_mark:
return "gc_conc_mark";
case gc_conc_refine:
case CPUTimeType::gc_conc_refine:
return "gc_conc_refine";
case gc_service:
case CPUTimeType::gc_service:
return "gc_service";
case vm:
case CPUTimeType::vm:
return "vm";
case conc_dedup:
case CPUTimeType::conc_dedup:
return "conc_dedup";
case COUNT:
return "Illegal counter";
default:
ShouldNotReachHere();
};
ShouldNotReachHere();
}

bool CPUTimeGroups::is_gc_counter(CPUTimeType val) {
@@ -66,36 +65,36 @@ bool CPUTimeGroups::is_gc_counter(CPUTimeType val) {
ShouldNotReachHere();
}

CPUTimeCounters* CPUTimeCounters::_instance = nullptr;
CPUTimeCounters* CPUTimeCounters::_instance = nullptr;

CPUTimeCounters::CPUTimeCounters() :
_cpu_time_counters(),
_total_cpu_time_diff(0) {
create_counter(SUN_THREADS, CPUTimeGroups::total);
_gc_total_cpu_time_diff(0) {
create_counter(SUN_THREADS, CPUTimeGroups::CPUTimeType::gc_total);
}

void CPUTimeCounters::inc_total_cpu_time(jlong diff) {
Atomic::add(&_total_cpu_time_diff, diff);
void CPUTimeCounters::inc_gc_total_cpu_time(jlong diff) {
Atomic::add(&_gc_total_cpu_time_diff, diff);
}

void CPUTimeCounters::publish_total_cpu_time() {
void CPUTimeCounters::publish_gc_total_cpu_time() {
// Ensure that we are only incrementing atomically by using Atomic::cmpxchg
// to set the value to zero after we obtain the new CPU time difference.
jlong old_value;
jlong fetched_value = Atomic::load(&_total_cpu_time_diff);
jlong fetched_value = Atomic::load(&_gc_total_cpu_time_diff);
jlong new_value = 0;
do {
old_value = fetched_value;
fetched_value = Atomic::cmpxchg(&_total_cpu_time_diff, old_value, new_value);
fetched_value = Atomic::cmpxchg(&_gc_total_cpu_time_diff, old_value, new_value);
} while (old_value != fetched_value);
get_counter(CPUTimeGroups::total)->inc(fetched_value);
get_counter(CPUTimeGroups::CPUTimeType::gc_total)->inc(fetched_value);
}

void CPUTimeCounters::create_counter(CounterNS ns, CPUTimeGroups::CPUTimeType name) {
if (UsePerfData) {
EXCEPTION_MARK;
if (os::is_thread_cpu_time_supported()) {
_cpu_time_counters[name] =
_cpu_time_counters[static_cast<int>(name)] =
PerfDataManager::create_counter(ns, CPUTimeGroups::to_string(name),
PerfData::U_Ticks, CHECK);
}
@@ -107,14 +106,16 @@ void CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType group) {
}

PerfCounter* CPUTimeCounters::get_counter(CPUTimeGroups::CPUTimeType name) {
return _cpu_time_counters[name];
return _cpu_time_counters[static_cast<int>(name)];
}

ThreadTotalCPUTimeClosure::~ThreadTotalCPUTimeClosure() {
jlong net_cpu_time = _total - _counter->get_value();
_counter->inc(net_cpu_time);
if (_update_gc_counters) {
_gc_counters->inc_total_cpu_time(net_cpu_time);
CPUTimeCounters* instance = CPUTimeCounters::get_instance();
PerfCounter* counter = instance->get_counter(_name);
jlong net_cpu_time = _gc_total - counter->get_value();
counter->inc(net_cpu_time);
if (CPUTimeGroups::is_gc_counter(_name)) {
instance->inc_gc_total_cpu_time(net_cpu_time);
}
}

@@ -123,7 +124,7 @@ void ThreadTotalCPUTimeClosure::do_thread(Thread* thread) {
// pthread_getcpuclockid() and clock_gettime() must return 0. Thus caller
// must ensure the thread exists and has not terminated.
assert(os::is_thread_cpu_time_supported(), "os must support cpu time");
_total += os::thread_cpu_time(thread);
_gc_total += os::thread_cpu_time(thread);
}


37 changes: 16 additions & 21 deletions src/hotspot/share/runtime/cpuTimeCounters.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023 Google LLC. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -27,13 +27,15 @@
#ifndef SHARE_RUNTIME_CPUTIMECOUNTERS_HPP
#define SHARE_RUNTIME_CPUTIMECOUNTERS_HPP


#include "memory/iterator.hpp"
#include "runtime/perfData.hpp"
#include "runtime/perfDataTypes.hpp"

class CPUTimeGroups : public AllStatic {
public:
enum CPUTimeType {
total,
enum class CPUTimeType {
gc_total,
gc_parallel_workers,
gc_conc_mark,
gc_conc_refine,
@@ -49,24 +51,25 @@ class CPUTimeGroups : public AllStatic {

class CPUTimeCounters: public CHeapObj<mtGC> {
private:
// We want CPUTimeCounters to be a singleton instance accessed by the vm thread.
// CPUTimeCounters is a singleton instance.
CPUTimeCounters();
static CPUTimeCounters* _instance;

// An array of PerfCounters which correspond to the various counters we want
// to track. Indexed by the enum value `CPUTimeType`.
PerfCounter* _cpu_time_counters[CPUTimeGroups::COUNT];
PerfCounter* _cpu_time_counters[static_cast<int>(CPUTimeGroups::CPUTimeType::COUNT)];

// A long which atomically tracks how much CPU time has been spent doing GC
// since the last time we called `publish_total_cpu_time()`.
// It is incremented using Atomic::add() to prevent race conditions, and
// is added to the `total` CPUTimeGroup at the end of GC.
volatile jlong _total_cpu_time_diff;
// is added to the `gc_total` CPUTimeType at the end of GC.
volatile jlong _gc_total_cpu_time_diff;

void create_counter(CounterNS ns, CPUTimeGroups::CPUTimeType name);

public:
static CPUTimeCounters* get_instance() {
assert(_instance != nullptr, "no instance found");
return _instance;
}

@@ -79,11 +82,9 @@ class CPUTimeCounters: public CHeapObj<mtGC> {
CPUTimeCounters(const CPUTimeCounters& copy) = delete;
void operator=(const CPUTimeCounters& copy) = delete;

~CPUTimeCounters();

// Methods to modify and update counter for total CPU time spent doing GC.
void inc_total_cpu_time(jlong diff);
void publish_total_cpu_time();
void inc_gc_total_cpu_time(jlong diff);
void publish_gc_total_cpu_time();

void create_counter(CPUTimeGroups::CPUTimeType name);
PerfCounter* get_counter(CPUTimeGroups::CPUTimeType name);
@@ -93,18 +94,12 @@ class CPUTimeCounters: public CHeapObj<mtGC> {
// hsperfdata counter.
class ThreadTotalCPUTimeClosure: public ThreadClosure {
private:
jlong _total;
PerfCounter* _counter;
CPUTimeCounters* _gc_counters;
bool _update_gc_counters;
jlong _gc_total;
CPUTimeGroups::CPUTimeType _name;

public:
ThreadTotalCPUTimeClosure(PerfCounter* counter) :
_total(0), _counter(counter), _gc_counters(CPUTimeCounters::get_instance()), _update_gc_counters(false) {}

ThreadTotalCPUTimeClosure(CPUTimeCounters* counters, CPUTimeGroups::CPUTimeType name) :
_total(0), _counter(counters->get_counter(name)), _gc_counters(counters),
_update_gc_counters(CPUTimeGroups::is_gc_counter(name)) {}
ThreadTotalCPUTimeClosure(CPUTimeGroups::CPUTimeType name) :
_gc_total(0), _name(name) {}

~ThreadTotalCPUTimeClosure();

Loading