• Nenhum resultado encontrado

Além dos aspectos já mencionados na Seção 4.2 (uso de ambos os paradigmas de programação e das novas primitivas do Java), os benchmarks desenvolvidos devem ter outras características, enumeradas a seguir:

1. Benchmarks simples de entender e executar: os benchmarks devem ser simples de entender para que o foco esteja de fato na comunicação e sincronização existentes em tais algoritmos. Benchmarks complexos, do ponto de vista dos seus objetivos, não ne- cessariamente trazem maior complexidade à interação entre os processos, fato que não colabora para aumentar a complexidade da atividade de teste dos programas concorrentes. Como sugestão, podem ser usados algoritmos clássicos (descritos na literatura), com uma quantidade de linhas de código não alta e que também fossem de fácil execução. Podem ser desenvolvidas diferentes versões do mesmo algoritmo, considerando o uso de diferentes primitivas de comunicação e sincronização e níveis de interação. Deste modo os usuários de tais benchmarks podem focar nos aspectos da comunicação e sincronização existentes nos códigos. O aumento da complexidade (tanto da aplicação quanto da interação entre os processos) pode ser alcançada com programas flexíveis que permitem criar processos, threads e aumentar a interação através de códigos parametrizados (ver esta característica mais adiante).

2. Permitir a classificação quanto à interação: os benchmarks devem ser classificados quanto à interação entre os processos e/ou threads de modo que haja diferentes padrões de comunicação implementados. A métrica usada para quantificar a complexidade da interação neste trabalho é a quantidade de interações realizadas entre processos e threads. 3. Saídas simples: os benchmarks devem ter saídas simples, facilitando verificar se o resul-

tado da execução está correto ou errado.

4. Casos de teste: refere-se à existência ou não de casos de teste no benchmark. No conjunto de benchmarks desenvolvidos há versões que não possuem casos de teste. Estas versões de código têm o objetivo de validar aspectos específicos de comunicação e sincronização, sendo ideais para validar ferramentas de teste de programas concorrentes em fases iniciais de desenvolvimento. Os benchmarks com 2 (dois) ou mais casos de teste visam validar ferramentas em etapas avançadas de desenvolvimento.

4.3. Características dos Benchmarks 47

5. Avaliar a complexidade ciclomática: refere-se à construção de benchmarks que possuam variações na complexidade ciclomática, métrica intimamente ligada à quantidade de estru- turas de controle presentes no código fonte. Quanto maior for a complexidade ciclomática de um código, potencialmente mais caminhos existem para serem cobertos, talvez por diferentes casos de teste.

6. Programas flexíveis quanto ao número de processos, threads e interação: os bench- marks devem possibilitar a execução com um número variado de processos e/ou threads através do uso de códigos parametrizados, sendo possível executar um mesmo código com poucos ou muitos processos e/ou threads. Ao se variar a quantidade de processos e threads também é possível variar a complexidade das comunicações e sincronizações feitas. 7. Distribuição dos benchmarks entre as classes de programas: os benchmarks devem

estar distribuídos também em relação às classes de programas, representando padrões de comunicação distintos como: aplicações numéricas, produtor-consumidor, simulações diversas, entre outros.

8. Abrangência em relação às primitivas de comunicação e sincronização: diferentes linguagens de programação concorrentes oferecem suporte à interação entre processos e threads a partir de primitivas específicas que impõem semânticas distintas para acessar dados que são locais, remotos e compartilhados. Esta característica refere-se ao uso abrangente das primitivas de comunicação e sincronização da linguagem de programação concorrente utilizada para a implementação dos benchmarks.

9. Eventos de comunicação e sincronização: quando uma primitiva de comunicação é exe- cutada, ela gera um evento de comunicação e/ou sincronização que pode ser replicado caso esta primitiva seja reexecutada, por exemplo, por uma estrutura de repetição. Espera-se que os benchmarks evidenciem a diferença entre uma primitiva e um evento de comunicação e sincronização, por meio da reexcução de primitivas que gerem diferentes eventos de comunicação e sincronização a partir de um mesmo nó do PCFG.

10. Ambos os paradigmas: processos concorrentes interagem usando o paradigma de passa- gem de mensagem e/ou memória compartilhada. Os benchmarks devem considerar esses paradigmas isoladamente ou em conjunto.

11. Diferentes padrões de comunicação: corresponde ao desenvolvimento de benchmarks que apresentassem variados padrões de comunicação como: ponto-a-ponto (1 para 1), broadcast (1 para N), redução (N para 1), barreiras (N para N). Além destes padrões os benchmarks devem exercitar diferentes padrões de comunicação como os feitos na programação mestre-escravo, entre vizinhos mais próximos, pipeline, iterativo, entre outros.

12. Não determinismo: um algoritmo não determinístico apresenta diferentes comportamen- tos em diferentes execuções com a mesma entrada de dados. Programas concorrentes têm um grande potencial para comportamentos não determinísticos devido à concor- rência em pontos de sincronização. Os benchmarks devem apresentar comportamentos determinísticos e não determinísticos.

13. Código padronizado: benchmarks devem ser feitos com códigos padronizados, conside- rando indentação, comentários e uso de atributos. Isso os torna muito mais legíveis. Para a implementação Java dos benchmarks, por exemplo, foi usada a documentação Java Code Conventions.

14. Definição de um ambiente de execução padrão: refere-se à existência de um ambiente padrão para a execução dos benchmarks. Ela permite a replicação dos experimentos de forma mais clara por outros usuários.

15. Existência de pseudocódigo: o pseudocódigo descreve os benchmarks na forma de al- goritmos e que estejam desacoplados de uma linguagem de programação em particular, tornando os benchmarks ortogonais às mesmas. Os pseudocódigos seguiram o modelo usado porTanenbaum e Woodhull(2006) e foram inspirados na linguagem C.

16. Documentação padronizada: deve existir uma documentação padronizada para descrever cada benchmark. Nesta documentação há informações como: descrição do programa e qual seu objetivo, entradas suportadas e saídas esperadas, exemplo de como executar o programa e tabela descrevendo as principais características do programa. Nesta documentação também há o pseudocódigo e um grafo de fluxo de controle paralelo, o qual se baseia no pseudocódigo do benchmark.

17. Portabilidade dos benchmarks: os programas devem ter portabilidade, contando com recursos apenas do nível do usuário e independentes de linguagens, do sistema operacional (Linux, Windows, Mac OS), compiladores, bibliotecas e plataformas (hardware).

18. Benchmarks livres de defeitos conhecidos: os benchmarks devem ser livres de defeitos conhecidos e que funcionem de acordo com suas especificações.

19. Benchmarks com defeitos conhecidos: devem existir versões dos benchmarks com defei- tos conhecidos para auxiliar a validação dos modelos, critérios e ferramentas de teste. Outro ponto considerado é o uso balanceado das classes de defeitos no conjunto de benchmarks propostos.

A Tabela2é resultado do estudo da adequação das características anteriomente citadas sobre os benchmarks existentes (Rungta, Helgrind, Inspect e IBM) em comparação ao conjunto de benchmarks desenvolvidos neste projeto de mestrado (TestPar).