51
@jpbempel #LockFree @jpbempel #LockFree Programmation Lock-Free : les techniques des pros Ullink Architecte Performance @jpbempel http://jpbempel.blogspot.com [email protected]

Programmation lock free - les techniques des pros (1ere partie)

Embed Size (px)

Citation preview

Page 1: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Programmation Lock-Free : les techniques des pros

UllinkArchitecte Performance@jpbempelhttp://[email protected]

Page 2: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree

Objectif

Réduction de la contention pour une meilleure scalabilité

Page 3: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree

Agenda 1ère partieMesurer la contention

Copy On Write

Lock striping

Compare-And-Swap

Introduction au Modèle Mémoire Java

Page 4: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Immutabilité

Page 5: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Contention

Page 6: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Contention2 threads ou plus essayant d'acquérir un lock

Threads en attente de la libération du lock

Raison numéro 1 pour éviter les locks

Photo de Filip Bogdan

Page 7: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Measure, don’t guess!Kirk Pepperdine & Jack Shirazi

Page 8: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Measure, don’t premature!

Page 9: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Bloc Synchronized

•Profilers (YourKit, JProfiler, ZVision)•JVMTI native agent•Résultats peuvent être difficiles à exploiter

Mesurer la contention

Page 10: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer la contention

Page 11: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer la contention

Page 12: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer la contentionjava.util.concurrent.Lock

•JVM ne peut aider ici•classes du JDK, code classique•JProfiler peut les profiler•Modification classes j.u.c + bootclasspath (jucProfiler)

Page 13: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer la contention

Page 14: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer la contentionInsertion de compteur de contention•Identifier les endroits où l’acquisition des locks échouent •Incrémenter le compteur

Identifier les locks•Callstack à l’instanciation•logger le statut des compteurs

Comment mesurer les locks existants dans votre code•Modifier les classes du JDK•Réintroduire ces classes dans les bootclasspath

Page 15: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Copy On Write

Page 16: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Copier toutes les données quand il y a modification

Très simple, même chose que l’immutabilité

Même problèmes que l’immutabilité (surcoût copie, GC)

Fonctionne bien pour structures à faible modification

Copy On Write

Page 17: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Meilleur exemple dans JDK: CopyOnWriteArrayList

Parfait pour les listes de listeners

Autre usage interne: CopyOnWriteHashMap

Maps de référence

Copy On Write

Page 18: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Lock striping

Page 19: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Réduire la contention en la distribuant

N’enlève pas de locks, mais en ajoute !

Efficacité dépend d’un bon partitionnement (cf HashMap)

Lock striping

Page 20: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Meilleur exemple dans JDK: ConcurrentHashMap [JDK7]

Lock striping

Page 21: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Relativement simple à implémenter

Peut être très efficace si bon partitionnement

Peut être affiné (nombre de partitions) en fonction de la contention/niveau de concurrence

Lock striping

Page 22: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Compare-And-Swap

Page 23: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Primitive pour n’importe quel algorithme Lock-Free

Utilisé pour implémenter locks et primitives de synchronisations

Géré directement par le CPU (instruction dédiée)

Compare-And-Swap

Page 24: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Met à jour de façon atomique un emplacement mémoire par une valeur si la précédente est celle attendue

instruction à 3 arguments:•adresse mémoire (rbx)•valeur attendue (rax)•nouvelle valeur (rcx)

Compare-And-Swap

movabs rax,0x2a movabs rcx,0x2b lock cmpxchg QWORD PTR [rbx],rcx

Page 25: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Compare-And-Swap

Page 26: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

En Java pour les classes AtomicXXX :

L’adresse mémoire est le champ value de la classe

Compare-And-Swap

boolean compareAndSet(expect, update)

Page 27: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Incrément atomique avec CAS[JDK7] getAndIncrement():

[JDK8] getAndIncrement():

“intrinsèquifier”:

Compare-And-Swap: AtomicLong

while (true) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return current; }

return unsafe.getAndAddLong(this, valueOffset, 1L);

movabs rsi,0x1 lock xadd QWORD PTR [rdx+0x10],rsi

Page 28: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Echange atomique avec CAS[JDK7] long getAndSet(long newValue):

[JDK8] long getAndSet(long newValue):

“intrinsèquifier”:

Compare-And-Swap: AtomicLong

while (true) { long current = get(); if (compareAndSet(current, newValue)) return current; }

return unsafe.getAndSetLong(this, valueOffset, newValue);

xchg QWORD PTR [rsi+0x10],rdi

Page 29: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

ReentrantLock est implémenté avec CAS

Si CAS échoue => Lock déjà acquis

Compare-And-Swap: lock

volatile int state;

lock() compareAndSet(0, 1);

unlock(): setState(0);

Page 30: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

L’algorithme lock-free le plus simple

Utilise CAS pour mettre à jour le pointeur suivant dans la liste chainée

Si CAS échoue, une mise à jour concurrente a eu lieu

Lire la nouvelle valeur, aller à l’élément suivant et renouveler le CAS

Compare-And-Swap: ConcurrentLinkedQ

Page 31: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Compare-And-Swap: ConcurrentLinkedQ

Page 32: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Compare-And-Swap: ConcurrentLinkedQ

Page 33: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Compare-And-Swap: ConcurrentLinkedQ

Page 34: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Compare-And-Swap: ConcurrentLinkedQ

Page 35: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Modèle Mémoire Java(Introduction)

Page 36: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Premier langage à avoir un modèle mémoire bien défini:Java JDK5 (2004) avec le JSR 133

C++ obtient le sien en 2011 (C++11)

Avant cela, certaines constructions sont non définies ou différentes en fonction de la plateforme/compilateur (ex : Double Check Locking)

Modèle Mémoire Java

Page 37: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Ordonnancement mémoire int a; int b; boolean enabled;

{ { a = 21; enabled = true; b = a * 2; a = 21; enabled = true; b = a * 2; } }

JIT Compiler

Page 38: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Ordonnancement mémoire int a; int b; boolean enabled;

Thread 1 Thread 2 { { a = 21; if (enabled) { b = a * 2; int answer = b; enabled = true; process(answer); } } }

Page 39: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Ordonnancement mémoire int a; int b; volatile boolean enabled;

Thread 1 Thread 2 { { a = 21; if (enabled) { b = a * 2; int answer = b; enabled = true; process(answer); } } }

Page 40: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Peut être à 2 niveaux: Compilateur & Hardware

En fonction de l’architecture du CPU, la barrière n’est pas forcément requise

x86: Modèle fort, réordonnancement limité

Barrière Mémoire

Page 41: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Barrière mémoire

Page 42: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Champ volatile implique des barrières mémoires

Barrière compilateur : empêche réordonnancement

Barrière matérielle : S’assure que les buffers sont vidés

Sur x86, seule la barrière d’écriture est nécessaire

Barrière mémoire: volatile

lock add DWORD PTR [rsp],0x0

Page 43: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

CAS est aussi une barrière mémoire

Compilateur : Reconnu par le JIT (Unsafe)

Matérielle : toutes les instructions lock agissent comme une barrière mémoire

Barrière mémoire: CAS

Page 44: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

blocs synchronized ont aussi des barrières mémoires

Entrée du bloc: Barrière mémoire de lecture

Sortie du bloc: Barrière mémoire d’écriture

Barrière mémoire: synchronized

synchronized (this) { enabled = true; a = 21; b = a * 2; }

Page 45: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Méthode des classes AtomicXXX

Barrière mémoire seulement pour le compilateur

Pas de barrière mémoire matérielle pour l’écriture

Garantit toujours l’ordonnancement, mais l’effet ne sera pas immédiat pour les autres threads

Barrière mémoire: lazySet

Page 46: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Ce qu’il faut retenir

Page 47: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Mesurer

Copier

Distribuer

Mettre à jour atomiquement

Ordonner

Ce qu’il faut retenir

Page 48: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

A suivre...

Page 49: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @jpbempel#LockFree

Disruptor & Ring Buffer

wait/notify – await/signal

Attente active (Spinning)

Queues lock-free (JCTools)

Ticketage : OrderedScheduler

A suivre dans la 2ème partie

Page 50: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree

Références•jucProfiler: http://www.infoq.com/articles/jucprofiler•Java Memory Model Pragmatics: http://shipilev.net/blog/2014/jmm-pragmatics/

•Memory Barriers and JVM Concurrency: http://www.infoq.com/articles/memory_barriers_jvm_concurrency

•JSR 133 (FAQ): http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html

•CPU cache flushing fallacy: http://mechanical-sympathy.blogspot.fr/2013/02/cpu-cache-flushing-fallacy.html

•atomic<> Weapons: http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2

Page 51: Programmation lock free - les techniques des pros (1ere partie)

@jpbempel#LockFree @YourTwitterHandle@YourTwitterHandle@jpbempel#LockFree

Q & A

UllinkArchitecte Performance@jpbempelhttp://[email protected]