WIP, not liking results

This commit is contained in:
nathan 2015-04-21 19:47:34 +02:00
parent 5be16c6345
commit b4e012c87c
3 changed files with 83 additions and 88 deletions

View File

@ -65,6 +65,7 @@ public class LinkedArrayList extends PadA1 {
final Object lvHead() {
return UNSAFE.getObjectVolatile(this, HEAD);
// return this.head;
}
final Object lpHead() {
@ -76,48 +77,51 @@ public class LinkedArrayList extends PadA1 {
}
final Object lpTail() {
return UNSAFE.getObject(this, TAIL);
return lpTail(this);
}
final Object lpNext(Object node) {
static final Object lpTail(Object source) {
return UNSAFE.getObject(source, TAIL);
}
static final Object lpNext(Object node) {
return UNSAFE.getObject(node, NEXT);
}
final boolean advanceTail(Object expected, Object newTail) {
// if (expected == lvTail()) {
return UNSAFE.compareAndSwapObject(this, TAIL, expected, newTail);
// }
// return false;
final Object that = this;
return advanceTail(that, lpTail(that), expected, newTail);
}
static final boolean advanceTail(Object source, Object objectActualTail, Object expected, Object newTail) {
return expected == objectActualTail && UNSAFE.compareAndSwapObject(source, TAIL, expected, newTail);
}
final boolean advanceHead(Object expected, Object newHead) {
// if (expected == lvHead()) {
return UNSAFE.compareAndSwapObject(this, HEAD, expected, newHead);
// }
// return false;
return expected == lpHead() && UNSAFE.compareAndSwapObject(this, HEAD, expected, newHead);
}
final Object lvThread(Object node) {
static final Object lvThread(Object node) {
return UNSAFE.getObjectVolatile(node, THREAD);
}
final Object lpThread(Object node) {
static final Object lpThread(Object node) {
return UNSAFE.getObject(node, THREAD);
}
final void spThread(Object node, Thread thread) {
static final void spThread(Object node, Thread thread) {
UNSAFE.putObject(node, THREAD, thread);
}
final boolean casThread(Object node, Object expected, Object newThread) {
static final boolean casThread(Object node, Object expected, Object newThread) {
return UNSAFE.compareAndSwapObject(node, THREAD, expected, newThread);
}
final boolean lpType(Object node) {
static final boolean lpType(Object node) {
return UNSAFE.getBoolean(node, IS_CONSUMER);
}
final void spType(Object node, boolean isConsumer) {
static final void spType(Object node, boolean isConsumer) {
UNSAFE.putBoolean(node, IS_CONSUMER, isConsumer);
}

View File

@ -5,7 +5,7 @@ package dorkbox.util.messagebus.common.simpleq;
// mpmc sparse.shift = 2, for this to be fast.
abstract class PrePad {
volatile long y0, y1, y2, y4, y5, y6 = 7L;
// volatile long y0, y1, y2, y4, y5, y6 = 7L;
volatile long z0, z1, z2, z4, z5, z6 = 7L;
}
@ -14,42 +14,42 @@ abstract class ColdItems {
// public final int ID = count.getAndIncrement();
// public short type = MessageType.ONE;
public volatile Object item1 = null;
public transient volatile Object item1 = null;
// public Object item2 = null;
// public Object item3 = null;
// public Object[] item4 = null;
}
abstract class Pad0 extends ColdItems {
volatile long y0, y1, y2, y4, y5, y6 = 7L;
// volatile long y0, y1, y2, y4, y5, y6 = 7L;
volatile long z0, z1, z2, z4, z5, z6 = 7L;
}
abstract class HotItem1 extends Pad0 {
public volatile boolean isConsumer = false;
public transient volatile boolean isConsumer = false;
}
abstract class Pad1 extends HotItem1 {
volatile long y0, y1, y2, y4, y5, y6 = 7L;
// volatile long y0, y1, y2, y4, y5, y6 = 7L;
volatile long z0, z1, z2, z4, z5, z6 = 7L;
}
abstract class HotItem2 extends Pad1 {
public volatile Thread thread;
public transient volatile Thread thread;
}
abstract class Pad2 extends HotItem2 {
volatile long y0, y1, y2, y4, y5, y6 = 7L;
// volatile long y0, y1, y2, y4, y5, y6 = 7L;
volatile long z0, z1, z2, z4, z5, z6 = 7L;
}
abstract class HotItem3 extends Pad2 {
public volatile Node next;
public transient volatile Node next;
}
public class Node extends HotItem3 {
// post-padding
volatile long y0, y1, y2, y4, y5, y6 = 7L;
// volatile long y0, y1, y2, y4, y5, y6 = 7L;
volatile long z0, z1, z2, z4, z5, z6 = 7L;
public Node() {

View File

@ -31,7 +31,7 @@ public final class SimpleQueue extends LinkedArrayList {
* This is greater than timed value because untimed waits spin
* faster since they don't need to check times on each spin.
*/
static final int maxUntimedSpins = maxTimedSpins * 64;
static final int maxUntimedSpins = maxTimedSpins * 32;
static final int negMaxUntimedSpins = -maxUntimedSpins;
/**
@ -77,8 +77,17 @@ public final class SimpleQueue extends LinkedArrayList {
// BOTH can think that the queue is empty, resulting in a deadlock between threads
// it is ALSO possible that the consumer pops the previous node, and so we thought it was not-empty, when
// in reality, it is.
final boolean empty = head == lpNext(tail);
final boolean sameMode = lpType(tail) == isConsumer;
boolean empty = head == lpNext(tail);
boolean sameMode = lpType(tail) == isConsumer;
// check to make sure we are not "double dipping" on our head
thread = lpThread(head);
if (empty && thread != null) {
empty = false;
} else if (sameMode && thread == null) {
busySpin();
continue;
}
// empty or same mode = push+park onto queue
if (empty || sameMode) {
@ -94,26 +103,13 @@ public final class SimpleQueue extends LinkedArrayList {
continue;
}
thread = lpThread(head);
if (thread != null) {
if (empty) {
busySpin();
continue;
}
} else {
if (sameMode) {
busySpin();
continue;
}
}
if (isConsumer) {
spType(tNext, isConsumer);
spThread(tNext, Thread.currentThread());
if (!advanceTail(tail, tNext)) { // FULL barrier
// failed to link in
busySpin();
// busySpin();
continue;
}
@ -121,23 +117,24 @@ public final class SimpleQueue extends LinkedArrayList {
// this will only advance head if necessary
// advanceHead(tail, tNext);
return lpItem1(tNext);
Object lpItem1 = lpItem1(tNext);
spItem1(tNext, null);
return lpItem1;
} else {
// producer
spType(tNext, isConsumer);
spItem1(tNext, item);
spThread(tNext, Thread.currentThread());
if (!advanceTail(tail, tNext)) { // FULL barrier
// failed to link in
busySpin();
continue;
}
park(tNext, timed, nanos);
// this will only advance head if necessary
// advanceHead(tail, tNext);
advanceHead(tail, tNext);
return null;
}
}
@ -153,55 +150,37 @@ public final class SimpleQueue extends LinkedArrayList {
thread = lpThread(head);
if (isConsumer) {
Object returnVal;
// while (true) {
returnVal = lpItem1(head);
Object returnVal = lpItem1(head);
// is already cancelled/fulfilled
if (thread == null ||
!casThread(head, thread, null)) { // FULL barrier
// is already cancelled/fulfilled
if (thread == null ||
!casThread(head, thread, null)) { // FULL barrier
// move head forward to look for next "ready" node
if (!advanceHead(head, next)) { // FULL barrier
busySpin();
// head = next;
// next = lpNext(head);
}
// head was already used by a different thread
advanceHead(head, next); // FULL barrier
// thread = lpThread(head);
continue;
}
// break;
// }
continue;
}
spItem1(head, null);
LockSupport.unpark((Thread) thread);
advanceHead(head, next); // FULL barrier
advanceHead(head, next); // FULL barrier
return returnVal;
} else {
// while (true) {
spItem1(head, item); // StoreStore
// producer
spItem1(head, item); // StoreStore
// is already cancelled/fulfilled
if (thread == null ||
!casThread(head, thread, null)) { // FULL barrier
// is already cancelled/fulfilled
if (thread == null ||
!casThread(head, thread, null)) { // FULL barrier
// move head forward to look for next "ready" node
if (!advanceHead(head, next)) { // FULL barrier
// head = next;
// next = lpNext(head);
busySpin();
}
// head was already used by a different thread
advanceHead(head, next); // FULL barrier
// thread = lpThread(head);
continue;
}
// break;
// }
continue;
}
LockSupport.unpark((Thread) thread);
@ -212,6 +191,18 @@ public final class SimpleQueue extends LinkedArrayList {
}
}
private static final void busySpin2() {
// busy spin for the amount of time (roughly) of a CPU context switch
int spins = maxUntimedSpins;
for (;;) {
if (spins > 0) {
--spins;
} else {
break;
}
}
}
private static final void busySpin() {
// busy spin for the amount of time (roughly) of a CPU context switch
int spins = SPINS;
@ -243,13 +234,13 @@ public final class SimpleQueue extends LinkedArrayList {
// busy spin for the amount of time (roughly) of a CPU context switch
// then park (if necessary)
for (;;) {
if (lvThread(myNode) == null) {
if (lpThread(myNode) == null) {
return;
} else if (spins > 0) {
--spins;
// } else if (spins > 0) {
// --spins;
} else if (spins > negMaxUntimedSpins) {
--spins;
LockSupport.parkNanos(1);
// LockSupport.parkNanos(1);
} else {
// park can return for NO REASON. Subsequent loops will hit this if it has not been ACTUALLY unlocked.
LockSupport.park();