• Nenhum resultado encontrado

A inserção de defeitos nos benchmarks permite avaliar a eficácia de critérios em revelar tais defeitos. Os defeitos nos benchmarks de passagem de mensagem, desenvolvidos nesse projeto, tiveram como base a classificação de defeitos proposta porDeSouza et al.(2005). Para os benchmarks de memória compartilhada foram usados os tipos de defeitos apresentados em

Farchi, Nir e Ur(2003) eBradbury, Cordy e Dingel(2006). Além dos defeitos específicos de programas concorrentes, também foram utilizados defeitos vistos em programas sequencias, mas que de alguma forma interferem em aspectos da concorrência. A Tabela5apresenta a lista de defeitos inseridos.

Tabela 5 – Tipos de defeitos inseridos nos benchmarks.

Número Descrição

1 Diferentes tamanhos de mensagens para sends e receives correspondentes

2 Retirada de comandos

3 Processo de destino ou origem incorreto num send ou receive

4 Defeito no laço que antecede uma primitiva send ou receive impedindoque ocorra a mensagem 5 Atribuição de forma incorreta usando variáveis

6 Inicialização incorreta de contadores 7 Outros sinais ausentes ou inexistentes

8 Operação não atômica assumida como atômica

9 Bloqueio de uma região crítica

10 Bloqueio incorreto ou ausência de bloqueio

Foram geradas 13 versões de benchmarks com defeitos, abrangendo 8 benchmarks diferentes e 10 tipos de defeitos. Para cada defeito inserido foi gerada uma nova versão do

5.4. Inserção de Defeitos nos Benchmarks 61

benchmark. Decidiu-se inserir um único defeito por benchmark para se evitar a interferência de um defeito no outro, o que poderia resultar no mascaramento (um defeito anular o outro). Tomou-se essa decisão também com o intuito de facilitar a análise da eficácia dos critérios. Os defeitos foram inseridos de modo a ser possível a compilação do programa, ou seja, não adicionando defeitos sintáticos (detectados antes da execução do programa).

As versões de benchmarks com defeitos desenvolvidos neste trabalho de mestrado, apre- sentam defeitos propositalmente simples, já que a validação realizada tem um foco incremental. A proposta desde o início foi inserir defeitos seguindo taxonomias de defeitos conhecidas e que fossem capazes de avaliar, pontualmente, critérios de teste estrutural. Assim, os experimentos realizados com os benchmarks com defeitos neste trabalho, serviram como um indicativo da capacidade dos mesmos na avaliação de critérios de teste. Para uma avaliação mais completa, novos defeitos devem ser inseridos (considerando, inclusive, mais de um defeito por benchmark), acompanhando o desenvolvimento e a avaliação de novos critérios de teste.

A Tabela6apresenta os benchmarks, os respectivos defeitos inseridos e os tipos de erros observados.

Tabela 6 – Semeadura de defeitos nos benchmarks e tipo de erro observado.

Benchmark Defeito Tipo de Erro

Blocking_MP_PP_Fault 1 observabilidade Non_Blocking_MP_Fault 2 observabilidade Parallel_GCD_Fault_1 3 travamento Parallel_GCD_Fault_2 4 travamento GCD_Two_Slaves_Fault 5 observabilidade All_to_All_Fault_1 6 travamento All_to_All_Fault_2 7 travamento Matrix_Fault 8 observabilidade Prod_Cons_Lock_Cond_Fault_1 7 travamento Prod_Cons_Lock_Cond_Fault_2 9 travamento SM_Fault_1 6 observabilidade SM_Fault_2 8 observabilidade SM_Fault_3 10 observabilidade

O defeito inserido no benchmark Blocking_MP_PP_Fault (documentação pode ser vista no ApêndiceA, página104) carateriza-se pela definição de um tamanho de buffer no receive do processo Server, menor do que o tamanho da mensagem que o processo Client irá enviar. Isso faz com que a mensagem, ao chegar no processo Server, apareça incompleta.

O defeito presente no benchmark Non_Blocking_MP_Fault consistiu na retirada de comandos de modo a interferir nos aspectos de comunicação entre os processos. No processo Client foi removida a estrutura de repetição do-while (linhas 38 e 46 do pseudocódigo do benchmark na página109), o if-else (linhas 40, 42 e 45) e o sleep (linha 41). A retirada desses comandos pode ter como resultado o processo Client imprimir na tela uma string vazia, caso a

mensagem não tenha chegado a tempo no receive não bloqueante do benchmark (linha 39 do pseudocódigo).

No benchmark Parallel_GCD_Fault_1 o defeito foi inserido na linha 26 do pseudocódigo da página117, no qual o processo de destino foi definido incorretamente no send bloqueante. Ao invés de mandar a mensagem para o processo GcdSlave 3 (p3t0), a mensagem é enviada para o GcdSlave 2 (p2t0). Esse processo (GcdSlave 2), com que se fez a comunicação erroneamente, inclusive, já realizou sua comunicação e finalizou sua execução e, apesar da saída (Result = 1) ser exibida corretamente no processo GcdMaster, o processo GcdSlave 3 travará em um receive bloqueante a espera de uma mensagem que nunca será enviada.

Outra versão do benchmark com defeito é o Parallel_GCD_Fault_2 que se caracteriza pela presença de um defeito no laço que antecede a primitiva send do processo Slave. O defeito foi inserido na linha 48 do pseudocódigo da página 117, em que, ao invés da operação de subtração, é realizada uma adição, resultando em um laço infinito que impede que a primitiva send, da linha 55 vista na documentação, seja executada. Esse defeito pode ser revelado ou não, dependendo do dado de teste utilizado.

O defeito inserido no benchmark GCD_Two_Slaves_Fault consistiu na atribuição in- correta à variável result, em que, ao invés de realizar a atribuição result = snd no processo GcdMaster (linha 39 do pseudocódigo da página121), foi feita a atribuição result = fst. Esse defeito pode ou não ser revelado a depender do dado de teste utilizado e da ordem em que as mensagens chegam ao receive da linha 28 da documentação.

O defeito presente no benchmark All_to_All_Fault_1 caracteriza-se pela inicialização incorreta de permissões em uma das duas barreiras utilizadas no benchmark. O defeito foi inserido na primeira barreira (linha 02 do pseudocódigo da página164), em que, ao invés de se ter o valor 3 foi atribuído o valor 4. Assim o sistema ficará travado na espera de que uma thread a mais chegue na barreira, algo que pela semântica do benchmark não irá acontecer.

Já no benchmark All_to_All_Fault_2 o defeito foi a ausência da primitiva wait da linha 14 do pseudocódigo da página164.

O benchmark Matrix_Fault simula o engano de um programador que se esqueceu de proteger a região crítica referente à soma cumulativa presente na linha 84 do pseudocódigo da página198. Assim o defeito consiste na retirada dos comandos presentes nas linhas 83 e 85 do pseudocódigo. Esse defeito pode ser revelado a depender da sincronização das threads, que em certos instantes podem se comportar como o esperado, acessando em momentos apropriados a variável compartilhada, ou acessando de forma a revelar o defeito.

O defeito do benchmark Prod_Cons_Lock_Cond_Fault_1 está na inexistência do sinal da linha 101 do pseudocódigo do benchmark na página176. Esse defeito interfere na saída e faz com que o programa trave.

5.5. Considerações Finais 63

operação bloqueante de entrada e saída na região crítica do Producer entre as linhas 43 e 44 do pseudocódigo do benchmark na página175.

No benchmark SM_Fault_1 foi adicionado um token extra no semáforo mutex, além do que existe na linha 05 da Main do pseudocódigo do benchmark na página167. Essa situação faz com que a variável não esteja corretamente protegida interferindo na saída.

Na versão SM_Fault_2 do benchmark o defeito está relacionado à não proteção da região crítica, simulando que o programador assumiu que a operação realizada é atômica quando na verdade não é. Esse defeito também interfere na saída do benchmark.

Por fim, no benchmark SM_Fault_3 foi inserido um novo semáforo. Assim, cada uma das threads usa uma instância diferente de semáforo, resultando em uma possível interferência entre as threads sobre a mesma variável compartilhada que não estará realmente protegida.

Os benchmarks com defeitos inseridos apresentados neste capítulo foram utilizados em experimentos (Tabela 11 do capítulo6) tendo em vista verificar a capacidade da ferramenta ValiPar em revelá-los.

5.5 Considerações Finais

Este capítulo trouxe uma visão sobre taxonomias de defeitos para programas concorrentes evidenciando, também, a necessidade de se desenvolver benchmarks com defeitos conhecidos que permitam colocar à prova os modelos, critérios e ferramentas de teste. Este capítulo também mostra quais benchmarks com defeitos inseridos foram desenvolvidos neste trabalho de mestrado, evidenciando o tipo de defeito inserido e o tipo de erro observado para cada um deles.

65

CAPÍTULO

6

EXPERIMENTOS E ANÁLISE DOS

RESULTADOS

6.1 Considerações Iniciais

Este capítulo apresenta os resultados dos experimentos realizados com os benchmarks desenvolvidos neste trabalho, juntamente com uma discussão crítica sobre os mesmos, permitindo uma visão geral de como os benchmarks podem gerar uma demanda controlada e qualificada sobre o modelo, critérios e sobre a ferramenta ValiPar.

O capítulo está assim estruturado: na Seção6.2é abordada a metodologia dos experi- mentos destacando qual foi o objetivo, o ambiente de execução, as fases que compuseram um único experimento, quantas replicações do experimento foram feitas, além de identificar o modo de apresentação dos resultados obtidos com os experimentos realizados. A Seção6.3apresenta os resultados dos experimentos realizados com os benchmarks livres de defeitos conhecidos. A Seção6.4apresenta os resultados dos experimentos realizados com os benchmarks com defeitos inseridos. Por fim, a Seção6.6evidencia o uso dos benchmarks em outros projetos de pesquisa e também como material de apoio ao ensino.