understanding the disruptor

36
Understanding the Disruptor A Beginner's Guide to Hardcore Concurrency

Upload: trisha-gee

Post on 28-Nov-2014

5.512 views

Category:

Technology


1 download

DESCRIPTION

Presented to the London Java Community on the 11th October 2011.

TRANSCRIPT

Page 1: Understanding the Disruptor

Understanding the Disruptor

A Beginner's Guide to Hardcore Concurrency

Page 2: Understanding the Disruptor

Why is concurrency so difficult

?

Page 3: Understanding the Disruptor

Ordering

Program Order:

int w = 10;int x = 20;int y = 30;int z = 40;

int a = w + z;int b = x * y;

Execution Order (maybe):

int x = 20;int y = 30;int b = x * y;

int w = 10;int z = 40;int a = w + z;

Page 4: Understanding the Disruptor

Visibility

Page 5: Understanding the Disruptor

Why should we care about the details

?

Page 6: Understanding the Disruptor

Increment a Counter

static long foo = 0;

private static void increment() { for (long l = 0; l < 500000000L; l++) { foo++; }}

Page 7: Understanding the Disruptor

Using a Lock

public static long foo = 0;public static Lock lock = new Lock();

private static void increment() { for (long l = 0; l < 500000000L; l++) { lock.lock(); try { foo++; } finally { lock.unlock(); } }}

Page 8: Understanding the Disruptor

Using an AtomicLong

static AtomicLong foo = new AtomicLong(0);

private static void increment() { for (long l = 0; l < 500000000L; l++) { foo.getAndIncrement(); }}

Page 9: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms

Page 10: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms● One Thread (volatile): 4 700 ms (15x)

Page 11: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms● One Thread (volatile): 4 700 ms (15x)● One Thread (Atomic) : 5 700 ms (19x)

Page 12: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms● One Thread (volatile): 4 700 ms (15x)● One Thread (Atomic) : 5 700 ms (19x)● One Thread (Lock) : 10 000 ms (33x)

Page 13: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms● One Thread (volatile): 4 700 ms (15x)● One Thread (Atomic) : 5 700 ms (19x)● One Thread (Lock) : 10 000 ms (33x)● Two Threads (Atomic) : 30 000 ms (100x)

Page 14: Understanding the Disruptor

The Cost of Contention

Increment a counter 500 000 000 times.

● One Thread : 300 ms● One Thread (volatile): 4 700 ms (15x)● One Thread (Atomic) : 5 700 ms (19x)● One Thread (Lock) : 10 000 ms (33x)● Two Threads (Atomic) : 30 000 ms (100x)● Two Threads (Lock) : 224 000 ms (746x)

^^^^^^^^ ~4 minutes!!!

Page 15: Understanding the Disruptor

Parallel v. Serial - String Splitting

Guy Steele @ Strangle Loop:

http://www.infoq.com/presentations/Thinking-Parallel-Programming

Scala Implementation and Brute Force version in Java:

https://github.com/mikeb01/folklore/

Page 16: Understanding the Disruptor

Performance Test

Parallel (Scala): 440 ops/secSerial (Java) : 1768 ops/sec

Page 17: Understanding the Disruptor

CPUs Are Getting Faster

Single threaded string split on different CPUs

Page 18: Understanding the Disruptor

What problem were we trying to solve

?

Page 19: Understanding the Disruptor

Classic Approach to the Problem

Page 20: Understanding the Disruptor

The Problems We Found

Page 21: Understanding the Disruptor

Why Queues Suck

Page 22: Understanding the Disruptor

Why Queues Suck - Linked List

Page 23: Understanding the Disruptor

Why Queues Suck - Linked List

Page 24: Understanding the Disruptor

Contention Free Design

Page 25: Understanding the Disruptor

Now our Pipeline Looks Like...

Page 26: Understanding the Disruptor

How Fast Is It - Throughput

Page 27: Understanding the Disruptor

How Fast Is It - Latency

ABQ Disruptor

Min Latency (ns) 145 29

Mean Latency (ns) 32 757 52

99 Percentile Latency (ns) 2 097 152 128

99.99 Percentile Latency (ns) 4 194 304 8 192

Max Latency (ns) 5 069 086 175 567

Page 28: Understanding the Disruptor

How does it all work

?

Page 29: Understanding the Disruptor

Ordering and Visibility

private static final int SIZE = 32; private final Object[] data = new Object[SIZE]; private volatile long sequence = -1; private long nextValue = -1;

public void publish(Object value) { long index = ++nextValue; data[(int)(index % SIZE)] = value; sequence = index; }

public Object get(long index) { if (index <= sequence) { return data[(int)(index % SIZE)]; } return null; }

Page 30: Understanding the Disruptor

Ordering and Visibility - Store

mov $0x1,%ecxadd 0x18(%rsi),%rcx ;*ladd;...lea (%r12,%r8,8),%r11 ;*getfield data;...mov %r12b,(%r11,%r10,1)mov %rcx,0x10(%rsi)lock addl $0x0,(%rsp) ;*ladd

Page 31: Understanding the Disruptor

Ordering and Visibility - Load

mov %eax,-0x6000(%rsp)push %rbpsub $0x20,%rsp ;*synchronization entry ; - RingBuffer::get@-1 (line 17)mov 0x10(%rsi),%r10 ;*getfield sequence ; - RingBuffer::get@2 (line 17)cmp %r10,%rdxjl 0x00007ff92505f22d ;*iflt ; - RingBuffer::get@6 (line 17)mov %edx,%r11d ;*l2i ; - RingBuffer::get@14 (line 19)

Page 32: Understanding the Disruptor

Look Ma' No Memory Barrier

AtomicLong sequence = new AtomicLong(-1);

public void publish(Object value) { long index = ++nextValue; data[(int)(index % SIZE)] = value; sequence.lazySet(index);}

Page 33: Understanding the Disruptor

False Sharing - Hidden Contention

Page 34: Understanding the Disruptor

Cache Line Padding

public class PaddedAtomicLong extends AtomicLong {

public volatile long p1, p2, p3, p4, p5, p6 = 7L;

//... lines omitted

public long sumPaddingToPreventOptimisation() { return p1 + p2 + p3 + p4 + p5 + p6; }}

Page 35: Understanding the Disruptor

In Summary

● Concurrency is a tool● Ordering and visibility are the key challenges● For performance the details matter● Don't believe everything you read

○ Come up with your own theories and test them!

Page 36: Understanding the Disruptor

Q & A

[email protected]