Skip to content

Commit 28d4e42

Browse files
Log GC vtime on VM exit
1 parent 1c72b35 commit 28d4e42

19 files changed

+166
-6
lines changed

src/hotspot/share/gc/g1/g1CollectedHeap.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1470,6 +1470,8 @@ bool G1CollectedHeap::concurrent_mark_is_terminating() const {
14701470
}
14711471

14721472
void G1CollectedHeap::stop() {
1473+
log_gc_vtime();
1474+
14731475
// Stop all concurrent threads. We do this to make sure these threads
14741476
// do not continue to execute and access resources (e.g. logging)
14751477
// that are destroyed during shutdown.
@@ -1478,6 +1480,26 @@ void G1CollectedHeap::stop() {
14781480
_cm_thread->stop();
14791481
}
14801482

1483+
class G1VCPUThreadClosure : public ThreadClosure {
1484+
private:
1485+
volatile jlong _vtime = 0;
1486+
1487+
public:
1488+
virtual void do_thread(Thread *thread) {
1489+
Atomic::add(&_vtime, os::thread_cpu_time(thread));
1490+
}
1491+
jlong vtime() { return _vtime; };
1492+
};
1493+
1494+
double G1CollectedHeap::elapsed_gc_vtime() {
1495+
G1VCPUThreadClosure cl;
1496+
_cr->threads_do(&cl);
1497+
_cm->threads_do(&cl);
1498+
_workers->threads_do(&cl);
1499+
return ((double) cl.vtime() + os::thread_cpu_time(_service_thread) + os::thread_cpu_time(_cm_thread) + Universe::heap()->vm_vtime()) / NANOSECS_PER_SEC;
1500+
}
1501+
1502+
14811503
void G1CollectedHeap::safepoint_synchronize_begin() {
14821504
SuspendibleThreadSet::synchronize();
14831505
}

src/hotspot/share/gc/g1/g1CollectedHeap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,8 @@ class G1CollectedHeap : public CollectedHeap {
932932
GrowableArray<GCMemoryManager*> memory_managers() override;
933933
GrowableArray<MemoryPool*> memory_pools() override;
934934

935+
double elapsed_gc_vtime() override;
936+
935937
void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) override;
936938

937939
static void start_codecache_marking_cycle_if_inactive(bool concurrent_mark_start);

src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,27 @@ void ParallelScavengeHeap::initialize_serviceability() {
160160

161161
}
162162

163+
void ParallelScavengeHeap::stop() {
164+
log_gc_vtime();
165+
}
166+
167+
class ParallelVCPUThreadClosure : public ThreadClosure {
168+
private:
169+
volatile jlong _vtime = 0;
170+
171+
public:
172+
virtual void do_thread(Thread *thread) {
173+
Atomic::add(&_vtime, os::thread_cpu_time(thread));
174+
}
175+
jlong vtime() { return _vtime; };
176+
};
177+
178+
double ParallelScavengeHeap::elapsed_gc_vtime() {
179+
ParallelVCPUThreadClosure cl;
180+
workers().threads_do(&cl);
181+
return (double)(cl.vtime() + Universe::heap()->vm_vtime()) / NANOSECS_PER_SEC;
182+
}
183+
163184
void ParallelScavengeHeap::safepoint_synchronize_begin() {
164185
if (UseStringDeduplication) {
165186
SuspendibleThreadSet::synchronize();

src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ class ParallelScavengeHeap : public CollectedHeap {
214214
void gc_threads_do(ThreadClosure* tc) const override;
215215
void print_tracing_info() const override;
216216

217+
void stop() override;
218+
double elapsed_gc_vtime() override;
219+
217220
WorkerThreads* safepoint_workers() override { return &_workers; }
218221

219222
PreGenGCValues get_pre_gc_values() const;

src/hotspot/share/gc/serial/serialHeap.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ GrowableArray<MemoryPool*> SerialHeap::memory_pools() {
145145
return memory_pools;
146146
}
147147

148+
void SerialHeap::stop() {
149+
log_gc_vtime();
150+
}
151+
152+
double SerialHeap::elapsed_gc_vtime() {
153+
return (double) Universe::heap()->vm_vtime() / NANOSECS_PER_SEC;
154+
}
155+
148156
void SerialHeap::safepoint_synchronize_begin() {
149157
if (UseStringDeduplication) {
150158
SuspendibleThreadSet::synchronize();

src/hotspot/share/gc/serial/serialHeap.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ class SerialHeap : public CollectedHeap {
274274
GrowableArray<GCMemoryManager*> memory_managers() override;
275275
GrowableArray<MemoryPool*> memory_pools() override;
276276

277+
void stop() override;
278+
double elapsed_gc_vtime() override;
279+
277280
DefNewGeneration* young_gen() const {
278281
return _young_gen;
279282
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ size_t CollectedHeap::_lab_alignment_reserve = SIZE_MAX;
6666
Klass* CollectedHeap::_filler_object_klass = nullptr;
6767
size_t CollectedHeap::_filler_array_max_size = 0;
6868
size_t CollectedHeap::_stack_chunk_max_size = 0;
69+
jlong CollectedHeap::_vm_vtime = 0;
6970

7071
class GCLogMessage : public FormatBuffer<512> {};
7172

@@ -213,6 +214,27 @@ void CollectedHeap::print() const {
213214
print_gc_on(tty);
214215
}
215216

217+
void CollectedHeap::log_gc_vtime() {
218+
if (os::is_thread_cpu_time_supported()) {
219+
double process_vtime = os::elapsed_process_vtime();
220+
double gc_vtime = elapsed_gc_vtime();
221+
222+
if (process_vtime == -1 || gc_vtime == -1) return;
223+
224+
log_info(gc, cpu)("Process CPU time: %fs", process_vtime);
225+
log_info(gc, cpu)("GC CPU time: %fs", gc_vtime);
226+
double cost = -1;
227+
if (gc_vtime > process_vtime || process_vtime == 0 || gc_vtime == 0) {
228+
// This can happen e.g. for short running processes with
229+
// low CPU utilization
230+
cost = 0;
231+
} else {
232+
cost = 100 * gc_vtime / process_vtime;
233+
}
234+
log_info(gc)("GC CPU cost: %2.2f%%", cost);
235+
}
236+
}
237+
216238
void CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) {
217239
const GCHeapSummary& heap_summary = create_heap_summary();
218240
gc_tracer->report_gc_heap_summary(when, heap_summary);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ class CollectedHeap : public CHeapObj<mtGC> {
132132
NOT_PRODUCT(volatile size_t _promotion_failure_alot_count;)
133133
NOT_PRODUCT(volatile size_t _promotion_failure_alot_gc_number;)
134134

135+
static jlong _vm_vtime;
136+
135137
// Reason for current garbage collection. Should be set to
136138
// a value reflecting no collection between collections.
137139
GCCause::Cause _gc_cause;
@@ -246,6 +248,14 @@ class CollectedHeap : public CHeapObj<mtGC> {
246248
virtual void safepoint_synchronize_begin() {}
247249
virtual void safepoint_synchronize_end() {}
248250

251+
static jlong vm_vtime() {
252+
return _vm_vtime;
253+
}
254+
255+
static void add_vm_vtime(jlong time) {
256+
_vm_vtime += time;
257+
}
258+
249259
void initialize_reserved_region(const ReservedHeapSpace& rs);
250260

251261
virtual size_t capacity() const = 0;
@@ -455,6 +465,9 @@ class CollectedHeap : public CHeapObj<mtGC> {
455465
// Default implementation does nothing.
456466
virtual void print_tracing_info() const = 0;
457467

468+
virtual double elapsed_gc_vtime() { return -1; };
469+
void log_gc_vtime();
470+
458471
void print_before_gc() const;
459472
void print_after_gc() const;
460473

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ class VM_GC_Sync_Operation : public VM_Operation {
9393
virtual bool doit_prologue();
9494
// Releases the Heap_lock.
9595
virtual void doit_epilogue();
96+
97+
bool operation_is_gc() const { return true; }
9698
};
9799

98100
class VM_Verify : public VM_GC_Sync_Operation {

src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2202,6 +2202,7 @@ uint ShenandoahHeap::max_workers() {
22022202
}
22032203

22042204
void ShenandoahHeap::stop() {
2205+
log_gc_vtime();
22052206
// The shutdown sequence should be able to terminate when GC is running.
22062207

22072208
// Step 0. Notify policy to disable event recording and prevent visiting gc threads during shutdown
@@ -2219,6 +2220,23 @@ void ShenandoahHeap::stop() {
22192220
}
22202221
}
22212222

2223+
class ShenandoahCPUThreadClosure : public ThreadClosure {
2224+
private:
2225+
volatile jlong _vtime = 0;
2226+
2227+
public:
2228+
virtual void do_thread(Thread *thread) {
2229+
Atomic::add(&_vtime, os::thread_cpu_time(thread));
2230+
}
2231+
jlong vtime() { return _vtime; };
2232+
};
2233+
2234+
double ShenandoahHeap::elapsed_gc_vtime() {
2235+
ShenandoahCPUThreadClosure cl;
2236+
ShenandoahHeap::heap()->gc_threads_do(&cl);
2237+
return (double)(cl.vtime() + Universe::heap()->vm_vtime()) / NANOSECS_PER_SEC;
2238+
}
2239+
22222240
void ShenandoahHeap::stw_unload_classes(bool full_gc) {
22232241
if (!unload_classes()) return;
22242242
ClassUnloadingContext ctx(_workers->active_workers(),

src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ class ShenandoahHeap : public CollectedHeap {
209209

210210
void stop() override;
211211

212+
double elapsed_gc_vtime() override;
213+
212214
void prepare_for_verify() override;
213215
void verify(VerifyOption vo) override;
214216

src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ class VM_ShenandoahOperation : public VM_Operation {
5555
void log_active_generation(const char* prefix);
5656
bool doit_prologue() override;
5757
void doit_epilogue() override;
58+
59+
bool operation_is_gc() const override { return true; }
5860
};
5961

6062
class VM_ShenandoahReferenceOperation : public VM_ShenandoahOperation {

src/hotspot/share/gc/z/zCollectedHeap.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,31 @@ class ZStopConcurrentGCThreadClosure : public ThreadClosure {
105105

106106
void ZCollectedHeap::stop() {
107107
log_info_p(gc, exit)("Stopping ZGC");
108+
log_gc_vtime();
108109
ZAbort::abort();
109110
ZStopConcurrentGCThreadClosure cl;
110111
gc_threads_do(&cl);
111112
}
112113

114+
class ZVCPUThreadClosure : public ThreadClosure {
115+
private:
116+
volatile jlong _vtime = 0;
117+
public:
118+
virtual void do_thread(Thread *thread) {
119+
if (thread->is_ConcurrentGC_thread() ||
120+
strstr(thread->name(), "ZWorker") != nullptr) {
121+
Atomic::add(&_vtime, os::thread_cpu_time(thread));
122+
}
123+
}
124+
jlong vtime() { return _vtime; };
125+
};
126+
127+
double ZCollectedHeap::elapsed_gc_vtime() {
128+
ZVCPUThreadClosure cl;
129+
gc_threads_do(&cl);
130+
return (double)(cl.vtime() + Universe::heap()->vm_vtime()) / NANOSECS_PER_SEC;
131+
}
132+
113133
size_t ZCollectedHeap::max_capacity() const {
114134
return _heap.max_capacity();
115135
}

src/hotspot/share/gc/z/zCollectedHeap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class ZCollectedHeap : public CollectedHeap {
9191
GrowableArray<GCMemoryManager*> memory_managers() override;
9292
GrowableArray<MemoryPool*> memory_pools() override;
9393

94+
double elapsed_gc_vtime() override;
95+
9496
void object_iterate(ObjectClosure* cl) override;
9597
ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers) override;
9698

src/hotspot/share/gc/z/zGeneration.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ class VM_ZOperation : public VM_Operation {
442442
OopMapCache::try_trigger_cleanup();
443443
}
444444

445+
bool operation_is_gc() const override { return true; }
446+
445447
bool success() const {
446448
return _success;
447449
}

src/hotspot/share/runtime/cpuTimeCounters.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,7 @@ void ThreadTotalCPUTimeClosure::do_thread(Thread* thread) {
126126
// must ensure the thread exists and has not terminated.
127127
_total += os::thread_cpu_time(thread);
128128
}
129+
130+
void ThreadTotalCPUTimeClosure::inc_total(jlong value) {
131+
_total += value;
132+
}

src/hotspot/share/runtime/cpuTimeCounters.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class ThreadTotalCPUTimeClosure: public ThreadClosure {
109109
~ThreadTotalCPUTimeClosure();
110110

111111
virtual void do_thread(Thread* thread);
112+
void inc_total(jlong value);
112113
};
113114

114115
#endif // SHARE_RUNTIME_CPUTIMECOUNTERS_HPP

src/hotspot/share/runtime/vmOperation.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ class VM_Operation : public StackObj {
168168
// or concurrently with Java threads running.
169169
virtual bool evaluate_at_safepoint() const { return true; }
170170

171+
virtual bool operation_is_gc() const { return false; }
172+
171173
// Debugging
172174
virtual void print_on_error(outputStream* st) const;
173175
virtual const char* name() const { return _names[type()]; }

src/hotspot/share/runtime/vmThread.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,18 @@ static void post_vm_operation_event(EventExecuteVMOperation* event, VM_Operation
271271

272272
void VMThread::evaluate_operation(VM_Operation* op) {
273273
ResourceMark rm;
274-
274+
const bool gcLogging = log_is_enabled(Info, gc) || log_is_enabled(Info, gc, cpu);
275+
jlong start = 0;
275276
{
276277
PerfTraceTime vm_op_timer(perf_accumulated_vm_operation_time());
277278
HOTSPOT_VMOPS_BEGIN(
278279
(char *) op->name(), strlen(op->name()),
279280
op->evaluate_at_safepoint() ? 0 : 1);
280281

281282
EventExecuteVMOperation event;
283+
if (gcLogging && os::is_thread_cpu_time_supported()) {
284+
start = os::thread_cpu_time(this);
285+
}
282286
op->evaluate();
283287
if (event.should_commit()) {
284288
post_vm_operation_event(&event, op);
@@ -289,11 +293,18 @@ void VMThread::evaluate_operation(VM_Operation* op) {
289293
op->evaluate_at_safepoint() ? 0 : 1);
290294
}
291295

292-
if (UsePerfData && os::is_thread_cpu_time_supported()) {
293-
assert(Thread::current() == this, "Must be called from VM thread");
294-
// Update vm_thread_cpu_time after each VM operation.
295-
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::vm);
296-
tttc.do_thread(this);
296+
if (os::is_thread_cpu_time_supported()) {
297+
jlong end = gcLogging || UsePerfData ? os::thread_cpu_time(this) : 0;
298+
if (gcLogging) {
299+
jlong duration = end > start ? end - start : 0;
300+
Universe::heap()->add_vm_vtime(duration);
301+
}
302+
if (UsePerfData) {
303+
assert(Thread::current() == this, "Must be called from VM thread");
304+
// Update vm_thread_cpu_time after each VM operation.
305+
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::vm);
306+
tttc.inc_total(end);
307+
}
297308
}
298309
}
299310

0 commit comments

Comments
 (0)