Skip to content

Commit

Permalink
Rewrote the stack to support elimination & combining backoff strategies
Browse files Browse the repository at this point in the history
Eliminaton cancels out opposite operations (push and pop). Combining
merges similar operations (pushes) into a batch operation. Both use an
arena to transfer elements between threads as a backoff strategy when
the stack's top reference is contended (CAS failed). This greatly
improves scalability by reducing the number of threads contending on
a shared reference.

The approach taken is much simpler than the previous EliminationStack
or the DECS paper's algorithm. Both of the alternatives rely on multiple
arena states to model different scenarios. In this version, the arena slot
is either empty or full. The consumer may receive multiple elements and it
mimics a producer after taking one of the elements for itself. This greatly
simplifies the DECS algorithm, resulting in higher performance despite a
penalty incurred by the consumer when producing.
  • Loading branch information
ben-manes committed Apr 18, 2015
1 parent df9ac13 commit 7772145
Show file tree
Hide file tree
Showing 16 changed files with 989 additions and 722 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@
* @author [email protected] (Ben Manes)
*/
@State(Scope.Group)
public class EliminationStackBenchmark {
@Param({"EliminationStack", "ConcurrentLinkedQueue", "ArrayBlockingQueue",
"LinkedBlockingQueueBenchmark", "LinkedTransferQueue", "SynchronousQueue",
"SynchronizedArrayDeque"})
public class ConcurrentLinkedStackBenchmark {
@Param({"ConcurrentLinkedStack_linearizable", "ConcurrentLinkedQueue"})
QueueType queueType;

Queue<Boolean> queue;
Expand All @@ -44,23 +42,23 @@ public void setup() {
queue = queueType.create();
}

@Benchmark @Group("no_contention") @GroupThreads(1)
public void no_contention_offer() {
@Benchmark @Group("low_contention") @GroupThreads(1)
public void low_contention_offer() {
queue.offer(Boolean.TRUE);
}

@Benchmark @Group("no_contention") @GroupThreads(1)
public void no_contention_poll() {
@Benchmark @Group("low_contention") @GroupThreads(1)
public void low_contention_poll() {
queue.poll();
}

@Benchmark @Group("mild_contention") @GroupThreads(4)
public void mild_contention_offer() {
@Benchmark @Group("medium_contention") @GroupThreads(4)
public void medium_contention_offer() {
queue.offer(Boolean.TRUE);
}

@Benchmark @Group("mild_contention") @GroupThreads(4)
public void mild_contention_poll() {
@Benchmark @Group("medium_contention") @GroupThreads(4)
public void medium_contention_poll() {
queue.poll();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
public enum QueueType {
SingleConsumerQueue_optimistic(SingleConsumerQueue::optimistic),
SingleConsumerQueue_linearizable(SingleConsumerQueue::linearizable),
EliminationStack(() -> new EliminationStack<>().asLifoQueue()),
ConcurrentLinkedStack_optimistic(() -> ConcurrentLinkedStack.optimistic().asLifoQueue()),
ConcurrentLinkedStack_linearizable(() -> ConcurrentLinkedStack.linearizable().asLifoQueue()),
ConcurrentLinkedQueue(ConcurrentLinkedQueue<Object>::new),
ArrayBlockingQueue(() -> new ArrayBlockingQueue<>(10000)),
LinkedBlockingQueueBenchmark(LinkedBlockingQueue<Object>::new),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@
*/
@State(Scope.Group)
public class SingleConsumerQueueBenchmark {
@Param({"SingleConsumerQueue_optimistic",
"SingleConsumerQueue_linearizable",
"ConcurrentLinkedQueue"})
@Param({"SingleConsumerQueue_linearizable", "ConcurrentLinkedQueue"})
QueueType queueType;

Queue<Boolean> queue;
Expand Down Expand Up @@ -71,7 +69,7 @@ public void high_contention_offer() {
}

@Benchmark @Group("high_contention") @GroupThreads(1)
public void high_contention_poll() {
public void high_contention_clear() {
queue.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@

import java.util.concurrent.ThreadLocalRandom;

import com.github.benmanes.caffeine.EliminationStack;
import com.github.benmanes.caffeine.ConcurrentLinkedStack;

/**
* @author Ben Manes ([email protected])
*/
public final class EliminationStackProfiler extends ProfilerHook {
public final class ConcurrentLinkedStackProfiler extends ProfilerHook {
static final Integer ELEMENT = 1;

final EliminationStack<Integer> stack = new EliminationStack<>();
final ConcurrentLinkedStack<Integer> stack = ConcurrentLinkedStack.linearizable();

@Override
protected void profile() {
Expand All @@ -41,7 +41,7 @@ protected void profile() {
}

public static void main(String[] args) {
ProfilerHook profile = new EliminationStackProfiler();
ProfilerHook profile = new ConcurrentLinkedStackProfiler();
profile.run();
}
}
Loading

0 comments on commit 7772145

Please sign in to comment.