• Nenhum resultado encontrado

4.3 Otimizações realizadas

4.3.4 Mudança de semântica de Unfolding e Unfold

Uma outra alteração que realizamos trouxe impactos na parte conceitual da má- quina original. Realizamos uma mudança na redução dos vértices Unfolding e Unfold. Após uma análise, identiĄcamos que o vértice unfold não é um vértice avaliável, porém é colocado como uma construção na gramática de PEWS. Isso pode fazer com que possamos especiĄcar uma construção da seguinte forma: unfold ; unfold. Não teriamos nenhuma semântica para avaliação de unfolds.

Sabendo dessa possibilidade, a partir deste momento, a avaliação do Unfolding irá criar uma cópia do grafo e atribuí-la a todos os seus unfolds relacionados sem colocá-la no grafo no momento da avaliação. Já a avaliação do vértice unfold consistirá em ex- pandir para o grafo a cópia que lhe foi atribuída. Criaremos um atributo especíĄco para vértices do tipo unfold, chamado copia, que guardará informações sobre vértices e ares-

tas, ou seja, ao nos referirmos a este atributo com a chamada unfold.copia, receberemos como resposta uma conĄguração hV, Ac, Adi. Utilizamos o símbolo ← como um símbolo de atribuição. A nova redução de vértices Unfolding é apresentada a seguir:

hhV[w : µ, w1 : unfoldw1, ..., wn: unfoldnw], Ac, Adi , ρ, I, O, M, TE, NM Ti, sendo

Gw = hVw, Aw c, Awdi =⇒ DD V[w1 : unfoldw1, ..., wn : unfoldwn], Ac, Ad E , ρ, I, O, M, TE, NM T E , sendo wi.copia ← Gw, com 1 ≤ i ≤ n, Ac = Ac/{w 7→ y | y ∈ V }

Na conĄguração inicial, temos um vértice w que é do tipo Unfolding (µ). Além disso, temos n vértices do tipo unfold, identiĄcados por w1 a wn. EspeciĄcamos que estes vértices estão relacionados ao vértice Unfolding através da identiĄcação sobrescrita w. Além disso, especiĄcamos o grafo G, que é o grafo formado pelos vértices (e arestas relacionadas) que encontram-se dentro do âmbito do Unfolding, ou seja, os vértices a serem copiados. Na redução, o que fazemos é excluir o vértice w : µ do conjunto dos vértices principais (assim como suas arestas de controle, visto que este vértice não possui arestas de dependência para nenhum outro vértice), criar uma cópia do grafo G para cada vértice unfoldw

i e atribuí-la ao parâmetro unfold.copia.

Já na redução de vértice unfold, temos a seguinte conĄguração: hhV[w:unf old], Ac, Adi , ρ, I, O, M, TE, NM Ti, sendo

w.copia= hVw, Aw c, Awdi =⇒ DD V ∪ Vw, Ac∪ AwcΔ, Ad∪ Awd E , ρ, I, O, M, TE, NM T E , onde Ac = Ac/{w 7→ y | y ∈ V }, Δ = {x 7→ y |x ∈ Vw,!∃z.x 7→ z, y ∈ V, w 7→ y }

IdentiĄcamos inicialmente apenas o vértice w:unfold. Além disso, referimo-nos ao parâmetro unfold.copia como sendo hVw, Aw

c, Awdi, uma cópia atribuída a este parâmetro por algum vértice unfold anteriormente reduzido. Na redução, retiramos o vértice unfold e suas arestas. Além disso, o subgrafo associado ao parâmetro copia é colocado diretamente no grafo (vértices, arestas de controle e arestas de dependência). Por Ąm, acrescentamos à máquina de redução o parâmetro Δ. Este parâmetro acrescenta arestas que saem dos vértices de Vw que não possuem Ąlhos (!∃z.x 7→ z) para os vértices aos quais o unfold

4.4. Vizualização de Transformações e Reduções 83 tinha arestas de controle (y ∈ V, w 7→ y). Em outras palavras, substituimos o vértice unfold pela cópia relacionada.

4.4 Vizualização de Transformações e Reduções

A otimização realizada pela geração do arquivo texto trouxe ganhos consideráveis, pois temos a noção da situação detalhada dos vértices e da máquina a cada vez que uma redução é realizada. Porém, quando se trabalha com composições extensas, é difícil ter uma noção das ligações entre as arestas de controle e dependência dos vértices. Dessa forma, neste trabalho, tivemos também o objetivo de dar uma noção dos estados da composição após cada ação realizada através de uma estrutura gráĄca, gerada a partir de informações da composição. A implementação de estruturas que Ązessem essa geração gráĄca teria um esforço muito grande e não seria um dos focos principais deste trabalho. Portanto, decidimos procurar uma ferramenta na qual pudéssemos fazer uma integração entre o ambiente da máquina de redução e esta ferramenta.

Utilizamos a ferramenta GraphViz [13], que consiste numa variedade de softwares para desenhar grafos, implementando um extenso conjunto de linguagens para geração de imagens, sendo elas: dot [38], neato [14], fdp [12], sfdp [15], circo [36], entre ou- tros. Como trabalhamos com grafos direcionados, utilizaremos a linguagem dot. Além da linguagem, é preciso obter qualquer versão do GraphViz e instalá-la no computador. No anexo deste documento, mostraremos alguns detalhes de utilização do GraphViz. Veremos a seguir como sua utilização beneĄciará a vizualização de grafos na geração e execução de composições de serviços.

4.4.1

Uso do GraphViz na Máquina de Redução Estendida

A integração da máquina de redução com o GraphViz ocorre da seguinte forma: a cada passo da redução, geramos um arquivo texto. Para a geração deste arquivo, pegamos a situação atual do ambiente e transformamos numa estrutura padrão entendida pelo

GraphViz. Em seguida, fazemos a compilação deste arquivo texto e geramos a situação

atual do grafo em forma de imagem.

Em termos de código Java, criamos uma classe especíĄca para geração do arquivo texto. A mesma está presente no pacote pews.main, sendo denominada GeradorFiguras. Esta classe contém dois atributos:

• contFiguras Ű Geramos um arquivo de imagem para cada situação da máquina. Por isso, precisamos ter nomes de arquivos diferentes, para vizualizarmos a sequência de redução. Sendo assim, utilizamos o parâmetro contFiguras para gerar nomes diferentes de arquivos através de identiĄcação numérica progressiva. Os nomes dos

arquivos gerados tem sempre o padrão: Siti.dot, onde 1 ≤ i ≤ n, sendo n o número de Ąguras geradas pela execução da composição.

• contClusters Ű Da mesma forma que vários arquivos de imagem precisam ter nomes diferentes, algumas estruturas (pilhas de chamadas e subcomposições) precisam ter uma identiĄcação única. Utilizaremos clusters para representar essas estruturas, onde, assim como o atributo anterior, os nomes dos clusters gerados tem o padrão clusteri, onde 1 ≤ i ≤ n;

A classe contém diversos métodos utilizados para gerar as Ąguras. Os principais métodos são:

• GeradorFiguras Ű Construtor da classe, que apenas tem a função de setar o pa- râmetro contFiguras com o valor inicial sendo 1;

• nomeVerticeImpressao Ű Esta classe é utilizada para atribuir características aos vértices. A identiĄcação do vértice será sempre o seu identiĄcador único do Java, ou seja, seu hashcode. Os vértices simples tem a seguinte identiĄcação padrão (con- sideraremos o número 123456 como id do vértice de todos os exemplos):

Ű Entrada de serviço (S! ¯E) Ű 123456 [label= "S! ¯E"];

Ű Saída de serviço (S? ¯X) Ű 123456 [label= "S? ¯X"];

Ű Escolha (+) Ű 123456 [label= "+",shape=diamond]; Ű Repetição (Mu) Ű 123456 [label= "Mu"];

Ű Unfold Ű 123456 [label= "Unfold"]; Ű Sync Ű 123456 [label= "Sync"];

Ű Expressão (Expr) Ű 123456 [label= "Expr",shape=box];

Mostramos abaixo um exemplo da descrição padrão para pilhas de chamadas e pilha de subcomposições (utilizaremos apenas a identiĄcação de pilhas de subcom- posições): subgraph cluster0 { vertice1 [atributos]; vertice2 [atributos]; ... verticen [atributos]; label="Pilha de Subcomposições" }

4.4. Vizualização de Transformações e Reduções 85 Um detalhe a ser observado é que, na escrita de pilhas de chamadas e pilhas de sub- composições, identiĄcamos também os vértices que fazem parte dos mesmos. Como sabemos, as pilhas são vértices que contém outros vértices internamente. Sendo as- sim, precisamos descrever os mesmos dentro dos clusters referentes às pilhas, para que eles apareçam internamente no momento da geração da Ągura. Essa descrição é feita dentro desta função.

• gerarGraĄcos Ű É a função principal da classe, que é chamada no momento em que é solicitada uma geração de imagem do grafo. Esta função recebe como parâmetro todos os vértices do ambiente (represntado por todosOsVertices) e um conjunto de atributos a serem colocados nos vértice (cores, formas, etc). Todas as vezes que a função é chamada, criamos um novo arquivo para nomear a imagem gerada, cujo padrão de nomes é Siti, onde é i referencia o parâmetro contFiguras, citado anteriormente.

Até agora, apenas criamos o arquivo e inserimos o texto. Precisamos fazer a inte- gração com o GraphViz para geração das imagens. O GraphViz tem uma interface que permite a geração da imagem apenas com a escrita do arquivo, porém, com o arquivo gerado, podemos fazer essa geração através de linha de comando. Sendo as- sim, com o arquivo gerado, criamos uma instância de um terminal dentro do código java através da classe Runtime. Supondo que o executável dot.exe é uma variável de ambiente e que estamos dentro da pasta, executamos o seguinte comando utilizando runtime.exec() (considerando que o arquivo gerado tenha o nome Siti):

dot Siti -Tgif -Kdot -Tplain

Tendo visto os atributos e métodos da classe geradorFiguras, veremos os tipos de Ąguras geradas. No momento da geração da primeira imagem do grafo, os vértices serão gerados segundo mostrado na Ągura 32.

Como podemos observar, todos os vértices são impressos como uma elipse, que é o tipo padrão. Dos vértice simples, diferenciamos apenas o vértice de escolha (mostrado como um losango) e o vértice que representa expressões (mostrado como um quadrado). Os vértices que representam pilhas de chamadas e subcomposições são mostrados em retângulos verticais, onde estão presentes, respectivamente, a representação dos vértices de chamada de serviços e as subcomposições alternativas.

Quando a composição principal começa a executar, as imagens da execução co- meçam a ser geradas. As imagens são geradas logo após a avaliação, ou mesmo antes do término da avaliação, dependendo do vértice que está sendo avaliado. Abaixo, temos as características que podem assumir todos os tipos de vértices durante a execução:

Figura 27 Ű Forma de Impressão dos vértices

• Unfolding e Unfold Ű Além da cor branca padrão, só assumem a cor vermelha, para o caso de fazerem parte de um condicional cuja execução foi descartada; • Sync Ű Além da cor branca padrão, ele assume a cor verde sempre quando é avaliado,

ou a cor vermelha, quando faz parte de um condicional cuja execução foi descartada; • Escolha (+) Ű Além da cor branca padrão, ele pode assumir as seguintes cores: amarela, para quando alguma de suas expressões está sendo avaliada; e verde, para o caso da avaliação de uma das guardas assumir o valor true;

• Expr Ű Além da cor branca padrão, ele pode assumir as seguintes cores: laranja, para o caso de alguma variável presente na expressão não ter sido avaliada; verde, para o caso da expressão ter retornado um valor true; ou vermelho, para o caso da expressão ter retornado um valor false;

• Chamada de Serviços Ű Além da cor branca padrão, ele pode assumir as seguintes cores: amarelo, quando a chamada está sendo avaliada; verde, para quando uma chamada foi executada com sucesso; ou vermelho, para quando uma chamada não conseguiu executar mesmo após a aplicação do Retry;

4.4. Vizualização de Transformações e Reduções 87

• Saída de Serviços Ű Além da cor branca padrão, ele só assume a cor verde, depois de avaliado;

• Pilha de Chamadas Ű Este vértice é um cluster que possui vértice internos (cha- madas de serviços). Ele pode assumir 3 cores diferentes: amarelo, quando os serviços internos estiverem sendo avaliados; verde, quando algum dos serviços completar a execução; e vermelho, quando nenhum dos serviços tiver sido executado. No caso deste vértice, adotamos não colorir o interior do mesmo, e sim o contorno externo; • Pilha de Subcomposições Ű Este vértice também é um cluster que possui com-

posições internas (que também são clusters). Da mesma forma como nas Pilhas de Chamadas, neste tipo de vértice, mudamos a cor da borda externa do cluster. Quando a pilha está sendo avaliada, ela assume uma cor amarela; no momento em que não há mais composições internas a serem executadas, a pilha assume uma cor vermelha; e se alguma composição executou completamente, a pilha assume uma cor verde. As subcomposições da pilha também podem assumir cores: a que está sendo executada assume a cor amarela, além de ser identiĄcada plelo texto EM EXECUÇÃO, atribuido por label="EM EXECUÇÃO". Se uma composição em execução falha, ela assume a cor vermelha. Se ela executa completamente, assume a cor verde. As ou- tras subcomposições da pilha Ącam em espera, apenas com a cor padrão, assumindo a cor vermelha se a execução de uma subcomposição foi realizada com sucesso;

Para demonstrar a sequência de imagens geradas, vamos propor uma composição e uma possível execução para a mesma na Ągura 33:

@ b(1,x) % a(1,x) % b(1,x) @ ; IF [x<2] a(x+1,x)

Criamos dois serviços Ąctícios: a, um serviço que avalia o parâmetro de entrada e atribui o resultado da avaliação à variável de saída (no caso, x); e b, um serviço qualquer. Vemos de (i) a (iii) a execução da pilha de chamadas de id=29131495. Primeiramente, ela Ąca sob avaliação (de acordo com (i)) e, ao executar um serviço, tanto os outros serviços da pilha como a própria pilha são descartados (de acordo, com (iii)). Vemos que o contorno da pilha e o vértice do serviço a Ącam verdes, indicando que a execução ocorreu da forma esperada. O vértice que contém o serviço b é descartado por não necessitar de sua execução, tendo o resultado desse procedimento mostrado em (iv). Observamos que existem duas arestas pontilhadas saindo do vértice 29131495?X. Essas são arestas de dependência, pois os vértices nos quais elas chegam utilizam-se de alguma variável presente neste vértice (no caso, a variável x). Em (v), temos a redução de um vértice de saída, que insere uma nova variável no ambiente, cujo resultado é mostrado em (vi). Chega-se a uma avaliação condicional do vértice Expr, que avalia a expressão x<2. Como

Figura 28 Ű Figuras geradas pela execução de uma composição

x=1, valor dado pelo serviço a, a avaliação retorna um valor true, e os vértices + e Expr são reduzidos do grafo, e o resultado é mostrado em (viii). Novamente, temos uma avaliação de um serviço a. No parâmetro de entrada, temos a variável x, que possui um valor no ambiente e, na variável de saída, também temos a mesma variável x. Neste caso, o que irá acontecer é o incremento desta variável, visto o parâmetro de entrada ser x+1. Portanto, não haverá inserções de variáveis, mas sim a atualização do seu valor.

89

5 EXPERIMENTAÇÃO

Após mostrarmos como foi implementada a máquina de redução com o trata- mento de falhas, temos o intuito de realizar um estudo de caso, com o objetivo de validar nossa implementação. Apesar de termos realizado algumas alterações e reĄnamentos na estrutura original, nosso objetivo maior é mostrar a execução, utilidade e eĄciência dos mecanismos de recuperação de falhas. Dessa forma, não será necessário construir uma composição extensa que englobe todas as capacidades da máquina, mas que foque nos mecanismos de recuperação implementados.