1 /*
2 * Copyright (c) 2016, Red Hat, Inc. and/or its affiliates.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24 #include "precompiled.hpp"
25
26 #include "gc_implementation/shenandoah/shenandoahHeap.hpp"
27 #include "gc_implementation/shenandoah/shenandoahLogging.hpp"
28 #include "gc_implementation/shenandoah/shenandoahTaskqueue.hpp"
29
30 void ShenandoahObjToScanQueueSet::clear() {
31 uint size = GenericTaskQueueSet<ShenandoahObjToScanQueue, mtGC>::size();
32 for (uint index = 0; index < size; index ++) {
33 ShenandoahObjToScanQueue* q = queue(index);
34 assert(q != NULL, "Sanity");
35 q->set_empty();
36 q->overflow_stack()->clear();
37 q->clear_buffer();
38 }
39 }
40
41
42 bool ShenandoahObjToScanQueueSet::is_empty() {
43 uint size = GenericTaskQueueSet<ShenandoahObjToScanQueue, mtGC>::size();
44 for (uint index = 0; index < size; index ++) {
45 ShenandoahObjToScanQueue* q = queue(index);
46 assert(q != NULL, "Sanity");
47 if (!q->is_empty()) {
48 return false;
49 }
50 }
51 return true;
52 }
53
54 bool ShenandoahTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
55 assert(_n_threads > 0, "Initialization is incorrect");
56 assert(_offered_termination < _n_threads, "Invariant");
57 assert(_blocker != NULL, "Invariant");
58
59 // single worker, done
60 if (_n_threads == 1) {
61 return true;
62 }
63
64 _blocker->lock_without_safepoint_check();
65 // all arrived, done
66 if (++ _offered_termination == _n_threads) {
67 _blocker->notify_all();
68 _blocker->unlock();
69 return true;
70 }
71
72 Thread* the_thread = Thread::current();
73 while (true) {
74 if (_spin_master == NULL) {
75 _spin_master = the_thread;
76
77 _blocker->unlock();
78
79 if (do_spin_master_work(terminator)) {
80 assert(_offered_termination == _n_threads, "termination condition");
81 return true;
82 } else {
83 _blocker->lock_without_safepoint_check();
84 }
85 } else {
86 _blocker->wait(true, WorkStealingSleepMillis);
87
88 if (_offered_termination == _n_threads) {
89 _blocker->unlock();
90 return true;
91 }
92 }
93
94 if (((terminator == NULL || terminator->should_force_termination()) && peek_in_queue_set()) ||
95 (terminator != NULL && terminator->should_exit_termination())) {
96 _offered_termination --;
97 _blocker->unlock();
98 return false;
99 }
100 }
101 }
102
103 #if TASKQUEUE_STATS
104 void ShenandoahObjToScanQueueSet::print_taskqueue_stats_hdr(outputStream* const st) {
105 st->print_raw_cr("GC Task Stats");
106 st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr();
107 st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
108 }
109
110 void ShenandoahObjToScanQueueSet::print_taskqueue_stats() {
111 if (! ShenandoahLogTrace) {
112 return;
113 }
114 ResourceMark rm;
115 outputStream* st = gclog_or_tty;
118 TaskQueueStats totals;
119 const uint n = size();
120 for (uint i = 0; i < n; ++i) {
121 st->print(UINT32_FORMAT_W(3), i);
122 queue(i)->stats.print(st);
123 st->cr();
124 totals += queue(i)->stats;
125 }
126 st->print("tot "); totals.print(st); st->cr();
127 DEBUG_ONLY(totals.verify());
128 }
129
130 void ShenandoahObjToScanQueueSet::reset_taskqueue_stats() {
131 const uint n = size();
132 for (uint i = 0; i < n; ++i) {
133 queue(i)->stats.reset();
134 }
135 }
136 #endif // TASKQUEUE_STATS
137
138
139 bool ShenandoahTaskTerminator::do_spin_master_work(TerminatorTerminator* terminator) {
140 uint yield_count = 0;
141 // Number of hard spin loops done since last yield
142 uint hard_spin_count = 0;
143 // Number of iterations in the hard spin loop.
144 uint hard_spin_limit = WorkStealingHardSpins;
145
146 // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
147 // If it is greater than 0, then start with a small number
148 // of spins and increase number with each turn at spinning until
149 // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
150 // Then do a yield() call and start spinning afresh.
151 if (WorkStealingSpinToYieldRatio > 0) {
152 hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
153 hard_spin_limit = MAX2(hard_spin_limit, 1U);
154 }
155 // Remember the initial spin limit.
156 uint hard_spin_start = hard_spin_limit;
157
158 // Loop waiting for all threads to offer termination or
159 // more work.
|
1 /*
2 * Copyright (c) 2016, 2018, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24 #include "precompiled.hpp"
25
26 #include "gc_implementation/shenandoah/shenandoahHeap.hpp"
27 #include "gc_implementation/shenandoah/shenandoahLogging.hpp"
28 #include "gc_implementation/shenandoah/shenandoahTaskqueue.hpp"
29
30 void ShenandoahObjToScanQueueSet::clear() {
31 uint size = GenericTaskQueueSet<ShenandoahObjToScanQueue, mtGC>::size();
32 for (uint index = 0; index < size; index ++) {
33 ShenandoahObjToScanQueue* q = queue(index);
34 assert(q != NULL, "Sanity");
35 q->clear();
36 }
37 }
38
39 bool ShenandoahObjToScanQueueSet::is_empty() {
40 uint size = GenericTaskQueueSet<ShenandoahObjToScanQueue, mtGC>::size();
41 for (uint index = 0; index < size; index ++) {
42 ShenandoahObjToScanQueue* q = queue(index);
43 assert(q != NULL, "Sanity");
44 if (!q->is_empty()) {
45 return false;
46 }
47 }
48 return true;
49 }
50
51 bool ShenandoahTaskTerminator::offer_termination(ShenandoahTerminatorTerminator* terminator) {
52 assert(_n_threads > 0, "Initialization is incorrect");
53 assert(_offered_termination < _n_threads, "Invariant");
54 assert(_blocker != NULL, "Invariant");
55
56 // single worker, done
57 if (_n_threads == 1) {
58 return true;
59 }
60
61 _blocker->lock_without_safepoint_check();
62 // all arrived, done
63 if (++ _offered_termination == _n_threads) {
64 _blocker->notify_all();
65 _blocker->unlock();
66 return true;
67 }
68
69 Thread* the_thread = Thread::current();
70 while (true) {
71 if (_spin_master == NULL) {
72 _spin_master = the_thread;
73
74 _blocker->unlock();
75
76 if (do_spin_master_work(terminator)) {
77 assert(_offered_termination == _n_threads, "termination condition");
78 return true;
79 } else {
80 _blocker->lock_without_safepoint_check();
81 }
82 } else {
83 _blocker->wait(true, WorkStealingSleepMillis);
84
85 if (_offered_termination == _n_threads) {
86 _blocker->unlock();
87 return true;
88 }
89 }
90
91 bool force = (terminator != NULL) && terminator->should_force_termination();
92 bool exit = (terminator != NULL) && terminator->should_exit_termination();
93 if ((!force && peek_in_queue_set()) || exit) {
94 _offered_termination --;
95 _blocker->unlock();
96 return false;
97 }
98 }
99 }
100
101 #if TASKQUEUE_STATS
102 void ShenandoahObjToScanQueueSet::print_taskqueue_stats_hdr(outputStream* const st) {
103 st->print_raw_cr("GC Task Stats");
104 st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr();
105 st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr();
106 }
107
108 void ShenandoahObjToScanQueueSet::print_taskqueue_stats() {
109 if (! ShenandoahLogTrace) {
110 return;
111 }
112 ResourceMark rm;
113 outputStream* st = gclog_or_tty;
116 TaskQueueStats totals;
117 const uint n = size();
118 for (uint i = 0; i < n; ++i) {
119 st->print(UINT32_FORMAT_W(3), i);
120 queue(i)->stats.print(st);
121 st->cr();
122 totals += queue(i)->stats;
123 }
124 st->print("tot "); totals.print(st); st->cr();
125 DEBUG_ONLY(totals.verify());
126 }
127
128 void ShenandoahObjToScanQueueSet::reset_taskqueue_stats() {
129 const uint n = size();
130 for (uint i = 0; i < n; ++i) {
131 queue(i)->stats.reset();
132 }
133 }
134 #endif // TASKQUEUE_STATS
135
136 bool ShenandoahTaskTerminator::do_spin_master_work(ShenandoahTerminatorTerminator* terminator) {
137 uint yield_count = 0;
138 // Number of hard spin loops done since last yield
139 uint hard_spin_count = 0;
140 // Number of iterations in the hard spin loop.
141 uint hard_spin_limit = WorkStealingHardSpins;
142
143 // If WorkStealingSpinToYieldRatio is 0, no hard spinning is done.
144 // If it is greater than 0, then start with a small number
145 // of spins and increase number with each turn at spinning until
146 // the count of hard spins exceeds WorkStealingSpinToYieldRatio.
147 // Then do a yield() call and start spinning afresh.
148 if (WorkStealingSpinToYieldRatio > 0) {
149 hard_spin_limit = WorkStealingHardSpins >> WorkStealingSpinToYieldRatio;
150 hard_spin_limit = MAX2(hard_spin_limit, 1U);
151 }
152 // Remember the initial spin limit.
153 uint hard_spin_start = hard_spin_limit;
154
155 // Loop waiting for all threads to offer termination or
156 // more work.
|