< prev index next >
src/hotspot/share/runtime/objectMonitor.cpp
Print this page
rev 51814 : imported patch syncknobs-00-base
rev 51815 : imported patch syncknobs-01-Knob_ReportSettings
rev 51816 : imported patch syncknobs-02-Knob_SpinBackOff
rev 51817 : imported patch syncknobs-03-BackOffMask
rev 51818 : imported patch syncknobs-04-Knob_ExitRelease
rev 51820 : imported patch syncknobs-05-Knob_InlineNotify
rev 51821 : imported patch syncknobs-06-Knob_Verbose
rev 51822 : imported patch syncknobs-07-Knob_VerifyInUse
rev 51824 : imported patch syncknobs-08-Knob_VerifyMatch
rev 51825 : imported patch syncknobs-09-Knob_SpinBase
rev 51826 : imported patch syncknobs-10-Knob_CASPenalty
rev 51827 : imported patch syncknobs-11-Knob_OXPenalty
rev 51828 : imported patch syncknobs-12-Knob_SpinSetSucc
rev 51829 : imported patch syncknobs-13-Knob_SpinEarly
rev 51830 : imported patch syncknobs-14-Knob_SuccEnabled
rev 51831 : imported patch syncknobs-15-Knob_SuccRestrict
rev 51832 : imported patch syncknobs-16-Knob_MaxSpinners
rev 51833 : imported patch syncknobs-17-Knob_SpinAfterFutile
rev 51834 : imported patch syncknobs-18-Knob_OState
rev 51835 : imported patch syncknobs-19-Knob_UsePause
rev 51836 : imported patch syncknobs-20-Knob_ExitPolicy
rev 51837 : imported patch syncknobs-20.2-Knob_ExitPolicy
rev 51838 : imported patch syncknobs-21-Knob_ResetEvent
rev 51839 : imported patch syncknobs-22-Knob_FastHSSEC
rev 51840 : imported patch syncknobs-23-Knob_MoveNotifyee
rev 51841 : imported patch syncknobs-24-Knob_QMode
@@ -99,43 +99,19 @@
// Tunables ...
// The knob* variables are effectively final. Once set they should
// never be modified hence. Consider using __read_mostly with GCC.
-int ObjectMonitor::Knob_ExitRelease = 0;
-int ObjectMonitor::Knob_InlineNotify = 1;
-int ObjectMonitor::Knob_Verbose = 0;
-int ObjectMonitor::Knob_VerifyInUse = 0;
-int ObjectMonitor::Knob_VerifyMatch = 0;
int ObjectMonitor::Knob_SpinLimit = 5000; // derived by an external tool -
-static int Knob_ReportSettings = 0;
-static int Knob_SpinBase = 0; // Floor AKA SpinMin
-static int Knob_SpinBackOff = 0; // spin-loop backoff
-static int Knob_CASPenalty = -1; // Penalty for failed CAS
-static int Knob_OXPenalty = -1; // Penalty for observed _owner change
-static int Knob_SpinSetSucc = 1; // spinners set the _succ field
-static int Knob_SpinEarly = 1;
-static int Knob_SuccEnabled = 1; // futile wake throttling
-static int Knob_SuccRestrict = 0; // Limit successors + spinners to at-most-one
-static int Knob_MaxSpinners = -1; // Should be a function of # CPUs
static int Knob_Bonus = 100; // spin success bonus
static int Knob_BonusB = 100; // spin success bonus
static int Knob_Penalty = 200; // spin failure penalty
static int Knob_Poverty = 1000;
-static int Knob_SpinAfterFutile = 1; // Spin after returning from park()
static int Knob_FixedSpin = 0;
-static int Knob_OState = 3; // Spinner checks thread state of _owner
-static int Knob_UsePause = 1;
-static int Knob_ExitPolicy = 0;
static int Knob_PreSpin = 10; // 20-100 likely better
-static int Knob_ResetEvent = 0;
-static int BackOffMask = 0;
-static int Knob_FastHSSEC = 0;
-static int Knob_MoveNotifyee = 2; // notify() - disposition of notifyee
-static int Knob_QMode = 0; // EntryList-cxq policy - queue discipline
static volatile int InitDone = 0;
// -----------------------------------------------------------------------------
// Theory of operations -- Monitors lists, thread residency, etc:
//
@@ -297,11 +273,11 @@
// Try one round of spinning *before* enqueueing Self
// and before going through the awkward and expensive state
// transitions. The following spin is strictly optional ...
// Note that if we acquire the monitor from an initial spin
// we forgo posting JVMTI events and firing DTRACE probes.
- if (Knob_SpinEarly && TrySpin (Self) > 0) {
+ if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_recursions == 0, "invariant");
assert(((oop)(object()))->mark() == markOopDesc::encode(this), "invariant");
Self->_Stalled = 0;
return;
@@ -459,11 +435,11 @@
// If the _owner is ready but OFFPROC we could use a YieldTo()
// operation to donate the remainder of this thread's quantum
// to the owner. This has subtle but beneficial affinity
// effects.
- if (TrySpin (Self) > 0) {
+ if (TrySpin(Self) > 0) {
assert(_owner == Self, "invariant");
assert(_succ != Self, "invariant");
assert(_Responsible != Self, "invariant");
return;
}
@@ -581,24 +557,18 @@
// Assuming this is not a spurious wakeup we'll normally find _succ == Self.
// We can defer clearing _succ until after the spin completes
// TrySpin() must tolerate being called with _succ == Self.
// Try yet another round of adaptive spinning.
- if ((Knob_SpinAfterFutile & 1) && TrySpin(Self) > 0) break;
+ if (TrySpin(Self) > 0) break;
// We can find that we were unpark()ed and redesignated _succ while
// we were spinning. That's harmless. If we iterate and call park(),
// park() will consume the event and return immediately and we'll
// just spin again. This pattern can repeat, leaving _succ to simply
- // spin on a CPU. Enable Knob_ResetEvent to clear pending unparks().
- // Alternately, we can sample fired() here, and if set, forgo spinning
- // in the next iteration.
+ // spin on a CPU.
- if ((Knob_ResetEvent & 1) && Self->_ParkEvent->fired()) {
- Self->_ParkEvent->reset();
- OrderAccess::fence();
- }
if (_succ == Self) _succ = NULL;
// Invariant: after clearing _succ a thread *must* retry _owner before parking.
OrderAccess::fence();
}
@@ -673,13 +643,11 @@
// ReenterI() is a specialized inline form of the latter half of the
// contended slow-path from EnterI(). We use ReenterI() only for
// monitor reentry in wait().
//
-// In the future we should reconcile EnterI() and ReenterI(), adding
-// Knob_Reset and Knob_SpinAfterFutile support and restructuring the
-// loop accordingly.
+// In the future we should reconcile EnterI() and ReenterI().
void ObjectMonitor::ReenterI(Thread * Self, ObjectWaiter * SelfNode) {
assert(Self != NULL, "invariant");
assert(SelfNode != NULL, "invariant");
assert(SelfNode->_thread == Self, "invariant");
@@ -927,23 +895,14 @@
#endif
for (;;) {
assert(THREAD == _owner, "invariant");
- if (Knob_ExitPolicy == 0) {
// release semantics: prior loads and stores from within the critical section
// must not float (reorder) past the following store that drops the lock.
// On SPARC that requires MEMBAR #loadstore|#storestore.
// But of course in TSO #loadstore|#storestore is not required.
- // I'd like to write one of the following:
- // A. OrderAccess::release() ; _owner = NULL
- // B. OrderAccess::loadstore(); OrderAccess::storestore(); _owner = NULL;
- // Unfortunately OrderAccess::release() and OrderAccess::loadstore() both
- // store into a _dummy variable. That store is not needed, but can result
- // in massive wasteful coherency traffic on classic SMP systems.
- // Instead, I use release_store(), which is implemented as just a simple
- // ST on x64, x86 and SPARC.
OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
OrderAccess::storeload(); // See if we need to wake a successor
if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
return;
}
@@ -986,126 +945,14 @@
// falls to the new owner.
//
if (!Atomic::replace_if_null(THREAD, &_owner)) {
return;
}
- } else {
- if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
- OrderAccess::release_store(&_owner, (void*)NULL); // drop the lock
- OrderAccess::storeload();
- // Ratify the previously observed values.
- if (_cxq == NULL || _succ != NULL) {
- return;
- }
-
- // inopportune interleaving -- the exiting thread (this thread)
- // in the fast-exit path raced an entering thread in the slow-enter
- // path.
- // We have two choices:
- // A. Try to reacquire the lock.
- // If the CAS() fails return immediately, otherwise
- // we either restart/rerun the exit operation, or simply
- // fall-through into the code below which wakes a successor.
- // B. If the elements forming the EntryList|cxq are TSM
- // we could simply unpark() the lead thread and return
- // without having set _succ.
- if (!Atomic::replace_if_null(THREAD, &_owner)) {
- return;
- }
- }
- }
guarantee(_owner == THREAD, "invariant");
ObjectWaiter * w = NULL;
- int QMode = Knob_QMode;
-
- if (QMode == 2 && _cxq != NULL) {
- // QMode == 2 : cxq has precedence over EntryList.
- // Try to directly wake a successor from the cxq.
- // If successful, the successor will need to unlink itself from cxq.
- w = _cxq;
- assert(w != NULL, "invariant");
- assert(w->TState == ObjectWaiter::TS_CXQ, "Invariant");
- ExitEpilog(Self, w);
- return;
- }
-
- if (QMode == 3 && _cxq != NULL) {
- // Aggressively drain cxq into EntryList at the first opportunity.
- // This policy ensure that recently-run threads live at the head of EntryList.
- // Drain _cxq into EntryList - bulk transfer.
- // First, detach _cxq.
- // The following loop is tantamount to: w = swap(&cxq, NULL)
- w = _cxq;
- for (;;) {
- assert(w != NULL, "Invariant");
- ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
- if (u == w) break;
- w = u;
- }
- assert(w != NULL, "invariant");
-
- ObjectWaiter * q = NULL;
- ObjectWaiter * p;
- for (p = w; p != NULL; p = p->_next) {
- guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
- p->TState = ObjectWaiter::TS_ENTER;
- p->_prev = q;
- q = p;
- }
-
- // Append the RATs to the EntryList
- // TODO: organize EntryList as a CDLL so we can locate the tail in constant-time.
- ObjectWaiter * Tail;
- for (Tail = _EntryList; Tail != NULL && Tail->_next != NULL;
- Tail = Tail->_next)
- /* empty */;
- if (Tail == NULL) {
- _EntryList = w;
- } else {
- Tail->_next = w;
- w->_prev = Tail;
- }
-
- // Fall thru into code that tries to wake a successor from EntryList
- }
-
- if (QMode == 4 && _cxq != NULL) {
- // Aggressively drain cxq into EntryList at the first opportunity.
- // This policy ensure that recently-run threads live at the head of EntryList.
-
- // Drain _cxq into EntryList - bulk transfer.
- // First, detach _cxq.
- // The following loop is tantamount to: w = swap(&cxq, NULL)
- w = _cxq;
- for (;;) {
- assert(w != NULL, "Invariant");
- ObjectWaiter * u = Atomic::cmpxchg((ObjectWaiter*)NULL, &_cxq, w);
- if (u == w) break;
- w = u;
- }
- assert(w != NULL, "invariant");
-
- ObjectWaiter * q = NULL;
- ObjectWaiter * p;
- for (p = w; p != NULL; p = p->_next) {
- guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
- p->TState = ObjectWaiter::TS_ENTER;
- p->_prev = q;
- q = p;
- }
-
- // Prepend the RATs to the EntryList
- if (_EntryList != NULL) {
- q->_next = _EntryList;
- _EntryList->_prev = q;
- }
- _EntryList = w;
-
- // Fall thru into code that tries to wake a successor from EntryList
- }
w = _EntryList;
if (w != NULL) {
// I'd like to write: guarantee (w->_thread != Self).
// But in practice an exiting thread may find itself on the EntryList.
@@ -1148,39 +995,19 @@
// and effectively lengthening the critical section.
// Invariant: s chases t chases u.
// TODO-FIXME: consider changing EntryList from a DLL to a CDLL so
// we have faster access to the tail.
- if (QMode == 1) {
- // QMode == 1 : drain cxq to EntryList, reversing order
- // We also reverse the order of the list.
- ObjectWaiter * s = NULL;
- ObjectWaiter * t = w;
- ObjectWaiter * u = NULL;
- while (t != NULL) {
- guarantee(t->TState == ObjectWaiter::TS_CXQ, "invariant");
- t->TState = ObjectWaiter::TS_ENTER;
- u = t->_next;
- t->_prev = u;
- t->_next = s;
- s = t;
- t = u;
- }
- _EntryList = s;
- assert(s != NULL, "invariant");
- } else {
- // QMode == 0 or QMode == 2
_EntryList = w;
ObjectWaiter * q = NULL;
ObjectWaiter * p;
for (p = w; p != NULL; p = p->_next) {
guarantee(p->TState == ObjectWaiter::TS_CXQ, "Invariant");
p->TState = ObjectWaiter::TS_ENTER;
p->_prev = q;
q = p;
}
- }
// In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = NULL
// The MEMBAR is satisfied by the release_store() operation in ExitEpilog().
// See if we can abdicate to a spinner instead of waking a thread.
@@ -1224,26 +1051,12 @@
// Alternately, a Dekker-like mechanism with multiple variables
// would suffice:
// ST Self->_suspend_equivalent = false
// MEMBAR
// LD Self_>_suspend_flags
-//
-// UPDATE 2007-10-6: since I've replaced the native Mutex/Monitor subsystem
-// with a more efficient implementation, the need to use "FastHSSEC" has
-// decreased. - Dave
-
bool ObjectMonitor::ExitSuspendEquivalent(JavaThread * jSelf) {
- const int Mode = Knob_FastHSSEC;
- if (Mode && !jSelf->is_external_suspend()) {
- assert(jSelf->is_suspend_equivalent(), "invariant");
- jSelf->clear_suspend_equivalent();
- if (2 == Mode) OrderAccess::storeload();
- if (!jSelf->is_external_suspend()) return false;
- // We raced a suspension -- fall thru into the slow path
- jSelf->set_suspend_equivalent();
- }
return jSelf->handle_special_suspend_equivalent_condition();
}
void ObjectMonitor::ExitEpilog(Thread * Self, ObjectWaiter * Wakee) {
@@ -1253,11 +1066,11 @@
// 1. ST _succ = wakee
// 2. membar #loadstore|#storestore;
// 2. ST _owner = NULL
// 3. unpark(wakee)
- _succ = Knob_SuccEnabled ? Wakee->_thread : NULL;
+ _succ = Wakee->_thread;
ParkEvent * Trigger = Wakee->_event;
// Hygiene -- once we've set _owner = NULL we can't safely dereference Wakee again.
// The thread associated with Wakee may have grabbed the lock and "Wakee" may be
// out-of-scope (non-extant).
@@ -1346,16 +1159,10 @@
void ObjectMonitor::check_slow(TRAPS) {
assert(THREAD != _owner && !THREAD->is_lock_owned((address) _owner), "must not be owner");
THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), "current thread not owner");
}
-static int Adjust(volatile int * adr, int dx) {
- int v;
- for (v = *adr; Atomic::cmpxchg(v + dx, adr, v) != v; v = *adr) /* empty */;
- return v;
-}
-
static void post_monitor_wait_event(EventJavaMonitorWait* event,
ObjectMonitor* monitor,
jlong notifier_tid,
jlong timeout,
bool timedout) {
@@ -1597,61 +1404,34 @@
// If the lock is cool (cxq == null && succ == null) and we're on an MP system
// then instead of transferring a thread from the WaitSet to the EntryList
// we might just dequeue a thread from the WaitSet and directly unpark() it.
void ObjectMonitor::INotify(Thread * Self) {
- const int policy = Knob_MoveNotifyee;
-
Thread::SpinAcquire(&_WaitSetLock, "WaitSet - notify");
ObjectWaiter * iterator = DequeueWaiter();
if (iterator != NULL) {
guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant");
guarantee(iterator->_notified == 0, "invariant");
// Disposition - what might we do with iterator ?
// a. add it directly to the EntryList - either tail (policy == 1)
// or head (policy == 0).
// b. push it onto the front of the _cxq (policy == 2).
// For now we use (b).
- if (policy != 4) {
+
iterator->TState = ObjectWaiter::TS_ENTER;
- }
+
iterator->_notified = 1;
iterator->_notifier_tid = JFR_THREAD_ID(Self);
ObjectWaiter * list = _EntryList;
if (list != NULL) {
assert(list->_prev == NULL, "invariant");
assert(list->TState == ObjectWaiter::TS_ENTER, "invariant");
assert(list != iterator, "invariant");
}
- if (policy == 0) { // prepend to EntryList
- if (list == NULL) {
- iterator->_next = iterator->_prev = NULL;
- _EntryList = iterator;
- } else {
- list->_prev = iterator;
- iterator->_next = list;
- iterator->_prev = NULL;
- _EntryList = iterator;
- }
- } else if (policy == 1) { // append to EntryList
- if (list == NULL) {
- iterator->_next = iterator->_prev = NULL;
- _EntryList = iterator;
- } else {
- // CONSIDER: finding the tail currently requires a linear-time walk of
- // the EntryList. We can make tail access constant-time by converting to
- // a CDLL instead of using our current DLL.
- ObjectWaiter * tail;
- for (tail = list; tail->_next != NULL; tail = tail->_next) {}
- assert(tail != NULL && tail->_next == NULL, "invariant");
- tail->_next = iterator;
- iterator->_prev = tail;
- iterator->_next = NULL;
- }
- } else if (policy == 2) { // prepend to cxq
+ // prepend to cxq
if (list == NULL) {
iterator->_next = iterator->_prev = NULL;
_EntryList = iterator;
} else {
iterator->TState = ObjectWaiter::TS_CXQ;
@@ -1661,46 +1441,21 @@
if (Atomic::cmpxchg(iterator, &_cxq, front) == front) {
break;
}
}
}
- } else if (policy == 3) { // append to cxq
- iterator->TState = ObjectWaiter::TS_CXQ;
- for (;;) {
- ObjectWaiter * tail = _cxq;
- if (tail == NULL) {
- iterator->_next = NULL;
- if (Atomic::replace_if_null(iterator, &_cxq)) {
- break;
- }
- } else {
- while (tail->_next != NULL) tail = tail->_next;
- tail->_next = iterator;
- iterator->_prev = tail;
- iterator->_next = NULL;
- break;
- }
- }
- } else {
- ParkEvent * ev = iterator->_event;
- iterator->TState = ObjectWaiter::TS_RUN;
- OrderAccess::fence();
- ev->unpark();
- }
// _WaitSetLock protects the wait queue, not the EntryList. We could
// move the add-to-EntryList operation, above, outside the critical section
// protected by _WaitSetLock. In practice that's not useful. With the
// exception of wait() timeouts and interrupts the monitor owner
// is the only thread that grabs _WaitSetLock. There's almost no contention
// on _WaitSetLock so it's not profitable to reduce the length of the
// critical section.
- if (policy < 4) {
iterator->wait_reenter_begin(this);
}
- }
Thread::SpinRelease(&_WaitSetLock);
}
// Consider: a not-uncommon synchronization bug is to use notify() when
// notifyAll() is more appropriate, potentially resulting in stranded
@@ -1852,37 +1607,23 @@
// the # of failed spin attempts (or iterations) reaches some threshold.
// This takes us into the realm of 1-out-of-N spinning, where we
// hold the duration constant but vary the frequency.
ctr = _SpinDuration;
- if (ctr < Knob_SpinBase) ctr = Knob_SpinBase;
if (ctr <= 0) return 0;
- if (Knob_SuccRestrict && _succ != NULL) return 0;
- if (Knob_OState && NotRunnable (Self, (Thread *) _owner)) {
- return 0;
- }
-
- int MaxSpin = Knob_MaxSpinners;
- if (MaxSpin >= 0) {
- if (_Spinner > MaxSpin) {
+ if (NotRunnable(Self, (Thread *) _owner)) {
return 0;
}
- // Slightly racy, but benign ...
- Adjust(&_Spinner, 1);
- }
// We're good to spin ... spin ingress.
// CONSIDER: use Prefetch::write() to avoid RTS->RTO upgrades
// when preparing to LD...CAS _owner, etc and the CAS is likely
// to succeed.
- int hits = 0;
- int msk = 0;
- int caspty = Knob_CASPenalty;
- int oxpty = Knob_OXPenalty;
- int sss = Knob_SpinSetSucc;
- if (sss && _succ == NULL) _succ = Self;
+ if (_succ == NULL) {
+ _succ = Self;
+ }
Thread * prv = NULL;
// There are three ways to exit the following loop:
// 1. A successful spin where this thread has acquired the lock.
// 2. Spin failure with prejudice
@@ -1901,36 +1642,11 @@
// We periodically check to see if there's a safepoint pending.
if ((ctr & 0xFF) == 0) {
if (SafepointMechanism::poll(Self)) {
goto Abort; // abrupt spin egress
}
- if (Knob_UsePause & 1) SpinPause();
- }
-
- if (Knob_UsePause & 2) SpinPause();
-
- // Exponential back-off ... Stay off the bus to reduce coherency traffic.
- // This is useful on classic SMP systems, but is of less utility on
- // N1-style CMT platforms.
- //
- // Trade-off: lock acquisition latency vs coherency bandwidth.
- // Lock hold times are typically short. A histogram
- // of successful spin attempts shows that we usually acquire
- // the lock early in the spin. That suggests we want to
- // sample _owner frequently in the early phase of the spin,
- // but then back-off and sample less frequently as the spin
- // progresses. The back-off makes a good citizen on SMP big
- // SMP systems. Oversampling _owner can consume excessive
- // coherency bandwidth. Relatedly, if we _oversample _owner we
- // can inadvertently interfere with the the ST m->owner=null.
- // executed by the lock owner.
- if (ctr & msk) continue;
- ++hits;
- if ((hits & 0xF) == 0) {
- // The 0xF, above, corresponds to the exponent.
- // Consider: (msk+1)|msk
- msk = ((msk << 2)|3) & BackOffMask;
+ SpinPause();
}
// Probe _owner with TATAS
// If this thread observes the monitor transition or flicker
// from locked to unlocked to locked, then the odds that this
@@ -1945,14 +1661,13 @@
if (ox == NULL) {
ox = (Thread*)Atomic::cmpxchg(Self, &_owner, (void*)NULL);
if (ox == NULL) {
// The CAS succeeded -- this thread acquired ownership
// Take care of some bookkeeping to exit spin state.
- if (sss && _succ == Self) {
+ if (_succ == Self) {
_succ = NULL;
}
- if (MaxSpin > 0) Adjust(&_Spinner, -1);
// Increase _SpinDuration :
// The spin was successful (profitable) so we tend toward
// longer spin attempts in the future.
// CONSIDER: factor "ctr" into the _SpinDuration adjustment.
@@ -1966,37 +1681,34 @@
}
return 1;
}
// The CAS failed ... we can take any of the following actions:
- // * penalize: ctr -= Knob_CASPenalty
+ // * penalize: ctr -= CASPenalty
// * exit spin with prejudice -- goto Abort;
// * exit spin without prejudice.
// * Since CAS is high-latency, retry again immediately.
prv = ox;
- if (caspty == -2) break;
- if (caspty == -1) goto Abort;
- ctr -= caspty;
- continue;
+ goto Abort;
}
// Did lock ownership change hands ?
if (ox != prv && prv != NULL) {
- if (oxpty == -2) break;
- if (oxpty == -1) goto Abort;
- ctr -= oxpty;
+ goto Abort;
}
prv = ox;
// Abort the spin if the owner is not executing.
// The owner must be executing in order to drop the lock.
// Spinning while the owner is OFFPROC is idiocy.
// Consider: ctr -= RunnablePenalty ;
- if (Knob_OState && NotRunnable (Self, ox)) {
+ if (NotRunnable(Self, ox)) {
goto Abort;
}
- if (sss && _succ == NULL) _succ = Self;
+ if (_succ == NULL) {
+ _succ = Self;
+ }
}
// Spin failed with prejudice -- reduce _SpinDuration.
// TODO: Use an AIMD-like policy to adjust _SpinDuration.
// AIMD is globally stable.
@@ -2010,12 +1722,11 @@
_SpinDuration = x;
}
}
Abort:
- if (MaxSpin >= 0) Adjust(&_Spinner, -1);
- if (sss && _succ == Self) {
+ if (_succ == Self) {
_succ = NULL;
// Invariant: after setting succ=null a contending thread
// must recheck-retry _owner before parking. This usually happens
// in the normal usage of TrySpin(), but it's safest
// to make TrySpin() as foolproof as possible.
@@ -2202,106 +1913,26 @@
#undef NEWPERFCOUNTER
#undef NEWPERFVARIABLE
}
}
-static char * kvGet(char * kvList, const char * Key) {
- if (kvList == NULL) return NULL;
- size_t n = strlen(Key);
- char * Search;
- for (Search = kvList; *Search; Search += strlen(Search) + 1) {
- if (strncmp (Search, Key, n) == 0) {
- if (Search[n] == '=') return Search + n + 1;
- if (Search[n] == 0) return(char *) "1";
- }
- }
- return NULL;
-}
-
-static int kvGetInt(char * kvList, const char * Key, int Default) {
- char * v = kvGet(kvList, Key);
- int rslt = v ? ::strtol(v, NULL, 0) : Default;
- if (Knob_ReportSettings && v != NULL) {
- tty->print_cr("INFO: SyncKnob: %s %d(%d)", Key, rslt, Default) ;
- tty->flush();
- }
- return rslt;
-}
-
void ObjectMonitor::DeferredInitialize() {
if (InitDone > 0) return;
if (Atomic::cmpxchg (-1, &InitDone, 0) != 0) {
while (InitDone != 1) /* empty */;
return;
}
// One-shot global initialization ...
// The initialization is idempotent, so we don't need locks.
// In the future consider doing this via os::init_2().
- // SyncKnobs consist of <Key>=<Value> pairs in the style
- // of environment variables. Start by converting ':' to NUL.
-
- if (SyncKnobs == NULL) SyncKnobs = "";
- size_t sz = strlen(SyncKnobs);
- char * knobs = (char *) os::malloc(sz + 2, mtInternal);
- if (knobs == NULL) {
- vm_exit_out_of_memory(sz + 2, OOM_MALLOC_ERROR, "Parse SyncKnobs");
- guarantee(0, "invariant");
- }
- strcpy(knobs, SyncKnobs);
- knobs[sz+1] = 0;
- for (char * p = knobs; *p; p++) {
- if (*p == ':') *p = 0;
- }
-
- #define SETKNOB(x) { Knob_##x = kvGetInt(knobs, #x, Knob_##x); }
- SETKNOB(ReportSettings);
- SETKNOB(ExitRelease);
- SETKNOB(InlineNotify);
- SETKNOB(Verbose);
- SETKNOB(VerifyInUse);
- SETKNOB(VerifyMatch);
- SETKNOB(FixedSpin);
- SETKNOB(SpinLimit);
- SETKNOB(SpinBase);
- SETKNOB(SpinBackOff);
- SETKNOB(CASPenalty);
- SETKNOB(OXPenalty);
- SETKNOB(SpinSetSucc);
- SETKNOB(SuccEnabled);
- SETKNOB(SuccRestrict);
- SETKNOB(Penalty);
- SETKNOB(Bonus);
- SETKNOB(BonusB);
- SETKNOB(Poverty);
- SETKNOB(SpinAfterFutile);
- SETKNOB(UsePause);
- SETKNOB(SpinEarly);
- SETKNOB(OState);
- SETKNOB(MaxSpinners);
- SETKNOB(PreSpin);
- SETKNOB(ExitPolicy);
- SETKNOB(QMode);
- SETKNOB(ResetEvent);
- SETKNOB(MoveNotifyee);
- SETKNOB(FastHSSEC);
- #undef SETKNOB
-
- if (os::is_MP()) {
- BackOffMask = (1 << Knob_SpinBackOff) - 1;
- if (Knob_ReportSettings) {
- tty->print_cr("INFO: BackOffMask=0x%X", BackOffMask);
- }
- // CONSIDER: BackOffMask = ROUNDUP_NEXT_POWER2 (ncpus-1)
- } else {
+ if (!os::is_MP()) {
Knob_SpinLimit = 0;
- Knob_SpinBase = 0;
Knob_PreSpin = 0;
Knob_FixedSpin = -1;
}
- os::free(knobs);
OrderAccess::fence();
InitDone = 1;
}
< prev index next >