Concurrecy techdrop

502 views
453 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
502
On SlideShare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Concurrecy techdrop

  1. 1. Clearpoint Techdrop Concurrency @mikeb2701 http://bad-concurrency.blogspot.comFriday, 8 March 13
  2. 2. public class OrderController { private Counter orderCounter; // What implementation??? public void placeOrder(long productId, long customerId) { orderCounter.increment(); // Place the order } }Friday, 8 March 13
  3. 3. public class BrokenCounter implements Counter { private long value = 0; @Override public void increment() { value++; } @Override public long getValue() { return value; } }Friday, 8 March 13
  4. 4. public class SynchronizedCounter implements Counter { private final Object mutex = new Object(); private long value = 0; public void increment() { synchronized (mutex) { value++; } } public long getValue() { return value; } }Friday, 8 March 13
  5. 5. public class LockedCounter implements Counter { private final Lock l = new ReentrantLock(); private long value = 0; public void increment() { l.lock(); try { value++; } finally { l.unlock(); } } public long getValue() { return value; } }Friday, 8 March 13
  6. 6. Sync Locked 40 30 M ops/sec 20 10 0 1 2 4 8 16 32 ThreadsFriday, 8 March 13
  7. 7. public class AtomicCounter implements Counter { private final AtomicLong value = new AtomicLong(0); @Override public void increment() { value.incrementAndGet(); } @Override public long getValue() { return value.get(); } }Friday, 8 March 13
  8. 8. public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } }Friday, 8 March 13
  9. 9. Sync Locked Atomic 90 67.5 45 22.5 0 1 2 4 8 16 32Friday, 8 March 13
  10. 10. public class ThreadLocalCounter implements Counter { ConcurrentLinkedQueue<AtomicLong> values = new ConcurrentLinkedQueue<AtomicLong>(); private final ThreadLocal<AtomicLong> counterLocal = new ThreadLocal<AtomicLong>() { protected AtomicLong initialValue() { AtomicLong value = new AtomicLong(); values.add(value); return value; } }; public void increment() { AtomicLong atomicLong = counterLocal.get(); atomicLong.lazySet(atomicLong.get() + 1); } public long getValue() { long l = 0; for (AtomicLong value : values) { l += value.get(); } return l; } }Friday, 8 March 13
  11. 11. Sync Locked Atomic Thread Local 1500 1125 750 375 0 1 2 4 8 16 32Friday, 8 March 13
  12. 12. 3. Write cache friendly code DRAM DRAM DRAM ~65ns DRAM DRAM DRAM QPI ~20ns MC MC L3 ~42 cycles ~15ns L3 L2 L2 L2 L2 ~10 cycles ~3ns L2 L2 L2 L2 L1 L1 L1 L1 ~4 cycles ~1ns L1 L1 L1 L1 C1 C2 C3 C4 Registers <1ns C1 C2 C3 C4Friday, 8 March 13
  13. 13. Friday, 8 March 13
  14. 14. Memory ModelsFriday, 8 March 13
  15. 15. public class SimpleQueue { private final Object[] data = new Object[1024]; private volatile int head, tail; public boolean offer(Object e) { if (head - (tail + data.length) < 0) { data[head & (data.length - 1)] = e; head++; return true; } return false; } public Object poll() { if (head - tail > 0) { Object e = data[tail & (data.length - 1)]; tail++; return e; } return null; } }Friday, 8 March 13
  16. 16. Happens-BeforeFriday, 8 March 13
  17. 17. Causality Causality Fear will keep the local systems inline. instructions - Grand Moff Wilhuff TarkinFriday, 8 March 13
  18. 18. 1st 2nd Operation Operation Normal Load Volatile Load Volatile Store Normal Store Monitor Enter Monitor Exit Normal Load Normal Store NO Volatile Load Monitor Enter NO NO NO Volatile Store Monitor Exit NO NOFriday, 8 March 13
  19. 19. • Loads are not reordered with other loads. • Stores are not reordered with other stores. • Stores are not reordered with older loads. • In a multiprocessor system, memory ordering obeys causality (memory ordering respects transitive visibility). • In a multiprocessor system, stores to the same location have a total order. • In a multiprocessor system, locked instructions to the same location have a total order. • Loads and Stores are not reordered with locked instructions.Friday, 8 March 13
  20. 20. Non-Blocking PrimitivesFriday, 8 March 13
  21. 21. UnsafeFriday, 8 March 13
  22. 22. public class AtomicLong extends Number implements Serializable { // ... private volatile long value; // ... /** * Sets to the given value. * * @param newValue the new value */ public final void set(long newValue) { value = newValue; } // ... }Friday, 8 March 13
  23. 23. # {method} set (J)V in java/util/concurrent/atomic/AtomicLong # this: rsi:rsi = java/util/concurrent/atomic/AtomicLong # parm0: rdx:rdx = long # [sp+0x20] (sp of caller) mov 0x8(%rsi),%r10d shl $0x3,%r10 cmp %r10,%rax jne 0x00007f1f410378a0 ; {runtime_call} xchg %ax,%ax nopl 0x0(%rax,%rax,1) xchg %ax,%ax push %rbp sub $0x10,%rsp nop mov %rdx,0x10(%rsi) lock addl $0x0,(%rsp) ;*putfield value ; - j.u.c.a.AtomicLong::set@2 (line 112) add $0x10,%rsp pop %rbp test %eax,0xa40fd06(%rip) # 0x00007f1f4b471000 ; {poll_return}Friday, 8 March 13
  24. 24. public class AtomicLong extends Number implements Serializable { // setup to use Unsafe.compareAndSwapLong for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; // ... /** * Eventually sets to the given value. * * @param newValue the new value * @since 1.6 */ public final void lazySet(long newValue) { unsafe.putOrderedLong(this, valueOffset, newValue); } // ... }Friday, 8 March 13
  25. 25. # {method} lazySet (J)V in java/util/concurrent/atomic/ AtomicLong # this: rsi:rsi = java/util/concurrent/atomic/AtomicLong # parm0: rdx:rdx = long # [sp+0x20] (sp of caller) mov 0x8(%rsi),%r10d shl $0x3,%r10 cmp %r10,%rax jne 0x00007f1f410378a0 ; {runtime_call} xchg %ax,%ax nopl 0x0(%rax,%rax,1) xchg %ax,%ax push %rbp sub $0x10,%rsp nop mov %rdx,0x10(%rsi) ;*invokevirtual putOrderedLong ; - AtomicLong::lazySet@8 (line 122) add $0x10,%rsp pop %rbp test %eax,0xa41204b(%rip) # 0x00007f1f4b471000 ; {poll_return}Friday, 8 March 13
  26. 26. public class AtomicInteger extends Number implements Serializable { // setup to use Unsafe.compareAndSwapInt for updates private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; private volatile int value; //... public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } }Friday, 8 March 13
  27. 27. # {method} compareAndSet (JJ)Z in java/util/concurrent/ atomic/AtomicLong # this: rsi:rsi = java/util/concurrent/atomic/AtomicLong # parm0: rdx:rdx = long # parm1: rcx:rcx = long # [sp+0x20] (sp of caller) mov 0x8(%rsi),%r10d shl $0x3,%r10 cmp %r10,%rax jne 0x00007f6699037a60 ; {runtime_call} xchg %ax,%ax nopl 0x0(%rax,%rax,1) xchg %ax,%ax sub $0x18,%rsp mov %rbp,0x10(%rsp) mov %rdx,%rax lock cmpxchg %rcx,0x10(%rsi) sete %r11b movzbl %r11b,%r11d ;*invokevirtual compareAndSwapLong ; - j.u.c.a.AtomicLong::compareAndSet@9 (line 149) mov %r11d,%eax add $0x10,%rsp pop %rbp test %eax,0x91df935(%rip) # 0x00007f66a223e000 ; {poll_return}Friday, 8 March 13
  28. 28. set() compareAndSet lazySet() 9 6.75 4.5 2.25 0 nanoseconds/opFriday, 8 March 13
  29. 29. Example - Disruptor Multi-producer private void publish(Disruptor disruptor, long value) { long next = disruptor.next(); disruptor.setValue(next, value); disruptor.publish(next); }Friday, 8 March 13
  30. 30. Example - Disruptor Multi-producer public long next() { long next; long current; do { current = nextSequence.get(); next = current + 1; while (next > (readSequence.get() + size)) { LockSupport.parkNanos(1L); continue; } } while (!nextSequence.compareAndSet(current, next)); return next; }Friday, 8 March 13
  31. 31. Algorithm: Spin - 1 public void publish(long sequence) { long sequenceMinusOne = sequence - 1; while (cursor.get() != sequenceMinusOne) { // Spin } cursor.lazySet(sequence); }Friday, 8 March 13
  32. 32. Spin - 1 25 18.75 million ops/sec 12.5 6.25 0 1 2 3 4 5 6 7 8 Producer ThreadsFriday, 8 March 13
  33. 33. Algorithm: Co-Op public void publish(long sequence) { int counter = RETRIES; while (sequence - cursor.get() > pendingPublication.length()) { if (--counter == 0) { Thread.yield(); counter = RETRIES; } } long expectedSequence = sequence - 1; pendingPublication.set((int) sequence & pendingMask, sequence); if (cursor.get() >= sequence) { return; } long nextSequence = sequence; while (cursor.compareAndSet(expectedSequence, nextSequence)) { expectedSequence = nextSequence; nextSequence++; if (pendingPublication.get((int) nextSequence & pendingMask) != nextSequence) { break; } } }Friday, 8 March 13
  34. 34. Spin - 1 Co-Op 30 22.5 million ops/sec 15 7.5 0 1 2 3 4 5 6 7 8 Producer ThreadsFriday, 8 March 13
  35. 35. Algorithm: Buffer public long next() { long next; long current; do { current = cursor.get(); next = current + 1; while (next > (readSequence.get() + size)) { LockSupport.parkNanos(1L); continue; } } while (!cursor.compareAndSet(current, next)); return next; }Friday, 8 March 13
  36. 36. Algorithm: Buffer public void publish(long sequence) { int publishedValue = (int) (sequence >>> indexShift); published.set(indexOf(sequence), publishedValue); } // Get Value int availableValue = (int) (current >>> indexShift); int index = indexOf(current); while (published.get(index) != availableValue) { // Spin }Friday, 8 March 13
  37. 37. Spin - 1 Co-Op Buffer 70 52.5 million ops/sec 35 17.5 0 1 2 3 4 5 6 7 8 ThreadsFriday, 8 March 13
  38. 38. Q&A • https://github.com/mikeb01/jax2012 • http://yow.eventer.com/yow-2012-1012/ lock-free-algorithms-for-ultimate- performance-by-martin-thompson-1250Friday, 8 March 13

×