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 // _notifier and _should_notify form a single-reader / multi-writer
52 // notification mechanism. The thread is the single reader. The writers
53 // are (other) threads that call activate() on the thread.
54
55 void G1ConcurrentRefineThread::wait_for_completed_buffers() {
56 assert(this == Thread::current(), "precondition");
57 while (Atomic::load_acquire(&_should_notify)) {
58 _notifier->wait();
59 }
60 }
61
62 void G1ConcurrentRefineThread::activate() {
63 assert(this != Thread::current(), "precondition");
64 // Notify iff transitioning from needing activation to not. This helps
65 // keep the semaphore count bounded and minimizes the work done by
66 // activators when the thread is already active.
67 if (Atomic::load_acquire(&_should_notify) &&
68 Atomic::cmpxchg(&_should_notify, true, false)) {
69 _notifier->signal();
70 }
71 }
72
73 // Called when no refinement work found for this thread.
74 // Returns true if should deactivate.
75 bool G1ConcurrentRefineThread::maybe_deactivate(bool more_work) {
76 assert(this == Thread::current(), "precondition");
77
78 if (more_work) {
79 // Suppress unnecessary notifications.
80 Atomic::release_store(&_should_notify, false);
81 return false;
82 } else if (Atomic::load_acquire(&_should_notify)) {
83 // Deactivate if no notifications since enabled (see below).
84 return true;
85 } else {
86 // Try for more refinement work with notifications enabled, to close
87 // race; there could be a plethora of suppressed activation attempts
88 // after we found no work but before we enable notifications here
89 // (so there could be lots of work for this thread to do), followed
90 // by a long time without activation after enabling notifications.
91 // But first, clear any pending signals to prevent accumulation.
92 while (_notifier->trywait()) {}
93 Atomic::release_store(&_should_notify, true);
94 return false;
95 }
96 }
97
98 void G1ConcurrentRefineThread::run_service() {
99 _vtime_start = os::elapsedVTime();
100
101 while (!should_terminate()) {
102 // Wait for work
103 wait_for_completed_buffers();
104 if (should_terminate()) {
105 break;
106 }
107
108 log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
109 _worker_id, _cr->activation_threshold(_worker_id),
110 G1BarrierSet::dirty_card_queue_set().num_cards());
111
112 size_t start_total_refined_cards = _total_refined_cards; // For logging.
113
114 {
115 SuspendibleThreadSetJoiner sts_join;
116
117 while (!should_terminate()) {
118 if (sts_join.should_yield()) {
119 sts_join.yield();
120 continue; // Re-check for termination after yield delay.
121 }
122
123 Ticks start_time = Ticks::now();
124 bool more_work = _cr->do_refinement_step(_worker_id, &_total_refined_cards);
125 _total_refinement_time += (Ticks::now() - start_time);
126
127 if (maybe_deactivate(more_work)) break;
128 }
129 }
130
131 log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
132 ", current: " SIZE_FORMAT ", refined cards: "
133 SIZE_FORMAT ", total refined cards: " SIZE_FORMAT,
134 _worker_id, _cr->deactivation_threshold(_worker_id),
135 G1BarrierSet::dirty_card_queue_set().num_cards(),
136 _total_refined_cards - start_total_refined_cards,
137 _total_refined_cards);
138
139 if (os::supports_vtime()) {
140 _vtime_accum = (os::elapsedVTime() - _vtime_start);
141 } else {
142 _vtime_accum = 0.0;
143 }
144 }
145
146 log_debug(gc, refine)("Stopping %d", _worker_id);
147 }
148
149 void G1ConcurrentRefineThread::stop_service() {
150 activate();
151 }
|