• Nenhum resultado encontrado

C. Teste estrutural

3.3.4. Trabalhos Relacionados

Esta seção apresenta os trabalhos relacionados com o contexto de melhoria de qualidade e confiabilidade de aplicações para GPU. Nessa linha, foram identificados trabalhos voltados para a análise dos mecanismos de tolerância a falhas da GPU, que pode afetar os resultados obtidos na execução da aplicação, e estudos voltados a detecção de defeitos em aplicações CUDA e OpenCL.

Sendo um modelo de programação e arquitetura recente, diversas funcionalidades comumente usadas em HPC não foram inicialmente suportadas por este modelo. Uma dessas funcionalidades é poder parar a execução da aplicação e posteriormente continuar do ponto em que parou. Visando isso, Takizawa et al.(2009) propuseram o CheCUDA, uma ferramenta CPR (Checkpoint / Restart). Ele busca permitir que na ocorrência de uma instabilidade que impeça a continuação da execução da aplicação, que ela possa posteriormente continuar do mesmo ponto. Isso também permite também que quando utilizado em clusters ou Cloud Computing, a aplicação possa ser migrada para um novo nó. Para isso, o CheCUDA armazena informações referente a execução, assim como efetua uma cópia do conteúdo da memória da GPU para a memória da CPU e desabilita o CUDA Runtime, posteriormente reativando-o e recuperando as informações salvas. No entanto, o CheCUDA exige que a aplicação seja desenvolvida usando uma extensão CUDA de baixo nível (CUDA driver API) e que o código seja recompilado para seu funcionamento. Baseado nisso, Nukada, Takizawa e Matsuoka (2011) propuseram o NVCR que permite usar funções de alto nível (CUDA runtime API) e não exige a recompilação do código para que as capacidades CPR funcionem. Laosooksathit, Naksinehaboon e Leangsuksan (2011) exploraram o mesmo problema, buscando assim diminuir o overhead causado pelo CPR na aplicação.

Apesar da linha de GPU voltada para HPC suportar ECC (Error Correction Code), apresentando maior resiliência a erros, a linha doméstica (Geforce) não apresenta esse recurso, estando dessa forma mais propenso a erros (TANet al., 2011; HAQUE; PANDE, 2010; SHEAFFER; LUEBKE; SKADRON, 2007). Para remediar esse problema Maruyama, Nukada e Matsuoka (2010) propuseram um framework para detectar erros na memória e se recuperar de erros, apresentando, no entanto, um alto overhead. (JEON; ANNAVARAM, 2012) e (ABDEL-MAJEED et al., 2015) buscam minimizar o overhead causado pela detecção e recuperação de erros buscando utilizar recursos subutilizados na execução da aplicação, como, por exemplo, a subutilização causada pela divergência de warps.

Poucos trabalhos relacionados a teste de software buscam diminuir defeitos em aplicações sob o modelo de programação CUDA. Dentre os poucos trabalhos existentes, percebe-se um forte foco dos mesmos na detecção de condições de disputa e, em alguns casos, em buscar deadlocks. Embora ainda incipiente, o teste de programas concorrentes CUDA conta com algumas pesquisas já desenvolvidas. Esta seção apresenta alguns dos principais trabalhos encontrados na literatura e que podem ser relacionados a este assunto.

Boyer, Skadron e Weimer (2018) apresentam uma técnica de análise automática para revelar dois tipos específicos de falha em aplicações CUDA: condição de disputa que pode resultar em uma saída não esperada, e conflitos de banco no acesso à memória compartilhada, que degrada a vazão de dados. A análise e detecção é feita por meio da instrumentação do programa, permitindo rastrear os acessos à memória por diferentes threads e por meio desses dados determinar se houve uma condição de disputa ou conflito de banco. Li e Gopalakrishnan (2010) buscaram atender aos mesmos objetivos apresentando a ferramenta PUG (Prover of User GPU programs), que detecta condições de disputa no acesso à memória, conflitos de banco de dados na memória compartilhada e ainda a presença de deadlocks. Para isso foram utilizadas as Teorias do Módulo de Satisfação (Satisfiability Modulo Theories - SMT) (BARRETT et al., 2009) para analisar automaticamente os kernels de programas CUDA. Também visando condições de disputa em CUDA, Zhenget al. (2011) desenvolveram o GRace, que utiliza análise estática para diminuir o número de instruções que precisam ser instrumentadas, melhorando o desempenho. Ele analisa os registros gerados dinamicamente buscando detectar condições de disputa.

Buscando detectar condições de disputa e divergência de barreiras de sincronização, Betts et al. (2012) conceberam o GPUVerify, que analisa aplicações desenvolvidas com CUDA ou OpenCL, devido às semelhanças entre os modelos quando aplicados ao desenvolvimento de aplicações para GPU. Collingbourne, Cadar e Kelly (2012) utilizaram a execução simbólica (KING, 1976), por meio da ferramenta KLEE-CL, para detectar condições de disputa em programas que utilizam OpenCL e comparando com seu equivalente em C ou C++ para detectar divergências nos resultados. Para diminuir o número de casos de testes necessários para detectar condições de disputa, Leunget al. (2012) utilizaram test amplification, executando uma vez o código e analisando seu comportamento. Caso os dados de entrada não sejam usados para definir o acesso à memória ou não afetem o fluxo de controle, ele generaliza para todas as entradas a ausência de condições de disputa. Li et al. (2012) utilizam o código base do KLEE e apresenta o framework chamado GKLEE (GPU KLEE) que utiliza execução concolic (concreto mais simbólico) para detectar condições de disputa, deadlocks e outros problemas relacionados a desempenho, como acesso não-coalescente a memória, conflito de bancos de memória e divergência de warps. Ele consegue gerar parcialmente os dados de teste, mas depende de o usuário definir quais variáveis serão simbólicas. Li, Li e Gopalakrishnan (2012) estenderam o GKLEE em uma nova versão chamada

GKLEEp, buscando diminuir o número de threads necessárias para detectar

condições de disputa por meio da partição do espaço de execução usando classes

de equivalência de fluxo paramétrico. GKLEEp necessita de apenas duas threads ao

invés de N threads no caso do GKLEE para detectar condições de disputa. Por fim, Li, Li e Gopalakrishnan (2014) apresentam o SESA (Symbolic Execution and Static Analysis) que diminui a necessidade do usuário definir as variáveis como simbólica por meio da análise do fluxo de dados.

A Tabela 1 apresenta um resumo e comparação entre as diferentes ferramentas pesquisadas, onde pode-se observar o foco principalmente em condições de disputa e a ausência de mecanismos para a detecção de erros de programação que podem resultar em uma saída diferente da esperada.

Tabela 1 – Comparação de ferramentas de análise e teste de programas para GPU.

Fonte: Adaptada de Li (2015).

3.3.4.1. Considerações Finais

Este capítulo apresentou os trabalhos relacionados com a melhoria da qualidade de aplicações CUDA. Foram identificadas duas vertentes nessa linha: a primeira relacionada a mecanismos de tolerância a falhas, enquanto a segunda está relacionada com a detecção de defeitos em aplicações CUDA e OpenCL. Por meio desses trabalhos pode-se observar que os trabalhos relacionados a detecção de defeitos o foco principal é revelar defeitos de desempenho, tendo como foco secundário relevar alguns defeitos que afetam a semântica da aplicação, como condições de disputa. Esse foco é diferente do proposto por este trabalho, que visa revelar defeitos que causem falha na aplicação, como os defeitos apresentados no Capítulo 1.1.

Documentos relacionados