mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-04 05:00:31 +00:00
8274051: Remove supports_vtime()/elapsedVTime()
Reviewed-by: kbarrett, iwalulya
This commit is contained in:
parent
c2d76f9844
commit
00adbbe553
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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) :
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user