[Pereira ic'2011] explorando o paralelismo no nível de threads
Escape Analysis for Java: Identifying Objects with Limited Lifetimes
1. Escape Analysis for
Java
Jong-Deok Choi, Manish Gupta, Mauricio Serrano, Vugranam C.
Sreedhar, Sam Midkiff
IBM T.J. Watson Resarch Center
OOPSLA’99 11/99, Denver, CO, USA
MO615 – Marcio Machado Pereira
2. Escape Analysis for Java [1]
Em Java:
Objetos são alocados no heap e só podem ser
dealocados pelo GC;
Objetos tem associado a eles um objeto “lock”
usado para garantir a exclusão mútua quando um
método ou ação de sincronização é invocado.
Overhead no desempenho.
3. Escape Analysis for Java [2]
Escape analysis no contexto de Java:
Determina se um objeto “escapa” ou não o método
que o criou (i.é., o objeto é local ao método ou não)
Aplicações:
Objeto pode ser alocado na pilha (stack frame) do
método que o criou;
Alocação na pilha é mais barata do que no heap;
Reduz overhead do GC.
4. Escape Analysis for Java [3]
Escape analysis no contexto de Java:
Determina se um objeto “escapa” a thread que o
criou (i.e., outras threads podem acessar o objeto).
Aplicações:
Pode-se eliminar os mecanismos de sincronização
associado ao objeto que não escapa a thread;
Objeto pode ser alocado na memória do processador
onde a thread foi agendada (scheduled), melhorando a
localidade do dado.
5. Escape Analysis for Java [4]
Choi et al. introduziram um novo framework para
Escape analysis baseado em uma abstração do
programa chamada de Connection Graph (CG).
Connection Graph captura a relação de
conectividade entre os objetos alocados no heap e as
referencias a estes objetos
A DFA simplesmente realiza uma análise de alcance
(reachability analysis) no CG para determinar se um
objeto é local a um método ou local a uma thread.
6. Escape Analysis for Java [5]
CG pode ser sumarizado para cada método de
forma que a mesma informação pode ser
usada eficientemente em diferentes contextos
de chamada (calling contexts).
Choi et al. apresentaram um algorítmo
interprocedural que usa a propriedade de
sumarização para computar de forma eficiente
o CG e identificar objetos que não escapam
métodos ou threads.
7. Escape de um Objeto [1]
Seja O uma instância de um objeto e M a invocação de
um método. O escapa M, denotado por Escapes (O,M),
se o tempo de vida de O exceder o tempo de vida de M.
Um objeto O é alocavel na pilha (stack-allocatable) de
M se ¬Escapes (O,M)
Seja O uma instância de um objeto e T uma thread
(instância). O escapa T, denotado por Escapes (O,T), se
outra thread T' ≠ T, puder acessar O.
Um objeto O é local a uma thread T se ¬Escapes (O,T)
8. Escape de um Objeto [2]
Proposição:
Para todo objeto O, onde o método M é invocado na
thread T:
¬Escapes (O,M) ⇒ ¬Escapes (O,T)
Intuitivamente:
“Um objeto cujo tempo de vida é limitado pelo tempo de
vida do método que o invocou, só pode ser acessado por
uma única thread”.
9. Connection Graph [1]
CG = ( No U Nr U Nf U Ng, Er U Ed U Ef )
No – representa o conjunto de objetos
Nr – variáveis de referência (locais e formais)
Nf – fields não estáticos
Ng – fields estáticos (variáveis globais)
Er – arestas “point-to”
x → y ∈ Er ⇒ x ∈ Nr U Nf U Ng & y ∈ No
Ed – arestas deferred (diferidas)
x → y ∈ Ed ⇒ x, y ∈ Nr U Nf U Ng
Ef – arestas field
x → y ∈ Ef ⇒ x ∈ No & y ∈ Nf U Ng
10. Connection Graph [2]
Representa uma aresta “point-to” do nó x para o nó y
Representa uma aresta deferred (diferida) do nó x para o nó y
Representa uma aresta field do nó x para o nó y
11. Idéia Básica do Escape Analysis
Escapement Lattice: NoEscape < ArgEscape < GlobalEscape
ArgEscape – objeto escapa o método via argumentos, mas não escapa a thread
GlobalEscape – objeto escapa globalmente (i.e., todas as threads e métodos)
Seja CG o grafo de conexão do método M e seja O um nó objeto em
CG. Se O pode ser alcançado em CG por algum nó cujo estado é
diferente de NoEscape, então O escapa M.
Após DFA todos os objetos marcados como NoEscape são
alocáveis na pilha (stack-allocatable) e todos os objetos marcados
como NoEscape ou ArgEscape são locais à thread e, portanto, as
operações de sincronização podem ser eliminadas sem violar a
semântica do programa.
12. Análise Intraprocedural [1]
DFA forward, disjuntiva:
fs é a função de transferência e Meet ( Λ ) = U, i.e.
Se C1 = (N1, E1) e C2 = (N2, E2) então C1 Λ C2 = (N1 U N2, E1 U E2)
Para cada nó n ∈ N, associa-se um estado de Escape:
Ng – inicializado como GlobalEscape
No U Nr U Nf – inicializado como NoEscape
Associa-se a cada field f de um objeto um identificador único fid(f) que
corresponde ao offset de f na classe que define o objeto. Isto posto, se O1 e O2,
são 2 objetos da mesma classe C, então fid(O1.f) = fid (O2.f)
13. Análise Intraprocedural [2]
Dado um nó de referencia m ∈ Nr U Nf U Ng, o conjunto de nós objetos
O ⊆ Νο que m “aponta para” (point-to) é determinado percorrendo as
aponta ( )
arestas diferidas a partir de m até visitarmos a primeira aresta point-to no
caminho. Formalmente:
onde é uma sequência de arestas
que termina em exatamente uma aresta “point-to”
14. Análise Intraprocedural [3]
ByPass
A função ByPass (p) quando aplicada ao nó p ∈ Nr U Nf redireciona as arestas
diferidas incidentes em p aos nós sucessores de p
Formalmente, sejam:
ByPass (p) remove as arestas do conjunto:
e adiciona as arestas no conjunto:
15. Análise Intraprocedural [4]
Transfer functions (4 ações afetam o Escape Analysis):
p = new r ();
Cria o nó objeto O (se não existir)
(Flow-Sensitive) → aplica ByPass (p)
(Flow-Sensitive/Insensitive) → adiciona aresta “point-to” de p para O
p = q;
(Flow-Sensitive) → aplica ByPass (p)
(Flow-Sensitive/Insensitive) → adiciona aresta
16. Análise Intraprocedural [5]
p.f = q;
Faça U = PointsTo (p)
Se U = Ø então ou p = null (null pointer exception) ou o objeto para o qual
p aponta foi criado fora do método (p é um parâmetro formal ou alcançável por
um parâmetro formal). Conservativamente, cria-se um objeto fantasma Oph
(phantom object node) e insere-se a aresta p Oph
Faça V = { v| u v, u,v ∈ U & fid(v) = f }
Se V = Ø cria-se um nó field e adiciona-se a V
Finalmente, adiciona-se arestas {v q | v ∈ V}
17. Análise Intraprocedural [6]
p = q.f;
Faça U = { u | q u },
V={v|u v, u ∈ U & fid (v) = fid (f) }
Se U = Ø então cria-se um phantom object e adiciona-se a U.
V = Ø então cria-se um field reference e adiciona-se a V
(Flow-Sensitive) → Aplica-se ByPass (p)
(Flow-Sensitive/Insensitive) → Adiciona-se arestas { p v|v∈V}
19. Análise Interprocedural [1]
Vamos assumir que um método A chama outro método B. Então,
Se método B já foi analisado pelo Escape Analysis então, quando for feito a
análise intraprocedural de A este simplesmente usa uma informação sumarizada
de B.
Usa-se o Program Call Graph para representar a relação Caller – Callee.
Uma vez que Java suporta métodos virtuais usa-se a informação de tipo para
refinar o Call Graph.
4 pontos são relevantes na análise interprocedural:
Entrada do método B
Saída do método B
Imediatamente antes da invocação do método B
Imediatamente após a invocação do método B
20. Análise Interprocedural [2]
No exemplo abaixo o método L() constrói uma lista ligada e o método T() constrói uma
estrutura em árvore. A figura ao lado mostra a relação Caller-Callee para o programa
exemplo:
22. Análise Interprocedural [4]
Connection Graph na entrada do método:
Para cada parâmetro formal fi, existe um parâmetro real ai no Caller, que produz
o valor para fi.
No ponto de entrada do Callee cria-se então uma atribuição da forma fi = ai
fi é tratado como uma variável local dentro do método, então ela pode ser morta
(killed) por outras atribuições a fi. Cria-se então um nó de referência phantom para
ai e insere uma aresta diferida de fi para ai .
Os estados de fi e ai são inicializados como:
EscapeState [ fi ] = NoEscape
EscapeState [ ai ] = ArgEscape
23. Análise Interprocedural [5]
Connection Graph na saída do método:
Modela-se a ação return que retorna uma referência a um objeto como uma
atribuição a uma variável especial phantom chamada return.
Multiplas ações de retorno são resolvidas no CG executando o “merge” dos
respectivos valores return.
Após completar o Escape Analysis intraprocedural para um método usa-se a
função ByPass para eliminar todas as arestas diferidas no CG, criando nós
phantom onde forem necessários. É o caso do nó R para o exemplo:
24. Análise Interprocedural [6]
Connection Graph na saída do método:
Ao final, faz-se a análise de alcançe (reachability analysis) no CG para atualizar
os estados de Escape dos objetos. Esta análise particiona o grafo em três
subgrafos:
1. Subgrafo induzido Sg do conjunto de nós que são “alcançaveis” a partir de um
nó GlobalEscape (inicialmente, static fields e objetos runnable).
2. Subgrafo induzido Sa do conjunto de nós “alcançaveis” a partir de um nó
ArgEscape (inicialmente, nós de referência phantom que representam os
parâmetros reais criados na entrada do método, como a1 e a2 no exemplo.
3. Subgrafo induzido Sn do conjunto de nós que não são alcançaveis por
nenhum nó GlobalEscape ou ArgEscape.
Então:
Sg U Sa ≅ NonLocalGraph (representa CG sumarizado do método)
Sn ≅ LocalGraph (todos os objetos são marcados stack-allocatable)
27. Análise Interprocedural [9]
Connection Graph imediatamente antes da invocação do método:
A passagem de parâmetros é tratada como uma atribuição ao parâmetro real no
chamador. A chamada u1.foo (u2, u3, ..., un) é modelada como:
Cada parâmetro no local da chamada será comparado com o nó de referência
phantom do método chamado. No exemplo, 2 nós â1 e â2 são criados como
arestas diferidas apontando para o 1º e 2º parâmetros reais da chamada, u e v,
respectivamente.
28. Análise Interprocedural [10]
Connection Graph imediatamente após a invocação do método:
Faz-se o mapeamento das informações contidas no CG sumarizado do método
chamado de volta para o CG do chamador.
Três tipos de nós desempenham um papel importante na atualização do CG, âi's
do caller's CG, ai's do callee's CG e o nó return.
Relações de mapeamento MapsToObj ( ↦ ) para atualização dos nós:
29. Análise Interprocedural [11]
Connection Graph imediatamente após a invocação do método:
A atualização das arestas é feita da seguinte maneira. Sejam p e q objetos do
Callee’ CG tal que:
32. Resultados Experimentais
Protótipo → IBM High Performance Compiler for Java.
Target → PowerPC 333Mhz, 128MB
no de objetos que puderam ser alocados na pilha
excedeu 70% dos objetos criados dinamicamente
em 3 de 10 benchmarks (com a mediana em 19%)
11% a 92% de todas as operações de lock foram
eliminadas nos 10 programas (com a mediana em
51%)
A redução no tempo de execução foi de 2% a 23%
(com a mediana em 7%)
33. Escape Analysis x Points-to Analysis
Connection Graph (CG) → Escape Analysis
Points-to Graph (PG) →Pointer-induced Alias Analysis
CG e PG são abstrações de estruturas de dados
dinâmica com ponteiros ou referencias.
Alias Analysis → desambiguação de memória
PG mesmo nó se duas referencias apontam para o
mesmo objeto
Escape Analysis → identificar objetos que escapam o
escopo (dinâmico) do método ou da thread que o invocou.
CG permite diferentes nós referenciando o mesmo
objeto (pode ignorar o contexto de chamada).
34. Histórico e Trabalhos relacionados
Analises do tempo de vida de objetos alocados dinâmicamente tem sido
tradicionalmente usadas para gerenciar o espaço de armazenamento em
tempo de compilação.
Park & Goldeberg[2] introduziram o termo Escape Analysis em
linguagens funcionais para determinar estaticamente quais partes de uma
lista passada para uma função não escapa a chamada da função. Outros
melhoraram e estenderam o trabalho de Park & Goldeberg.
Birkedal et al. propuseram um modelo de alocação baseado em regiões
que são gerenciadas durante a compilação.
Tem havido uma série de esforços paralelos em Escape Analysis para
Java. Bogda & Holzle[3] usam um conjunto de restrições para computar
objetos locais às threads.
Blanchet[4] atribui “pesos” a tipos para codificar como um objeto de um
tipo pode ter referências a outros objetos ou é um subtipo de outro objeto.
Ele propõe uma analise flow-insensitive em duas fases (backward e forward)
para computar as informações de Escape..
35. Referências
[1] Jong-Deok Choi, M. Gupta, M. Serrano, V.C. Sreedhar and S. Midkiff. Escape
Analysis for Java. In Proceedings of ACM SIGPLAN Conference on Object-
Oriented Programming Systems, Languages and Applications, Denver, Colorado,
November 1999.
[2] Y.G. Park and B. Goldberg. Escape analysis on lists. In Proceedings of. ACM
SIGPLAN Conference Programming Language Design and Implementation, pages
117-127, July 1992.
[3] Jeff Bodga and Urs Holzle. Removing unnecessary synchronization in java. In
Proceedings of ACM SIGPLAN Conference on Object-Oriented Programming
Systems, Languages and Applications, Denver, Colorado, November 1999.
[4] Bruno Blanchet. Escape Analysis for object-oriented languages: Applications to
Java. In Proceedings of ACM SIGPLAN Conference on Object-Oriented
Programming Systems, Languages and Applications, Denver, Colorado, November
1999.