src/share/vm/utilities/taskqueue.cpp

Thu, 20 Nov 2008 16:56:09 -0800

author
ysr
date
Thu, 20 Nov 2008 16:56:09 -0800
changeset 888
c96030fff130
parent 810
81cd571500b0
child 905
ad8c8ca4ab0f
permissions
-rw-r--r--

6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa

duke@435 1 /*
duke@435 2 * Copyright 2001-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
duke@435 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 21 * have any questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 # include "incls/_precompiled.incl"
duke@435 26 # include "incls/_taskqueue.cpp.incl"
duke@435 27
duke@435 28 bool TaskQueueSuper::peek() {
duke@435 29 return _bottom != _age.top();
duke@435 30 }
duke@435 31
duke@435 32 int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
duke@435 33 const int a = 16807;
duke@435 34 const int m = 2147483647;
duke@435 35 const int q = 127773; /* m div a */
duke@435 36 const int r = 2836; /* m mod a */
duke@435 37 assert(sizeof(int) == 4, "I think this relies on that");
duke@435 38 int seed = *seed0;
duke@435 39 int hi = seed / q;
duke@435 40 int lo = seed % q;
duke@435 41 int test = a * lo - r * hi;
duke@435 42 if (test > 0)
duke@435 43 seed = test;
duke@435 44 else
duke@435 45 seed = test + m;
duke@435 46 *seed0 = seed;
duke@435 47 return seed;
duke@435 48 }
duke@435 49
duke@435 50 ParallelTaskTerminator::
duke@435 51 ParallelTaskTerminator(int n_threads, TaskQueueSetSuper* queue_set) :
duke@435 52 _n_threads(n_threads),
duke@435 53 _queue_set(queue_set),
duke@435 54 _offered_termination(0) {}
duke@435 55
duke@435 56 bool ParallelTaskTerminator::peek_in_queue_set() {
duke@435 57 return _queue_set->peek();
duke@435 58 }
duke@435 59
duke@435 60 void ParallelTaskTerminator::yield() {
duke@435 61 os::yield();
duke@435 62 }
duke@435 63
duke@435 64 void ParallelTaskTerminator::sleep(uint millis) {
duke@435 65 os::sleep(Thread::current(), millis, false);
duke@435 66 }
duke@435 67
ysr@777 68 bool
ysr@777 69 ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
duke@435 70 Atomic::inc(&_offered_termination);
duke@435 71
duke@435 72 juint yield_count = 0;
duke@435 73 while (true) {
duke@435 74 if (_offered_termination == _n_threads) {
duke@435 75 //inner_termination_loop();
duke@435 76 return true;
duke@435 77 } else {
duke@435 78 if (yield_count <= WorkStealingYieldsBeforeSleep) {
duke@435 79 yield_count++;
duke@435 80 yield();
duke@435 81 } else {
duke@435 82 if (PrintGCDetails && Verbose) {
duke@435 83 gclog_or_tty->print_cr("ParallelTaskTerminator::offer_termination() "
duke@435 84 "thread %d sleeps after %d yields",
duke@435 85 Thread::current(), yield_count);
duke@435 86 }
duke@435 87 yield_count = 0;
duke@435 88 // A sleep will cause this processor to seek work on another processor's
duke@435 89 // runqueue, if it has nothing else to run (as opposed to the yield
duke@435 90 // which may only move the thread to the end of the this processor's
duke@435 91 // runqueue).
duke@435 92 sleep(WorkStealingSleepMillis);
duke@435 93 }
duke@435 94
ysr@777 95 if (peek_in_queue_set() ||
ysr@777 96 (terminator != NULL && terminator->should_exit_termination())) {
duke@435 97 Atomic::dec(&_offered_termination);
duke@435 98 return false;
duke@435 99 }
duke@435 100 }
duke@435 101 }
duke@435 102 }
duke@435 103
duke@435 104 void ParallelTaskTerminator::reset_for_reuse() {
duke@435 105 if (_offered_termination != 0) {
duke@435 106 assert(_offered_termination == _n_threads,
duke@435 107 "Terminator may still be in use");
duke@435 108 _offered_termination = 0;
duke@435 109 }
duke@435 110 }
duke@435 111
jcoomes@810 112 bool RegionTaskQueueWithOverflow::is_empty() {
jcoomes@810 113 return (_region_queue.size() == 0) &&
duke@435 114 (_overflow_stack->length() == 0);
duke@435 115 }
duke@435 116
jcoomes@810 117 bool RegionTaskQueueWithOverflow::stealable_is_empty() {
jcoomes@810 118 return _region_queue.size() == 0;
duke@435 119 }
duke@435 120
jcoomes@810 121 bool RegionTaskQueueWithOverflow::overflow_is_empty() {
duke@435 122 return _overflow_stack->length() == 0;
duke@435 123 }
duke@435 124
jcoomes@810 125 void RegionTaskQueueWithOverflow::initialize() {
jcoomes@810 126 _region_queue.initialize();
duke@435 127 assert(_overflow_stack == 0, "Creating memory leak");
duke@435 128 _overflow_stack =
jcoomes@810 129 new (ResourceObj::C_HEAP) GrowableArray<RegionTask>(10, true);
duke@435 130 }
duke@435 131
jcoomes@810 132 void RegionTaskQueueWithOverflow::save(RegionTask t) {
jcoomes@810 133 if (TraceRegionTasksQueuing && Verbose) {
duke@435 134 gclog_or_tty->print_cr("CTQ: save " PTR_FORMAT, t);
duke@435 135 }
jcoomes@810 136 if(!_region_queue.push(t)) {
duke@435 137 _overflow_stack->push(t);
duke@435 138 }
duke@435 139 }
duke@435 140
jcoomes@810 141 // Note that using this method will retrieve all regions
duke@435 142 // that have been saved but that it will always check
duke@435 143 // the overflow stack. It may be more efficient to
duke@435 144 // check the stealable queue and the overflow stack
duke@435 145 // separately.
jcoomes@810 146 bool RegionTaskQueueWithOverflow::retrieve(RegionTask& region_task) {
jcoomes@810 147 bool result = retrieve_from_overflow(region_task);
duke@435 148 if (!result) {
jcoomes@810 149 result = retrieve_from_stealable_queue(region_task);
duke@435 150 }
jcoomes@810 151 if (TraceRegionTasksQueuing && Verbose && result) {
duke@435 152 gclog_or_tty->print_cr(" CTQ: retrieve " PTR_FORMAT, result);
duke@435 153 }
duke@435 154 return result;
duke@435 155 }
duke@435 156
jcoomes@810 157 bool RegionTaskQueueWithOverflow::retrieve_from_stealable_queue(
jcoomes@810 158 RegionTask& region_task) {
jcoomes@810 159 bool result = _region_queue.pop_local(region_task);
jcoomes@810 160 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 161 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 162 }
duke@435 163 return result;
duke@435 164 }
duke@435 165
jcoomes@810 166 bool
jcoomes@810 167 RegionTaskQueueWithOverflow::retrieve_from_overflow(RegionTask& region_task) {
duke@435 168 bool result;
duke@435 169 if (!_overflow_stack->is_empty()) {
jcoomes@810 170 region_task = _overflow_stack->pop();
duke@435 171 result = true;
duke@435 172 } else {
jcoomes@810 173 region_task = (RegionTask) NULL;
duke@435 174 result = false;
duke@435 175 }
jcoomes@810 176 if (TraceRegionTasksQueuing && Verbose) {
jcoomes@810 177 gclog_or_tty->print_cr("CTQ: retrieve_stealable " PTR_FORMAT, region_task);
duke@435 178 }
duke@435 179 return result;
duke@435 180 }

mercurial