8274051: Remove supports_vtime()/elapsedVTime()

Reviewed-by: kbarrett, iwalulya
This commit is contained in:
Thomas Schatzl 2025-06-30 11:22:46 +00:00
parent c2d76f9844
commit 00adbbe553
19 changed files with 122 additions and 192 deletions

View File

@ -879,17 +879,6 @@ void os::free_thread(OSThread* osthread) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
struct rusage usage;
int retval = getrusage(RUSAGE_THREAD, &usage);
if (retval == 0) {
return usage.ru_utime.tv_sec + usage.ru_stime.tv_sec + (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000.0 * 1000);
} else {
// better than nothing, but not much
return elapsedTime();
}
}
// We use mread_real_time here.
// On AIX: If the CPU has a time register, the result will be RTC_POWER and
// it has to be converted to real time. AIX documentations suggests to do

View File

@ -782,10 +782,6 @@ void os::free_thread(OSThread* osthread) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
// better than nothing, but not much
return elapsedTime();
}
#ifdef __APPLE__
void os::Bsd::clock_init() {

View File

@ -1487,16 +1487,6 @@ void os::Linux::capture_initial_stack(size_t max_size) {
////////////////////////////////////////////////////////////////////////////////
// time support
double os::elapsedVTime() {
struct rusage usage;
int retval = getrusage(RUSAGE_THREAD, &usage);
if (retval == 0) {
return (double) (usage.ru_utime.tv_sec + usage.ru_stime.tv_sec) + (double) (usage.ru_utime.tv_usec + usage.ru_stime.tv_usec) / (1000 * 1000);
} else {
// better than nothing, but not much
return elapsedTime();
}
}
void os::Linux::fast_thread_clock_init() {
clockid_t clockid;

View File

@ -1599,8 +1599,6 @@ jlong os::elapsed_frequency() {
return NANOSECS_PER_SEC; // nanosecond resolution
}
bool os::supports_vtime() { return true; }
// Return the real, user, and system times in seconds from an
// arbitrary fixed point in the past.
bool os::getTimesSecs(double* process_real_time,

View File

@ -1194,21 +1194,6 @@ FILETIME java_to_windows_time(jlong l) {
return result;
}
bool os::supports_vtime() { return true; }
double os::elapsedVTime() {
FILETIME created;
FILETIME exited;
FILETIME kernel;
FILETIME user;
if (GetThreadTimes(GetCurrentThread(), &created, &exited, &kernel, &user) != 0) {
// the resolution of windows_to_java_time() should be sufficient (ms)
return (double) (windows_to_java_time(kernel) + windows_to_java_time(user)) / MILLIUNITS;
} else {
return elapsedTime();
}
}
jlong os::javaTimeMillis() {
FILETIME wt;
GetSystemTimeAsFileTime(&wt);

View File

@ -1269,6 +1269,9 @@ jint G1CollectedHeap::initialize_service_thread() {
jint G1CollectedHeap::initialize() {
if (!os::is_thread_cpu_time_supported()) {
vm_exit_during_initialization("G1 requires cpu time gathering support");
}
// Necessary to satisfy locking discipline assertions.
MutexLocker x(Heap_lock);
@ -2234,7 +2237,7 @@ void G1CollectedHeap::gc_epilogue(bool full) {
_free_arena_memory_task->notify_new_stats(&_young_gen_card_set_stats,
&_collection_set_candidates_card_set_stats);
update_parallel_gc_threads_cpu_time();
update_perf_counter_cpu_time();
}
uint G1CollectedHeap::uncommit_regions(uint region_limit) {
@ -2318,10 +2321,10 @@ void G1CollectedHeap::verify_region_attr_remset_is_tracked() {
}
#endif
void G1CollectedHeap::update_parallel_gc_threads_cpu_time() {
void G1CollectedHeap::update_perf_counter_cpu_time() {
assert(Thread::current()->is_VM_thread(),
"Must be called from VM thread to avoid races");
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
if (!UsePerfData) {
return;
}

View File

@ -262,7 +262,7 @@ public:
void set_collection_set_candidates_stats(G1MonotonicArenaMemoryStats& stats);
void set_young_gen_card_set_stats(const G1MonotonicArenaMemoryStats& stats);
void update_parallel_gc_threads_cpu_time();
void update_perf_counter_cpu_time();
private:
// Return true if an explicit GC should start a concurrent cycle instead

View File

@ -71,6 +71,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
#include "runtime/prefetch.inline.hpp"
#include "runtime/threads.hpp"
#include "utilities/align.hpp"
@ -507,8 +508,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
_remark_weak_ref_times(),
_cleanup_times(),
_accum_task_vtime(nullptr),
_concurrent_workers(nullptr),
_num_concurrent_workers(0),
_max_concurrent_workers(0),
@ -542,7 +541,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
}
_tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_num_tasks, mtGC);
_accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_num_tasks, mtGC);
// so that the assertion in MarkingTaskQueue::task_queue doesn't fail
_num_active_tasks = _max_num_tasks;
@ -552,8 +550,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
_task_queues->register_queue(i, task_queue);
_tasks[i] = new G1CMTask(i, this, task_queue, _region_mark_stats);
_accum_task_vtime[i] = 0.0;
}
reset_at_marking_complete();
@ -980,30 +976,23 @@ public:
void work(uint worker_id) {
ResourceMark rm;
double start_vtime = os::elapsedVTime();
SuspendibleThreadSetJoiner sts_join;
{
SuspendibleThreadSetJoiner sts_join;
assert(worker_id < _cm->active_tasks(), "invariant");
assert(worker_id < _cm->active_tasks(), "invariant");
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
if (!_cm->has_aborted()) {
do {
task->do_marking_step(G1ConcMarkStepDurationMillis,
true /* do_termination */,
false /* is_serial*/);
G1CMTask* task = _cm->task(worker_id);
task->record_start_time();
if (!_cm->has_aborted()) {
do {
task->do_marking_step(G1ConcMarkStepDurationMillis,
true /* do_termination */,
false /* is_serial*/);
_cm->do_yield_check();
} while (!_cm->has_aborted() && task->has_aborted());
}
task->record_end_time();
guarantee(!task->has_aborted() || _cm->has_aborted(), "invariant");
_cm->do_yield_check();
} while (!_cm->has_aborted() && task->has_aborted());
}
double end_vtime = os::elapsedVTime();
_cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);
task->record_end_time();
guarantee(!task->has_aborted() || _cm->has_aborted(), "invariant");
}
G1CMConcurrentMarkingTask(G1ConcurrentMark* cm) :
@ -1496,7 +1485,7 @@ void G1ConcurrentMark::remark() {
_remark_weak_ref_times.add((now - mark_work_end) * 1000.0);
_remark_times.add((now - start) * 1000.0);
_g1h->update_parallel_gc_threads_cpu_time();
_g1h->update_perf_counter_cpu_time();
policy->record_concurrent_mark_remark_end();
}
@ -2090,6 +2079,23 @@ void G1ConcurrentMark::abort_marking_threads() {
_second_overflow_barrier_sync.abort();
}
double G1ConcurrentMark::worker_threads_cpu_time_s() {
class CountCpuTimeThreadClosure : public ThreadClosure {
public:
jlong _total_cpu_time;
CountCpuTimeThreadClosure() : ThreadClosure(), _total_cpu_time(0) { }
void do_thread(Thread* t) {
_total_cpu_time += os::thread_cpu_time(t);
}
} cl;
threads_do(&cl);
return (double)cl._total_cpu_time / NANOSECS_PER_SEC;
}
static void print_ms_time_info(const char* prefix, const char* name,
NumberSeq& ns) {
log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
@ -2119,7 +2125,7 @@ void G1ConcurrentMark::print_summary_info() {
log.trace(" Total stop_world time = %8.2f s.",
(_remark_times.sum() + _cleanup_times.sum())/1000.0);
log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
cm_thread()->vtime_accum(), cm_thread()->vtime_mark_accum());
cm_thread()->total_mark_cpu_time_s(), cm_thread()->worker_threads_cpu_time_s());
}
void G1ConcurrentMark::threads_do(ThreadClosure* tc) const {
@ -2263,8 +2269,6 @@ bool G1CMTask::regular_clock_call() {
return false;
}
double curr_time_ms = os::elapsedVTime() * 1000.0;
// (4) We check whether we should yield. If we have to, then we abort.
if (SuspendibleThreadSet::should_yield()) {
// We should yield. To do this we abort the task. The caller is
@ -2274,7 +2278,7 @@ bool G1CMTask::regular_clock_call() {
// (5) We check whether we've reached our time quota. If we have,
// then we abort.
double elapsed_time_ms = curr_time_ms - _start_time_ms;
double elapsed_time_ms = (double)(os::current_thread_cpu_time() - _start_cpu_time_ns) / NANOSECS_PER_MILLISEC;
if (elapsed_time_ms > _time_target_ms) {
_has_timed_out = true;
return false;
@ -2789,9 +2793,9 @@ void G1CMTask::handle_abort(bool is_serial, double elapsed_time_ms) {
phase has visited reach a given limit. Additional invocations to
the method clock have been planted in a few other strategic places
too. The initial reason for the clock method was to avoid calling
vtime too regularly, as it is quite expensive. So, once it was in
place, it was natural to piggy-back all the other conditions on it
too and not constantly check them throughout the code.
cpu time gathering too regularly, as it is quite expensive. So,
once it was in place, it was natural to piggy-back all the other
conditions on it too and not constantly check them throughout the code.
If do_termination is true then do_marking_step will enter its
termination protocol.
@ -2814,7 +2818,7 @@ void G1CMTask::do_marking_step(double time_target_ms,
bool is_serial) {
assert(time_target_ms >= 1.0, "minimum granularity is 1ms");
_start_time_ms = os::elapsedVTime() * 1000.0;
_start_cpu_time_ns = os::current_thread_cpu_time();
// If do_stealing is true then do_marking_step will attempt to
// steal work from the other G1CMTasks. It only makes sense to
@ -2908,8 +2912,8 @@ void G1CMTask::do_marking_step(double time_target_ms,
// closure which was statically allocated in this frame doesn't
// escape it by accident.
set_cm_oop_closure(nullptr);
double end_time_ms = os::elapsedVTime() * 1000.0;
double elapsed_time_ms = end_time_ms - _start_time_ms;
jlong end_cpu_time_ns = os::current_thread_cpu_time();
double elapsed_time_ms = (double)(end_cpu_time_ns - _start_cpu_time_ns) / NANOSECS_PER_MILLISEC;
// Update the step history.
_step_times_ms.add(elapsed_time_ms);
@ -2932,7 +2936,7 @@ G1CMTask::G1CMTask(uint worker_id,
_mark_stats_cache(mark_stats, G1RegionMarkStatsCache::RegionMarkStatsCacheSize),
_calls(0),
_time_target_ms(0.0),
_start_time_ms(0.0),
_start_cpu_time_ns(0),
_cm_oop_closure(nullptr),
_curr_region(nullptr),
_finger(nullptr),

View File

@ -446,8 +446,6 @@ class G1ConcurrentMark : public CHeapObj<mtGC> {
NumberSeq _remark_weak_ref_times;
NumberSeq _cleanup_times;
double* _accum_task_vtime; // Accumulated task vtime
WorkerThreads* _concurrent_workers;
uint _num_concurrent_workers; // The number of marking worker threads we're using
uint _max_concurrent_workers; // Maximum number of marking worker threads
@ -612,16 +610,8 @@ public:
// running.
void abort_marking_threads();
void update_accum_task_vtime(uint i, double vtime) {
_accum_task_vtime[i] += vtime;
}
double all_task_accum_vtime() {
double ret = 0.0;
for (uint i = 0; i < _max_num_tasks; ++i)
ret += _accum_task_vtime[i];
return ret;
}
// Total cpu time spent in mark worker threads in seconds.
double worker_threads_cpu_time_s();
// Attempts to steal an object from the task queues of other tasks
bool try_stealing(uint worker_id, G1TaskQueueEntry& task_entry);
@ -753,8 +743,8 @@ private:
// When the virtual timer reaches this time, the marking step should exit
double _time_target_ms;
// Start time of the current marking step
double _start_time_ms;
// Start cpu time of the current marking step
jlong _start_cpu_time_ns;
// Oop closure used for iterations over oops
G1CMOopClosure* _cm_oop_closure;

View File

@ -47,8 +47,6 @@
G1ConcurrentMarkThread::G1ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_vtime_start(0.0),
_vtime_accum(0.0),
_cm(cm),
_state(Idle)
{
@ -113,8 +111,6 @@ class G1ConcPhaseTimer : public GCTraceConcTimeImpl<LogLevel::Info, LOG_TAGS(gc,
};
void G1ConcurrentMarkThread::run_service() {
_vtime_start = os::elapsedVTime();
while (wait_for_next_cycle()) {
assert(in_progress(), "must be");
@ -133,9 +129,7 @@ void G1ConcurrentMarkThread::run_service() {
concurrent_cycle_end(_state == FullMark && !_cm->has_aborted());
_vtime_accum = (os::elapsedVTime() - _vtime_start);
update_threads_cpu_time();
update_perf_counter_cpu_time();
}
_cm->root_regions()->cancel_scan();
}
@ -171,7 +165,7 @@ bool G1ConcurrentMarkThread::phase_clear_cld_claimed_marks() {
bool G1ConcurrentMarkThread::phase_scan_root_regions() {
G1ConcPhaseTimer p(_cm, "Concurrent Scan Root Regions");
_cm->scan_root_regions();
update_threads_cpu_time();
update_perf_counter_cpu_time();
return _cm->has_aborted();
}
@ -231,7 +225,7 @@ bool G1ConcurrentMarkThread::subphase_delay_to_keep_mmu_before_remark() {
bool G1ConcurrentMarkThread::subphase_remark() {
ConcurrentGCBreakpoints::at("BEFORE MARKING COMPLETED");
update_threads_cpu_time();
update_perf_counter_cpu_time();
VM_G1PauseRemark op;
VMThread::execute(&op);
return _cm->has_aborted();
@ -241,7 +235,7 @@ bool G1ConcurrentMarkThread::phase_rebuild_and_scrub() {
ConcurrentGCBreakpoints::at("AFTER REBUILD STARTED");
G1ConcPhaseTimer p(_cm, "Concurrent Rebuild Remembered Sets and Scrub Regions");
_cm->rebuild_and_scrub();
update_threads_cpu_time();
update_perf_counter_cpu_time();
return _cm->has_aborted();
}
@ -342,8 +336,8 @@ void G1ConcurrentMarkThread::concurrent_cycle_end(bool mark_cycle_completed) {
ConcurrentGCBreakpoints::notify_active_to_idle();
}
void G1ConcurrentMarkThread::update_threads_cpu_time() {
if (!UsePerfData || !os::is_thread_cpu_time_supported()) {
void G1ConcurrentMarkThread::update_perf_counter_cpu_time() {
if (!UsePerfData) {
return;
}
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_mark);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,9 +35,6 @@ class G1Policy;
class G1ConcurrentMarkThread: public ConcurrentGCThread {
friend class VMStructs;
double _vtime_start; // Initial virtual time.
double _vtime_accum; // Accumulated virtual time.
G1ConcurrentMark* _cm;
enum ServiceState : uint {
@ -88,10 +85,11 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread {
// Constructor
G1ConcurrentMarkThread(G1ConcurrentMark* cm);
// Total virtual time so far for this thread and concurrent marking tasks.
double vtime_accum();
// Marking virtual time so far this thread and concurrent marking tasks.
double vtime_mark_accum();
// Total cpu time used by all marking related threads (i.e. this thread and the
// marking worker threads) in seconds.
double total_mark_cpu_time_s();
// Cpu time used by all marking worker threads in seconds.
double worker_threads_cpu_time_s();
G1ConcurrentMark* cm() { return _cm; }
@ -110,7 +108,7 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread {
bool in_undo_mark() const;
// Update the perf data counter for concurrent mark.
void update_threads_cpu_time();
void update_perf_counter_cpu_time();
};
#endif // SHARE_GC_G1_G1CONCURRENTMARKTHREAD_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,15 +28,16 @@
#include "gc/g1/g1ConcurrentMarkThread.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
#include "runtime/os.hpp"
// Total virtual time so far.
inline double G1ConcurrentMarkThread::vtime_accum() {
return _vtime_accum + _cm->all_task_accum_vtime();
inline double G1ConcurrentMarkThread::total_mark_cpu_time_s() {
return os::thread_cpu_time(this) + worker_threads_cpu_time_s();
}
// Marking virtual time so far
inline double G1ConcurrentMarkThread::vtime_mark_accum() {
return _cm->all_task_accum_vtime();
inline double G1ConcurrentMarkThread::worker_threads_cpu_time_s() {
return _cm->worker_threads_cpu_time_s();
}
inline void G1ConcurrentMarkThread::set_idle() {

View File

@ -40,8 +40,6 @@
G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
ConcurrentGCThread(),
_vtime_start(0.0),
_vtime_accum(0.0),
_notifier(Mutex::nosafepoint, FormatBuffer<>("G1 Refine#%d", worker_id), true),
_requested_active(false),
_refinement_stats(),
@ -53,8 +51,6 @@ G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint
}
void G1ConcurrentRefineThread::run_service() {
_vtime_start = os::elapsedVTime();
while (wait_for_completed_buffers()) {
SuspendibleThreadSetJoiner sts_join;
G1ConcurrentRefineStats active_stats_start = _refinement_stats;
@ -74,7 +70,7 @@ void G1ConcurrentRefineThread::run_service() {
}
}
report_inactive("Deactivated", _refinement_stats - active_stats_start);
track_usage();
update_perf_counter_cpu_time();
}
log_debug(gc, refine)("Stopping %d", _worker_id);
@ -128,12 +124,17 @@ void G1ConcurrentRefineThread::stop_service() {
activate();
}
jlong G1ConcurrentRefineThread::cpu_time() {
return os::thread_cpu_time(this);
}
// The (single) primary thread drives the controller for the refinement threads.
class G1PrimaryConcurrentRefineThread final : public G1ConcurrentRefineThread {
bool wait_for_completed_buffers() override;
bool maybe_deactivate() override;
void do_refinement_step() override;
void track_usage() override;
// Updates jstat cpu usage for all refinement threads.
void update_perf_counter_cpu_time() override;
public:
G1PrimaryConcurrentRefineThread(G1ConcurrentRefine* cr) :
@ -179,10 +180,8 @@ void G1PrimaryConcurrentRefineThread::do_refinement_step() {
}
}
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()) {
void G1PrimaryConcurrentRefineThread::update_perf_counter_cpu_time() {
if (UsePerfData) {
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_conc_refine);
cr()->threads_do(&tttc);
}
@ -191,6 +190,7 @@ void G1PrimaryConcurrentRefineThread::track_usage() {
class G1SecondaryConcurrentRefineThread final : public G1ConcurrentRefineThread {
bool wait_for_completed_buffers() override;
void do_refinement_step() override;
void update_perf_counter_cpu_time() override { /* Nothing to do. The primary thread does all the work. */ }
public:
G1SecondaryConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,9 +39,6 @@ class G1ConcurrentRefineThread: public ConcurrentGCThread {
friend class VMStructs;
friend class G1CollectedHeap;
double _vtime_start; // Initial virtual time.
double _vtime_accum; // Accumulated virtual time.
Monitor _notifier;
bool _requested_active;
@ -71,15 +68,8 @@ protected:
// precondition: this is the current thread.
virtual void do_refinement_step() = 0;
// Update concurrent refine threads stats.
// If we are in Primary thread, we additionally update CPU time tracking.
virtual void track_usage() {
if (os::supports_vtime()) {
_vtime_accum = (os::elapsedVTime() - _vtime_start);
} else {
_vtime_accum = 0.0;
}
};
// Update concurrent refine threads cpu time stats.
virtual void update_perf_counter_cpu_time() = 0;
// Helper for do_refinement_step implementations. Try to perform some
// refinement work, limited by stop_at. Returns true if any refinement work
@ -113,8 +103,8 @@ public:
return &_refinement_stats;
}
// Total virtual time so far.
double vtime_accum() { return _vtime_accum; }
// Total cpu time spent in this thread so far.
jlong cpu_time();
};
#endif // SHARE_GC_G1_G1CONCURRENTREFINETHREAD_HPP

View File

@ -44,7 +44,7 @@ void G1RemSetSummary::update() {
CollectData(G1RemSetSummary * summary) : _summary(summary), _counter(0) {}
virtual void do_thread(Thread* t) {
G1ConcurrentRefineThread* crt = static_cast<G1ConcurrentRefineThread*>(t);
_summary->set_rs_thread_vtime(_counter, crt->vtime_accum());
_summary->set_refine_thread_cpu_time(_counter, crt->cpu_time());
_counter++;
}
} collector(this);
@ -53,23 +53,23 @@ void G1RemSetSummary::update() {
g1h->concurrent_refine()->threads_do(&collector);
}
void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) {
assert(_rs_threads_vtimes != nullptr, "just checking");
assert(thread < _num_vtimes, "just checking");
_rs_threads_vtimes[thread] = value;
void G1RemSetSummary::set_refine_thread_cpu_time(uint thread, jlong value) {
assert(_refine_threads_cpu_times != nullptr, "just checking");
assert(thread < _num_refine_threads, "just checking");
_refine_threads_cpu_times[thread] = value;
}
double G1RemSetSummary::rs_thread_vtime(uint thread) const {
assert(_rs_threads_vtimes != nullptr, "just checking");
assert(thread < _num_vtimes, "just checking");
return _rs_threads_vtimes[thread];
jlong G1RemSetSummary::refine_thread_cpu_time(uint thread) const {
assert(_refine_threads_cpu_times != nullptr, "just checking");
assert(thread < _num_refine_threads, "just checking");
return _refine_threads_cpu_times[thread];
}
G1RemSetSummary::G1RemSetSummary(bool should_update) :
_num_vtimes(G1ConcRefinementThreads),
_rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)) {
_num_refine_threads(G1ConcRefinementThreads),
_refine_threads_cpu_times(NEW_C_HEAP_ARRAY(jlong, _num_refine_threads, mtGC)) {
memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes);
memset(_refine_threads_cpu_times, 0, sizeof(jlong) * _num_refine_threads);
if (should_update) {
update();
@ -77,22 +77,22 @@ G1RemSetSummary::G1RemSetSummary(bool should_update) :
}
G1RemSetSummary::~G1RemSetSummary() {
FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes);
FREE_C_HEAP_ARRAY(jlong, _refine_threads_cpu_times);
}
void G1RemSetSummary::set(G1RemSetSummary* other) {
assert(other != nullptr, "just checking");
assert(_num_vtimes == other->_num_vtimes, "just checking");
assert(_num_refine_threads == other->_num_refine_threads, "just checking");
memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes);
memcpy(_refine_threads_cpu_times, other->_refine_threads_cpu_times, sizeof(jlong) * _num_refine_threads);
}
void G1RemSetSummary::subtract_from(G1RemSetSummary* other) {
assert(other != nullptr, "just checking");
assert(_num_vtimes == other->_num_vtimes, "just checking");
assert(_num_refine_threads == other->_num_refine_threads, "just checking");
for (uint i = 0; i < _num_vtimes; i++) {
set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i));
for (uint i = 0; i < _num_refine_threads; i++) {
set_refine_thread_cpu_time(i, other->refine_thread_cpu_time(i) - refine_thread_cpu_time(i));
}
}
@ -383,8 +383,8 @@ void G1RemSetSummary::print_on(outputStream* out, bool show_thread_times) {
if (show_thread_times) {
out->print_cr(" Concurrent refinement threads times (s)");
out->print(" ");
for (uint i = 0; i < _num_vtimes; i++) {
out->print(" %5.2f", rs_thread_vtime(i));
for (uint i = 0; i < _num_refine_threads; i++) {
out->print(" %5.2f", (double)refine_thread_cpu_time(i) / NANOSECS_PER_SEC);
}
out->cr();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -31,15 +31,14 @@
class G1RemSet;
// A G1RemSetSummary manages statistical information about the G1RemSet
// A G1RemSetSummary manages statistical information about the remembered set.
class G1RemSetSummary {
size_t _num_vtimes;
double* _rs_threads_vtimes;
size_t _num_refine_threads;
jlong* _refine_threads_cpu_times;
void set_rs_thread_vtime(uint thread, double value);
void set_refine_thread_cpu_time(uint thread, jlong value);
// update this summary with current data from various places
// Update this summary with current data from various places.
void update();
public:
@ -47,14 +46,14 @@ public:
~G1RemSetSummary();
// set the counters in this summary to the values of the others
// Set the counters in this summary to the values of the others.
void set(G1RemSetSummary* other);
// subtract all counters from the other summary, and set them in the current
// Subtract all counters from the other summary, and set them in the current.
void subtract_from(G1RemSetSummary* other);
void print_on(outputStream* out, bool show_thread_times);
double rs_thread_vtime(uint thread) const;
jlong refine_thread_cpu_time(uint thread) const;
};
#endif // SHARE_GC_G1_G1REMSETSUMMARY_HPP

View File

@ -119,7 +119,7 @@ G1ServiceTask* G1ServiceThread::wait_for_task() {
void G1ServiceThread::run_task(G1ServiceTask* task) {
jlong start = os::elapsed_counter();
double vstart = os::elapsedVTime();
jlong start_cpu_time_ns = os::thread_cpu_time(this);
assert(task->time() <= start,
"task run early: " JLONG_FORMAT " > " JLONG_FORMAT,
@ -130,12 +130,12 @@ void G1ServiceThread::run_task(G1ServiceTask* task) {
task->execute();
update_thread_cpu_time();
update_perf_counter_cpu_time();
log_debug(gc, task)("G1 Service Thread (%s) (run: %1.3fms) (cpu: %1.3fms)",
task->name(),
TimeHelper::counter_to_millis(os::elapsed_counter() - start),
(os::elapsedVTime() - vstart) * MILLIUNITS);
(double)(os::thread_cpu_time(this) - start_cpu_time_ns) / NANOSECS_PER_MILLISEC);
}
void G1ServiceThread::run_service() {
@ -153,8 +153,8 @@ void G1ServiceThread::stop_service() {
ml.notify();
}
void G1ServiceThread::update_thread_cpu_time() {
if (UsePerfData && os::is_thread_cpu_time_supported()) {
void G1ServiceThread::update_perf_counter_cpu_time() {
if (UsePerfData) {
ThreadTotalCPUTimeClosure tttc(CPUTimeGroups::CPUTimeType::gc_service);
tttc.do_thread(this);
}

View File

@ -121,7 +121,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();
void update_perf_counter_cpu_time();
public:
G1ServiceThread();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -293,13 +293,6 @@ class os: AllStatic {
static jlong elapsed_counter();
static jlong elapsed_frequency();
// The "virtual time" of a thread is the amount of time a thread has
// actually run. The first function indicates whether the OS supports
// this functionality for the current thread, and if so the second
// returns the elapsed virtual time for the current thread.
static bool supports_vtime();
static double elapsedVTime();
// Return current local time in a string (YYYY-MM-DD HH:MM:SS).
// It is MT safe, but not async-safe, as reading time zone
// information may require a lock on some platforms.