Skip to content

Commit fb651fd

Browse files
JonasNorlinderalbertnetymk
authored andcommitted
8364638: Refactor and make accumulated GC CPU time code generic
Reviewed-by: ayang, sjohanss
1 parent 1548ac4 commit fb651fd

File tree

11 files changed

+205
-79
lines changed

11 files changed

+205
-79
lines changed

src/hotspot/share/gc/shared/collectedHeap.cpp

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -201,34 +201,6 @@ void CollectedHeap::print_relative_to_gc(GCWhen::Type when) const {
201201
}
202202
}
203203

204-
class CPUTimeThreadClosure : public ThreadClosure {
205-
private:
206-
jlong _cpu_time = 0;
207-
208-
public:
209-
virtual void do_thread(Thread* thread) {
210-
jlong cpu_time = os::thread_cpu_time(thread);
211-
if (cpu_time != -1) {
212-
_cpu_time += cpu_time;
213-
}
214-
}
215-
jlong cpu_time() { return _cpu_time; };
216-
};
217-
218-
double CollectedHeap::elapsed_gc_cpu_time() const {
219-
double string_dedup_cpu_time = UseStringDeduplication ?
220-
os::thread_cpu_time((Thread*)StringDedup::_processor->_thread) : 0;
221-
222-
if (string_dedup_cpu_time == -1) {
223-
string_dedup_cpu_time = 0;
224-
}
225-
226-
CPUTimeThreadClosure cl;
227-
gc_threads_do(&cl);
228-
229-
return (double)(cl.cpu_time() + _vmthread_cpu_time + string_dedup_cpu_time) / NANOSECS_PER_SEC;
230-
}
231-
232204
void CollectedHeap::print_before_gc() const {
233205
print_relative_to_gc(GCWhen::BeforeGC);
234206
}
@@ -633,36 +605,9 @@ void CollectedHeap::post_initialize() {
633605
initialize_serviceability();
634606
}
635607

636-
void CollectedHeap::log_gc_cpu_time() const {
637-
LogTarget(Info, gc, cpu) out;
638-
if (os::is_thread_cpu_time_supported() && out.is_enabled()) {
639-
double process_cpu_time = os::elapsed_process_cpu_time();
640-
double gc_cpu_time = elapsed_gc_cpu_time();
641-
642-
if (process_cpu_time == -1 || gc_cpu_time == -1) {
643-
log_warning(gc, cpu)("Could not sample CPU time");
644-
return;
645-
}
646-
647-
double usage;
648-
if (gc_cpu_time > process_cpu_time ||
649-
process_cpu_time == 0 || gc_cpu_time == 0) {
650-
// This can happen e.g. for short running processes with
651-
// low CPU utilization
652-
usage = 0;
653-
} else {
654-
usage = 100 * gc_cpu_time / process_cpu_time;
655-
}
656-
out.print("GC CPU usage: %.2f%% (Process: %.4fs GC: %.4fs)", usage, process_cpu_time, gc_cpu_time);
657-
}
658-
}
659-
660608
void CollectedHeap::before_exit() {
661609
print_tracing_info();
662610

663-
// Log GC CPU usage.
664-
log_gc_cpu_time();
665-
666611
// Stop any on-going concurrent work and prepare for exit.
667612
stop();
668613
}

src/hotspot/share/gc/shared/collectedHeap.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "runtime/handles.hpp"
3737
#include "runtime/perfDataTypes.hpp"
3838
#include "runtime/safepoint.hpp"
39+
#include "services/cpuTimeUsage.hpp"
3940
#include "services/memoryUsage.hpp"
4041
#include "utilities/debug.hpp"
4142
#include "utilities/formatBuffer.hpp"
@@ -89,6 +90,7 @@ class ParallelObjectIterator : public StackObj {
8990
// ZCollectedHeap
9091
//
9192
class CollectedHeap : public CHeapObj<mtGC> {
93+
friend class CPUTimeUsage::GC;
9294
friend class VMStructs;
9395
friend class JVMCIVMStructs;
9496
friend class IsSTWGCActiveMark; // Block structured external access to _is_stw_gc_active
@@ -429,8 +431,6 @@ class CollectedHeap : public CHeapObj<mtGC> {
429431

430432
void print_relative_to_gc(GCWhen::Type when) const;
431433

432-
void log_gc_cpu_time() const;
433-
434434
public:
435435
void pre_full_gc_dump(GCTimer* timer);
436436
void post_full_gc_dump(GCTimer* timer);
@@ -463,8 +463,6 @@ class CollectedHeap : public CHeapObj<mtGC> {
463463
// Iterator for all GC threads (other than VM thread)
464464
virtual void gc_threads_do(ThreadClosure* tc) const = 0;
465465

466-
double elapsed_gc_cpu_time() const;
467-
468466
void print_before_gc() const;
469467
void print_after_gc() const;
470468

src/hotspot/share/gc/shared/stringdedup/stringDedup.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@
103103
#include "memory/allocation.hpp"
104104
#include "memory/allStatic.hpp"
105105
#include "oops/oopsHierarchy.hpp"
106+
#include "services/cpuTimeUsage.hpp"
106107
#include "utilities/globalDefinitions.hpp"
107108

108-
class CollectedHeap;
109109
class Klass;
110110
class StringDedupThread;
111111
class ThreadClosure;
@@ -116,7 +116,7 @@ class ThreadClosure;
116116
// feature. Other functions in the StringDedup class are called where
117117
// needed, without requiring GC-specific code.
118118
class StringDedup : public AllStatic {
119-
friend class CollectedHeap;
119+
friend class CPUTimeUsage::GC;
120120
friend class StringDedupThread;
121121

122122
class Config;

src/hotspot/share/gc/shared/stringdedup/stringDedupProcessor.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727

2828
#include "gc/shared/stringdedup/stringDedup.hpp"
2929
#include "memory/allocation.hpp"
30+
#include "services/cpuTimeUsage.hpp"
3031
#include "utilities/macros.hpp"
3132

32-
class CollectedHeap;
3333
class JavaThread;
3434
class OopStorage;
3535

@@ -43,7 +43,7 @@ class OopStorage;
4343
// incremental operations for resizing and for removing dead entries, so
4444
// safepoint checks can be performed between steps in those operations.
4545
class StringDedup::Processor : public CHeapObj<mtGC> {
46-
friend class CollectedHeap;
46+
friend class CPUTimeUsage::GC;
4747

4848
Processor();
4949
~Processor() = default;

src/hotspot/share/memory/universe.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,13 @@
8181
#include "runtime/threads.hpp"
8282
#include "runtime/timerTrace.hpp"
8383
#include "sanitizers/leak.hpp"
84+
#include "services/cpuTimeUsage.hpp"
8485
#include "services/memoryService.hpp"
8586
#include "utilities/align.hpp"
8687
#include "utilities/autoRestore.hpp"
8788
#include "utilities/debug.hpp"
8889
#include "utilities/formatBuffer.hpp"
90+
#include "utilities/globalDefinitions.hpp"
8991
#include "utilities/macros.hpp"
9092
#include "utilities/ostream.hpp"
9193
#include "utilities/preserveException.hpp"
@@ -1300,6 +1302,63 @@ void Universe::verify(VerifyOption option, const char* prefix) {
13001302
}
13011303
}
13021304

1305+
static void log_cpu_time() {
1306+
LogTarget(Info, cpu) cpuLog;
1307+
if (!cpuLog.is_enabled()) {
1308+
return;
1309+
}
1310+
1311+
const double process_cpu_time = os::elapsed_process_cpu_time();
1312+
if (process_cpu_time == 0 || process_cpu_time == -1) {
1313+
// 0 can happen e.g. for short running processes with
1314+
// low CPU utilization
1315+
return;
1316+
}
1317+
1318+
const double gc_threads_cpu_time = (double) CPUTimeUsage::GC::gc_threads() / NANOSECS_PER_SEC;
1319+
const double gc_vm_thread_cpu_time = (double) CPUTimeUsage::GC::vm_thread() / NANOSECS_PER_SEC;
1320+
const double gc_string_dedup_cpu_time = (double) CPUTimeUsage::GC::stringdedup() / NANOSECS_PER_SEC;
1321+
const double gc_cpu_time = (double) gc_threads_cpu_time + gc_vm_thread_cpu_time + gc_string_dedup_cpu_time;
1322+
1323+
const double elasped_time = os::elapsedTime();
1324+
const bool has_error = CPUTimeUsage::Error::has_error();
1325+
1326+
if (gc_cpu_time < process_cpu_time) {
1327+
cpuLog.print("=== CPU time Statistics =============================================================");
1328+
if (has_error) {
1329+
cpuLog.print("WARNING: CPU time sampling reported errors, numbers may be unreliable");
1330+
}
1331+
cpuLog.print(" CPUs");
1332+
cpuLog.print(" s %% utilized");
1333+
cpuLog.print(" Process");
1334+
cpuLog.print(" Total %30.4f %6.2f %8.1f", process_cpu_time, 100.0, process_cpu_time / elasped_time);
1335+
cpuLog.print(" Garbage Collection %30.4f %6.2f %8.1f", gc_cpu_time, percent_of(gc_cpu_time, process_cpu_time), gc_cpu_time / elasped_time);
1336+
cpuLog.print(" GC Threads %30.4f %6.2f %8.1f", gc_threads_cpu_time, percent_of(gc_threads_cpu_time, process_cpu_time), gc_threads_cpu_time / elasped_time);
1337+
cpuLog.print(" VM Thread %30.4f %6.2f %8.1f", gc_vm_thread_cpu_time, percent_of(gc_vm_thread_cpu_time, process_cpu_time), gc_vm_thread_cpu_time / elasped_time);
1338+
1339+
if (UseStringDeduplication) {
1340+
cpuLog.print(" String Deduplication %30.4f %6.2f %8.1f", gc_string_dedup_cpu_time, percent_of(gc_string_dedup_cpu_time, process_cpu_time), gc_string_dedup_cpu_time / elasped_time);
1341+
}
1342+
cpuLog.print("=====================================================================================");
1343+
}
1344+
}
1345+
1346+
void Universe::before_exit() {
1347+
log_cpu_time();
1348+
heap()->before_exit();
1349+
1350+
// Print GC/heap related information.
1351+
Log(gc, exit) log;
1352+
if (log.is_info()) {
1353+
LogStream ls_info(log.info());
1354+
Universe::print_on(&ls_info);
1355+
if (log.is_trace()) {
1356+
LogStream ls_trace(log.trace());
1357+
MutexLocker mcld(ClassLoaderDataGraph_lock);
1358+
ClassLoaderDataGraph::print_on(&ls_trace);
1359+
}
1360+
}
1361+
}
13031362

13041363
#ifndef PRODUCT
13051364
void Universe::calculate_verify_data(HeapWord* low_boundary, HeapWord* high_boundary) {

src/hotspot/share/memory/universe.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ class Universe: AllStatic {
305305
// The particular choice of collected heap.
306306
static CollectedHeap* heap() { return _collectedHeap; }
307307

308+
static void before_exit();
309+
308310
DEBUG_ONLY(static bool is_stw_gc_active();)
309311
DEBUG_ONLY(static bool is_in_heap(const void* p);)
310312
DEBUG_ONLY(static bool is_in_heap_or_null(const void* p) { return p == nullptr || is_in_heap(p); })

src/hotspot/share/runtime/java.cpp

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -475,19 +475,7 @@ void before_exit(JavaThread* thread, bool halt) {
475475
NativeHeapTrimmer::cleanup();
476476

477477
// Run before exit and then stop concurrent GC threads
478-
Universe::heap()->before_exit();
479-
480-
// Print GC/heap related information.
481-
Log(gc, exit) log;
482-
if (log.is_info()) {
483-
LogStream ls_info(log.info());
484-
Universe::print_on(&ls_info);
485-
if (log.is_trace()) {
486-
LogStream ls_trace(log.trace());
487-
MutexLocker mcld(ClassLoaderDataGraph_lock);
488-
ClassLoaderDataGraph::print_on(&ls_trace);
489-
}
490-
}
478+
Universe::before_exit();
491479

492480
if (PrintBytecodeHistogram) {
493481
BytecodeHistogram::print();

src/hotspot/share/runtime/vmThread.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
#include "jfr/jfrEvents.hpp"
2929
#include "jfr/support/jfrThreadId.hpp"
3030
#include "logging/log.hpp"
31-
#include "logging/logStream.hpp"
3231
#include "logging/logConfiguration.hpp"
32+
#include "logging/logStream.hpp"
3333
#include "memory/resourceArea.hpp"
3434
#include "memory/universe.hpp"
3535
#include "oops/oop.inline.hpp"
@@ -46,8 +46,8 @@
4646
#include "runtime/safepoint.hpp"
4747
#include "runtime/synchronizer.hpp"
4848
#include "runtime/timerTrace.hpp"
49-
#include "runtime/vmThread.hpp"
5049
#include "runtime/vmOperations.hpp"
50+
#include "runtime/vmThread.hpp"
5151
#include "utilities/dtrace.hpp"
5252
#include "utilities/events.hpp"
5353
#include "utilities/vmError.hpp"

src/hotspot/share/runtime/vmThread.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727

2828
#include "runtime/atomic.hpp"
2929
#include "runtime/javaThread.hpp"
30-
#include "runtime/perfDataTypes.hpp"
3130
#include "runtime/nonJavaThread.hpp"
31+
#include "runtime/perfDataTypes.hpp"
3232
#include "runtime/task.hpp"
3333
#include "runtime/vmOperation.hpp"
3434

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
#include "gc/shared/collectedHeap.hpp"
26+
#include "gc/shared/stringdedup/stringDedup.hpp"
27+
#include "gc/shared/stringdedup/stringDedupProcessor.hpp"
28+
#include "memory/universe.hpp"
29+
#include "runtime/globals.hpp"
30+
#include "runtime/os.hpp"
31+
#include "runtime/perfData.hpp"
32+
#include "runtime/vmThread.hpp"
33+
#include "services/cpuTimeUsage.hpp"
34+
35+
volatile bool CPUTimeUsage::Error::_has_error = false;
36+
37+
static inline jlong thread_cpu_time_or_zero(Thread* thread) {
38+
jlong cpu_time = os::thread_cpu_time(thread);
39+
if (cpu_time == -1) {
40+
CPUTimeUsage::Error::mark_error();
41+
return 0;
42+
}
43+
return cpu_time;
44+
}
45+
46+
class CPUTimeThreadClosure : public ThreadClosure {
47+
private:
48+
jlong _cpu_time = 0;
49+
50+
public:
51+
virtual void do_thread(Thread* thread) {
52+
_cpu_time += thread_cpu_time_or_zero(thread);
53+
}
54+
jlong cpu_time() { return _cpu_time; };
55+
};
56+
57+
jlong CPUTimeUsage::GC::vm_thread() {
58+
return Universe::heap()->_vmthread_cpu_time;
59+
}
60+
61+
jlong CPUTimeUsage::GC::gc_threads() {
62+
CPUTimeThreadClosure cl;
63+
Universe::heap()->gc_threads_do(&cl);
64+
return cl.cpu_time();
65+
}
66+
67+
jlong CPUTimeUsage::GC::total() {
68+
return gc_threads() + vm_thread() + stringdedup();
69+
}
70+
71+
jlong CPUTimeUsage::GC::stringdedup() {
72+
if (UseStringDeduplication) {
73+
return thread_cpu_time_or_zero((Thread*)StringDedup::_processor->_thread);
74+
}
75+
return 0;
76+
}
77+
78+
bool CPUTimeUsage::Error::has_error() {
79+
return Atomic::load(&_has_error);
80+
}
81+
82+
void CPUTimeUsage::Error::mark_error() {
83+
Atomic::store(&_has_error, true);
84+
}

0 commit comments

Comments
 (0)