1 /*
2 * Copyright (c) 2001, 2019, 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 "precompiled.hpp"
26 #include "gc/g1/g1BarrierSet.hpp"
27 #include "gc/g1/g1ConcurrentRefine.hpp"
28 #include "gc/g1/g1ConcurrentRefineThread.hpp"
29 #include "gc/g1/g1DirtyCardQueue.hpp"
30 #include "gc/shared/suspendibleThreadSet.hpp"
31 #include "logging/log.hpp"
32 #include "memory/resourceArea.hpp"
33 #include "runtime/handles.inline.hpp"
34 #include "runtime/mutexLocker.hpp"
35
36 G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
37 ConcurrentGCThread(),
38 _vtime_start(0.0),
39 _vtime_accum(0.0),
40 _total_refinement_time(),
41 _total_refined_cards(0),
42 _worker_id(worker_id),
43 _active(false),
44 _monitor(NULL),
45 _cr(cr)
46 {
47 // Each thread has its own monitor. The i-th thread is responsible for signaling
48 // to thread i+1 if the number of buffers in the queue exceeds a threshold for this
49 // thread. Monitors are also used to wake up the threads during termination.
50 // The 0th (primary) worker is notified by mutator threads and has a special monitor.
51 if (!is_primary()) {
52 _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true,
53 Monitor::_safepoint_check_never);
54 } else {
55 _monitor = DirtyCardQ_CBL_mon;
56 }
57
58 // set name
59 set_name("G1 Refine#%d", worker_id);
60 create_and_start();
61 }
62
63 void G1ConcurrentRefineThread::wait_for_completed_buffers() {
64 MonitorLocker ml(_monitor, Mutex::_no_safepoint_check_flag);
65 while (!should_terminate() && !is_active()) {
66 ml.wait();
67 }
68 }
69
70 bool G1ConcurrentRefineThread::is_active() {
71 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
72 return is_primary() ? dcqs.process_completed_buffers() : _active;
73 }
74
75 void G1ConcurrentRefineThread::activate() {
76 MutexLocker x(_monitor, Mutex::_no_safepoint_check_flag);
77 if (!is_primary()) {
78 set_active(true);
79 } else {
80 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
81 dcqs.set_process_completed_buffers(true);
82 }
83 _monitor->notify();
84 }
85
86 void G1ConcurrentRefineThread::deactivate() {
87 MutexLocker x(_monitor, Mutex::_no_safepoint_check_flag);
88 if (!is_primary()) {
89 set_active(false);
90 } else {
91 G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
92 dcqs.set_process_completed_buffers(false);
93 }
94 }
95
96 void G1ConcurrentRefineThread::run_service() {
97 _vtime_start = os::elapsedVTime();
98
99 while (!should_terminate()) {
100 // Wait for work
101 wait_for_completed_buffers();
102 if (should_terminate()) {
103 break;
104 }
105
106 log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
107 _worker_id, _cr->activation_threshold(_worker_id),
108 G1BarrierSet::dirty_card_queue_set().num_cards());
109
110 size_t start_total_refined_cards = _total_refined_cards; // For logging.
111
112 {
113 SuspendibleThreadSetJoiner sts_join;
114
115 while (!should_terminate()) {
116 if (sts_join.should_yield()) {
117 sts_join.yield();
118 continue; // Re-check for termination after yield delay.
119 }
120
121 Ticks start_time = Ticks::now();
122 if (!_cr->do_refinement_step(_worker_id, &_total_refined_cards)) {
123 break; // No cards to process.
124 }
125 _total_refinement_time += (Ticks::now() - start_time);
126 }
127 }
128
129 deactivate();
130 log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
131 ", current: " SIZE_FORMAT ", refined cards: "
132 SIZE_FORMAT ", total refined cards: " SIZE_FORMAT,
133 _worker_id, _cr->deactivation_threshold(_worker_id),
134 G1BarrierSet::dirty_card_queue_set().num_cards(),
135 _total_refined_cards - start_total_refined_cards,
136 _total_refined_cards);
137
138 if (os::supports_vtime()) {
139 _vtime_accum = (os::elapsedVTime() - _vtime_start);
140 } else {
141 _vtime_accum = 0.0;
142 }
143 }
144
145 log_debug(gc, refine)("Stopping %d", _worker_id);
146 }
147
148 void G1ConcurrentRefineThread::stop_service() {
149 MutexLocker x(_monitor, Mutex::_no_safepoint_check_flag);
150 _monitor->notify();
151 }
|
1 /*
2 * Copyright (c) 2001, 2020, 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 "precompiled.hpp"
26 #include "gc/g1/g1BarrierSet.hpp"
27 #include "gc/g1/g1ConcurrentRefine.hpp"
28 #include "gc/g1/g1ConcurrentRefineThread.hpp"
29 #include "gc/g1/g1DirtyCardQueue.hpp"
30 #include "gc/shared/suspendibleThreadSet.hpp"
31 #include "logging/log.hpp"
32 #include "runtime/atomic.hpp"
33 #include "runtime/thread.hpp"
34
35 G1ConcurrentRefineThread::G1ConcurrentRefineThread(G1ConcurrentRefine* cr, uint worker_id) :
36 ConcurrentGCThread(),
37 _vtime_start(0.0),
38 _vtime_accum(0.0),
39 _total_refinement_time(),
40 _total_refined_cards(0),
41 _worker_id(worker_id),
42 _notifier(new Semaphore(0)),
43 _should_notify(true),
44 _cr(cr)
45 {
46 // set name
47 set_name("G1 Refine#%d", worker_id);
48 create_and_start();
49 }
50
51 void G1ConcurrentRefineThread::wait_for_completed_buffers() {
52 assert(this == Thread::current(), "precondition");
53 while (Atomic::load_acquire(&_should_notify)) {
54 _notifier->wait();
55 }
56 }
57
58 void G1ConcurrentRefineThread::activate() {
59 assert(this != Thread::current(), "precondition");
60 // Notify iff transitioning from needing activation to not. This helps
61 // keep the semaphore count bounded and minimizes the work done by
62 // activators when the thread is already active.
63 if (Atomic::load_acquire(&_should_notify) &&
64 Atomic::cmpxchg(&_should_notify, true, false)) {
65 _notifier->signal();
66 }
67 }
68
69 bool G1ConcurrentRefineThread::maybe_deactivate(bool more_work) {
70 assert(this == Thread::current(), "precondition");
71
72 if (more_work) {
73 // Suppress unnecessary notifications.
74 Atomic::release_store(&_should_notify, false);
75 return false;
76 } else if (Atomic::load_acquire(&_should_notify)) {
77 // Deactivate if no notifications since enabled (see below).
78 return true;
79 } else {
80 // Try for more refinement work with notifications enabled, to close
81 // race; there could be a plethora of suppressed activation attempts
82 // after we found no work but before we enable notifications here
83 // (so there could be lots of work for this thread to do), followed
84 // by a long time without activation after enabling notifications.
85 // But first, clear any pending signals to prevent accumulation.
86 while (_notifier->trywait()) {}
87 Atomic::release_store(&_should_notify, true);
88 return false;
89 }
90 }
91
92 void G1ConcurrentRefineThread::run_service() {
93 _vtime_start = os::elapsedVTime();
94
95 while (!should_terminate()) {
96 // Wait for work
97 wait_for_completed_buffers();
98 if (should_terminate()) {
99 break;
100 }
101
102 log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
103 _worker_id, _cr->activation_threshold(_worker_id),
104 G1BarrierSet::dirty_card_queue_set().num_cards());
105
106 size_t start_total_refined_cards = _total_refined_cards; // For logging.
107
108 {
109 SuspendibleThreadSetJoiner sts_join;
110
111 while (!should_terminate()) {
112 if (sts_join.should_yield()) {
113 sts_join.yield();
114 continue; // Re-check for termination after yield delay.
115 }
116
117 Ticks start_time = Ticks::now();
118 bool more_work = _cr->do_refinement_step(_worker_id, &_total_refined_cards);
119 _total_refinement_time += (Ticks::now() - start_time);
120
121 if (maybe_deactivate(more_work)) break;
122 }
123 }
124
125 log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
126 ", current: " SIZE_FORMAT ", refined cards: "
127 SIZE_FORMAT ", total refined cards: " SIZE_FORMAT,
128 _worker_id, _cr->deactivation_threshold(_worker_id),
129 G1BarrierSet::dirty_card_queue_set().num_cards(),
130 _total_refined_cards - start_total_refined_cards,
131 _total_refined_cards);
132
133 if (os::supports_vtime()) {
134 _vtime_accum = (os::elapsedVTime() - _vtime_start);
135 } else {
136 _vtime_accum = 0.0;
137 }
138 }
139
140 log_debug(gc, refine)("Stopping %d", _worker_id);
141 }
142
143 void G1ConcurrentRefineThread::stop_service() {
144 activate();
145 }
|