Guido Araujo (IC-UNICAMP) email: [email protected]Alexandro Baldassin (IGCE-UNESP) email: [email protected]Blue Gene/Q Programação Paralela usando Memórias Transacionais: da Academia à Indústria IV Escola Regional de Alto Desempenho de São Paulo julho de 2013
144
Embed
Guido Araujo (IC-UNICAMP) email: [email protected] Alexandro Baldassin (IGCE-UNESP)
Programação Paralela usando Memórias Transacionais : da Academia à Indústria. IV Escola Regional de Alto Desempenho de São Paulo j ulho de 2013. Guido Araujo (IC-UNICAMP) email: [email protected] Alexandro Baldassin (IGCE-UNESP) e mail: [email protected]. Blue Gene/Q. Roteiro. - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
lock.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred = curr; curr = curr.next; } if (item != curr.key) { Node node = new Node(item); node.next = curr; pred.next = node; valid = true; } lock.unlock(); return valid;}
• Como melhorar a solução?• Sugestões?
32
Lista ordenada – locks finos
• Ideia• Associar um lock a cada nó da lista• Antes do conteúdo do nó ser acessado, adquirimos seu respectivo
lock (liberando-o após o acesso)
• Essa abordagem funciona?• Considere duas operações concorrentes para remoção dos itens
‘b’ e ‘a’, por duas threads distintas (T1 e T2)
33
Lista ordenada – locks finos
a b chead tail
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
T1
34
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
T1
35
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
T1
36
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
T1
37
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
T1
Assuma um “page fault” aqui!!
38
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
remove(a) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
T1 T2
39
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
remove(a) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
pred curr
T1 T2
40
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
remove(a) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
pred curr
T1 T2
Thread azul volta
41
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
pred curr
a b chead tail
remove(a) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
pred curr
T1 T2
Resultado?
42
remove(b) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
Lista ordenada – locks finos
a b chead tail
remove(a) ... head.lock(); pred = head; curr = pred.next; while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; pred.lock(); } if (item == curr.key) { pred.next = curr.next; valid = true; } pred.unlock(); return valid;}
T1 T2
“a” ainda ficou!!
43
Lista ordenada – locks finos
• Antes de alterar um nó, uma thread necessita adquirir as travas para o nó atual e o próximo
• Note que as threads envolvidas precisam adquirir os locks na mesma ordem para evitar o risco de deadlock
• Não é trivial provar a corretude!
• Exemplo de código para a operação de inserção ...
44
Lista ordenada – locks finos
public boolean add(int item) { boolean valid = false; head.lock(); Node pred = head; Node curr = pred.next; curr.lock(); while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; curr.lock(); } if (item != curr.key) { Node newNode = new Node(item); newNode.next = curr; pred.next = newNode; valid = true; } curr.unlock(); pred.unlock(); return valid;}
45
Lista ordenada – locks finos
public boolean add(int item) { boolean valid = false; head.lock(); Node pred = head; Node curr = pred.next; curr.lock(); while (curr.key < item) { pred.unlock(); pred = curr; curr = curr.next; curr.lock(); } if (item != curr.key) { Node newNode = new Node(item); newNode.next = curr; pred.next = newNode; valid = true; } curr.unlock(); pred.unlock(); return valid;}
Grande parte do código é específico para sincronização (6 de 18 linhas = ~33%)
46
Problemas com lock finos
• Risco alto de deadlock• Diferentes locks adquiridos em diferentes ordens
• Operações lock e unlock custosas• Geralmente envolvem alguma forma de syscall
• Dificuldade relacionada a engenharia de software• Como encapsular um método com locks?• Como compor código?
47
Composição de código com locks
• Imagine que nossa aplicação precise utilizar as operações da lista ligada para implementar uma outra operação de nível mais alto, como mover um elemento de uma lista para outra
• Não temos acesso ao código fonte• Apenas sabemos que cada operação é atômica
public boolean move(List new, List old, int item) { old.remove(item); new.add(item);}
48
Composição de código com locks
• Imagine que nossa aplicação precise utilizar as operações da lista ligada para implementar uma outra operação de nível mais alto, como mover um elemento de uma lista para outra
• Não temos acesso ao código fonte• Apenas sabemos que cada operação é atômica
public boolean move(List new, List old, int item) { old.remove(item); new.add(item);}
Atômico?
49
Composição de código com locks
• Colocar um lock global?public boolean move(List from, List to, int item) { newlock.lock(); from.remove(item); to.add(item); newlock.unlock();}
Funciona?
E se ocorrer busca(item,from) em outra thread neste ponto?
50
Composição de código com locks
• Colocar um lock global?
• Esta solução requer que todas as operações atômicas da lista sejam envoltas pelo novo lock
• Uma solução alternativa seria quebrar o encapsulamento e expor a implementação da lista (quais locks foram usados)
public boolean move(List from, List to, int item) { newlock.lock(); from.remove(item); to.add(item); newlock.unlock();}
51
Composição de código com locks
• Cada lista expõe seu lock global
• Esta solução funciona?
public boolean move(List from, List to, int item) { from.lock(); to.lock(); from.remove(item); to.add(item); from.unlock(); to.unlock();}
52
Composição de código com locks
• Cada lista expõe seu lock global
• Esta solução funciona?
public boolean move(List from, List to, int item) { from.lock(); to.lock(); from.remove(item); to.add(item); from.unlock(); to.unlock();}
antigo armazenado em buffer)• Efetivação rápida, mas cancelamento lento
• Deferido (lazy/optimistic/deferred)• Armazena atualização em buffer interno• Cancelamento rápido, mas efetivação lenta
70
Versionamento imediato
71
Versionamento imediato
72
Versionamento imediato
73
Versionamento imediato
74
Versionamento deferido
75
Versionamento deferido
76
Versionamento deferido
77
Versionamento deferido
78
Isolamento da execução
• Detecção de conflitos• Usa-se dois conjuntos:
• Read set: dados lidos • Write set: dados escritos
• Conflito se há intersecção entre o conjunto de leitura e escrita de transações diferentes
• Resolução de conflitos• Depende do gerenciador de contenção• Exemplo: abortar imediatamente, esperar, ...• Importante para garantir progresso
79
Formas de detecção de conflitos
• Adiantado (eager/pessimistic/encounter-time)• Ocorre no momento dos acessos ao dados• Pode evitar executar código desnecessário• Mais suscetível a livelock
• Tardio (lazy/optimistic/commit-time)• Ocorre na efetivação da transação• Potencialmente menos conflitos• Menos suscetível a livelock, porém starvation pode ser
um problema
80
Detecção de conflitos adiantado
81
Detecção de conflitos adiantado
82
Detecção de conflitos adiantado
83
Detecção de conflitos adiantado
84
Detecção de conflitos tardio
85
Detecção de conflitos tardio
86
Detecção de conflitos tardio
87
Detecção de conflitos tardio
PARTE 2Implementação em STM e HTM
89
Implementação de TM
• O suporte transacional pode ser realizado em hardware, software ou uma mescla de ambos (híbrido)
• Hardware (HTM)• Melhor desempenho• Problemas com virtualização (espaço, tempo)
• Software (STM)• Desempenho depende muito da aplicação• Extremamente flexível• Ideal para testar novas ideias
90
STM – Suporte
• Interface• API básica
• start, commit, barreiras de leitura e escrita• Object vs word
• Duas formas principais de implementação• Non-blocking• Blocking
• As implementações possuem diferentes garantias de progresso e consistência
91
STM – Shavit & Touitou (1995)
PODC’95
92
STM – Shavit & Touitou (1995)
• Cunhou o termo “software transactional memory” (STM)
• Transações eram “estáticas”• Uma transação precisa especificar, de forma antecipada, um vetor
com as posições de memória que serão acessadas
• Basicamente um CAS múltiplo
• A implementação, non-blocking, influenciou as novas propostas que surgiriam em seguida
93
DSTM – Herlihy et al. (2003)
PODC’03
94
DSTM – Herlihy et al. (2003)
• Definitivamente desencadeou a pesquisa em STM (junto com Harris & Fraser – OOPSLA 2003)
• Granularidade: objetos
• Detecção de conflitos adiantada/versionamento deferido
• Implementação é obstruction-free• Gerenciador de contenção é responsável por garantir progresso
95
Rob Ennals (2005, 2006)
• Motivado pelo baixo desempenho de implementações non-blocking, Rob Ennals propôs implementar sistemas STM baseados em locks
• Efficient Software Transactional Memory (2005)• “This paper described how software transactional memory could be made more efficient if
one was prepared to sacrifice non-blocking properties. It was rejected from SPAA, but was widely circulated and was fairly influential on the design of subsequent STM implementations.”
• Software Transactional Memory Should Not Be Obstruction-Free (2006)
• “This paper was submitted to SCOOL 2005, but was deemed to be "too controversial for publication" and so was instead made the topic of a panel instead.”
96
Lock-based STMs
• A ideia de Ennals gerou bastante controvérsia• Até então acreditava-se que as implementações deveriam ser non-
blocking por questões de garantia de progresso
• Ennals argumentou que o sistema runtime de linguagens modernas podem controlar o escolamento das threads, evitando o problema de preempção
• As principais implementações (mais rápidas) de STM atuais são blocking
97
TL2 – Dice et al. (2006)
DISC’06
98
TL2 – Dice et al. (2006)
• Principal representante de uma classe de implementações que adotam locks
• Granularidade: principalmente palavras
• Locks para escrita adquiridos durante fase de commit
ReadTx(endereco, valor)1. se (endereco em cjtEscrita) retorna cjtEscrita[endereco].valor2. v1 = ORT[hash(endereco)]3. valor = memoria[endereco]4. v2 = ORT[hash(endereco)]5. se (v1.lock travado || v1 != v2 || v1.versao > txdsc.versao)6. aborta transacao 7. cjtLeitura.insere(endereco)8. retorna valor
109
TL2 – Funcionamento
GCLOCK
descritor transação (txdsc)
status versão
conjunto de leitura (cjtLeitura)
conjunto de escrita (cjtEscrita)
endereço
endereçovalor
..
.
ORT
ORT-address = hash(endereço)CommitTx(endereco, valor)1. trava elementos em CjtEscrita2. incrementa GCLOCK (+2)3. valida CjtLeitura4. atualiza memória com valores no CjtEscrita5. destrava CjtEscrita e atualiza versao na ORT
Memória Compartilhada
110
TL2 – Características
• Contenção em GCLOCK pode ser tornar crítico para um número muito grande de transações concorrentes
• Implementação cuidadosa• Deve evitar deadlock
• Commit-time locking (CTL) com versionamento tardio• Conflitos write-after-write (WAW) e read-after-write (RAW)
detectados de forma tardia
111
Novas lock-based STMs
• A maioria das STMs que surgiram depois usam o mesmo conceito de relógio global para garantir consistências (time-based STMs)
• Principais variações• Encounter-time locking (ETL) com versionamento tardio ou
adiantado, com extensão de versões• Tipos de conflitos (read-after-write, write-after-write) tratados de
formas diferentes
• Exemplos de STMs da mesma classe• TinySTM, SwisSTM
112
Críticas sobre STMs
Comm. ACM’08
Queue’08
113
Research toy
114
STM strikes back
Comm. ACM’11
115
STM strikes back
Comm. ACM’11
Autores argumentam que artigo anterior usou conjunto de aplicações/hardware inadequado
116
STM strikes back
117
Suporte transacional no GCC 4.7
• Suporte experimental a TM existe no GCC a partir da versão 4.7 (abril de 2012)• As construções adicionadas à linguagem são baseadas no
documento “Draft Specification of Transactional Language Constructs for C++”, versão 1.1
• http://gcc.gnu.org/wiki/TransactionalMemory
“The support is experimental. In particular, this also means that several parts of the implementation are not yet optimized. If you observe performance that is lower than expected, you should not assume that transactional memory is inherently slow; instead, please just file a bug.”
118
Construções GCC
• Principais construções• __transaction_atomic {…}• __transaction_relaxed {…}• __transaction_cancel
• Máquina: AMD Opteron• Taxa de atualização (UPD_RATE): 20%• Tamanho do conjunto: 100 elementos
1 2 4 80
2
4
6
8
10
12
14
16
18
Threads
Tem
po (s
)
122
Compondo código usando TM
• Movendo elemento de uma lista para outra
• Se list_remove e list_add forem definidos em outro arquivo, é necessário usar transaction_safe
void move(list_node_t *from, list_node_t *to, int val){ __transaction_atomic { if (!list_remove(from, val)) __transaction_cancel; list_add(to, val); }}
__attribute__((transaction_safe)) int list_add(list_node_t *head, int item);
123
Detalhes da geração e execução
• O compilador gera duas versões para cada rotina especificada com o atributo transaction_safe• A versão transacional é usada quando a rotina é chamada dentro
de uma transação
• O código gerado é linkado com uma biblioteca de runtime chamada libitm• Essa biblioteca pode ser substituída em tempo de execução
• Permite que diferentes implementações possam ser avaliadas de forma simples
• Especificação segue basicamente a ABI proposta pela Intel• Intel Transactional Memory Compiler and Runtime Application Binary
Interface, revisão 1.1 – maio de 2009
124
HTM – Suporte
• Interface• Conjunto de instruções do processador• Exemplo: Intel TSX
• Versionamento• Cache ou buffer de escrita
• Conflitos• Protocolo de coerência de cache (snoop ou diretório)• R/W bits adicionados à cache
125
HTM – Exemplo Execução
Versionamento e detecção de conflitos atrasados
126
HTM – Exemplo Execução
127
HTM – Exemplo Execução
128
HTM – Exemplo Execução
129
HTM – Exemplo Execução
130
HTM – Herlihy & Moss (1993)
ISCA’93
131
HTM – Herlihy & Moss (1993)
• Novas instruções (6)• ST, LT, LTX• COMMIT, VALIDATE, ABORT
• Cache transacional separada• Mantém os conjuntos de leitura e escrita da transação
• Protocolo de coerência• Baseado em snoop
132
Problemas com a abordagem
• Cache adicional (em paralelo com as de dado e instruções) complica bastante o projeto de processadores modernos• Estender cache de dados tornou-se mais popular (1 bit extra para
read, e outro para escrita especulativa)
• Nenhuma virtualização• E se a cache transbordar?
Slide adapted from Martin Ohmacht’s presentation at Workshop held at PACT 2011
Uma visão simplificada da organização lógica de um slice da L2 (32MB)
Tag128BData
ThreadID
SpeculativeBit
11…11
16K
16 ways
00…00Index
16K linhas x 16 ways x 128 Bytes = 32M Bytes
Diretório da L2
Para cada linha escrita especulativamente, o diretório armazena um id da thread que é a dona.
Quando ocorre um acesso a uma linha especulativa, o diretório compara a id da tread fazendo o acesso com a id da dona, e interrompe o thread mais jovem que está em conflicto.
Se o conflito é entre uma thread especulativa e um thread não especulativa, a thread especulativa é abortada.
Speedup com relação à execução sequential
143
• Memória Transacional veio para ficar como um novo paradigma de programação paralela
• Duas grandes empresas na área lançaram processadores contendo extensões para TMs (IBM e Intel)
• Boas oportunidades para realização de pesquisa!
• Se estiver interessado em fazer pesquisa entre em contato!!