View
4
Download
0
Category
Preview:
Citation preview
06/06/2018
1
Alessandro Garcia
Eduardo Fernandes (assistente)
LES/DI/PUC-Rio
Junho 2018
Aula 21Instrumentação – Parte 1
1 / 28Alessandro Garcia © LES/DI/PUC-Rio
Hoje... Especificação
• Objetivo dessa aula
– Motivar instrumentação de programas
• Tipo 1: assertivas executáveis
• Tipo 2: contagem de passagem dos testes
– Módulo CONTA
• Referência básica:
– Capítulo 14
– Monografia
• Slides adaptados de: Staa, A.v. Notas de Aula em Programação
Modular; 2008.
Jun 2018
06/06/2018
2
2 / 28Alessandro Garcia © LES/DI/PUC-Rio
Sumário
• Propriedades desejáveis de programas fidedignos
• Tipos de instrumentação
• Módulo CONTA
Jun 2018
3 / 28Alessandro Garcia © LES/DI/PUC-Rio
Qualidade do software em execução
Dados Produtorcria elemento
Erro
?
?
?
?
Observadorde erros
Defeito
Elemento
Sistema
a
b
c
d
e
f
g
h
i
j
k
Usuário
Lesão(conseqüência
de erro nãoobservado)
Falha
Resultados
Engano do produtorintroduz defeito Causa exógena
provoca um erro
Causaendógenaprovocaum erro
Jun 2018
06/06/2018
3
4 / 28Alessandro Garcia © LES/DI/PUC-Rio
Tolerância a falhas: conceitos
• Para ser um software fidedigno, este deve ser robusto e/ou
tolerante a falhas
• Um programa robusto observa a ocorrência de erros
endógenos ou exógenos (detectabilidade)
– intercepta a execução quando observa um erro
– mantém confinado o possível dano decorrente da falta
• Um programa tolerante a falhas (fault tolerant)
– é um programa robusto
– possui mecanismos de recuperação, habilitando-o a continuar
operando confiavelmente (fidedignamente) após ter detectado
uma falha
• Deterioração controlada (graceful degradation)
– é a habilidade de um programa continuar operando
corretamente após uma falha, embora com alguma perda de
funcionalidade
Jun 2018
5 / 28Alessandro Garcia © LES/DI/PUC-Rio
Instrumentação: o que é
• A instrumentação
– monitora o comportamento do programa em execução
• Ex. assertivas executáveis
– visa garantir detectabilidade e diagnosticabilidade
– é formada por fragmentos inseridos no código
– deve poder ser inserida e mais tarde retirada sem que isto
afete a funcionalidade do programa
• não contribui para o serviço a que se destina o programa
• entretanto, pode interceptar a execução ao detectar uma falha
– pode estabelecer e explorar redundâncias
• exemplo: N-Version Programming
• leva a custos adicionais: desenvolvimento e recursos de execução
– porém, aumenta confiabilidade e reduz tempo de reparo
– pode simular e monitorar propriedades dinâmicas do programa
• cobertura dos testes e simulação de mau funcionamento
Jun 2018
06/06/2018
4
Jun 2018 6 / 28Alessandro Garcia © LES/DI/PUC-Rio
Instrumentação: objetivos
• Medir propriedades dinâmicas do programa
– cobertura dos testes
• quanto do código foi exercitado durante os testes
– simular mau funcionamento para fins de teste
• deturpadores
– localizar onde são consumidos recursos computacionais
– tempos de resposta
– número de transações processadas
– número de transações por unidade de tempo
– duração das transações
– vazamento de memória
– ...
7 / 28Alessandro Garcia © LES/DI/PUC-Rio
Instrumentação: inserção no código
• A instrumentação deve permanecer no código
– deve poder ser ativada ou desativada
• compilação condicional
– pode ser útil ao alterar um programa mais tarde
• Esquema de inclusão de instrumentos no código em C/C++
#ifdef _DEBUG
• código do instrumento
• funções e dados de uso exclusivo em instrumentos
#endif
• Para que a instrumentação seja compilada o comando de
compilação deve conter o parâmetro /D_DEBUG
Jun 2018
06/06/2018
5
Jun 2018 8 / 28Alessandro Garcia © LES/DI/PUC-Rio
Tipos de Instrumentos
• Internos ao programa
– assertivas executáveis
– controladores de espaços de dados
– verificadores e deturpadores de estruturas de dados
– contadores de passagem
• Externos ao programa
– arcabouço e módulos de teste
– depuradores
9 / 28
Arcabouço de teste
• Armaduras de teste (test harness) são ferramentas que
permitem realizar e controlar testes com o construto sob
teste
– arcabouços de teste são exemplos de armaduras de teste
– estabelecem um ambiente controlado para o construto sob
teste
• pode ser possivelmente formado por hardware e software
especializado
• simuladores
• módulos dublê (de imitação, mock modules, mock objects)
– podem verificar se os resultados obtidos pelos testes
correspondem a resultados válidos ou esperados
• módulo dublê -> test double, analogia: stunt double
Alessandro Garcia © LES/DI/PUC-RioJun 2018
06/06/2018
6
Jun 2018 10 / 28Alessandro Garcia © LES/DI/PUC-Rio
Assertivas executáveis
• Assertivas executáveis contribuem para
– aumentar a detectabilidade: identifica erro imediatamente
– aumentar a diagnosticabilidade: reduz o esforço de diagnose
• É possível traduzir uma parcela considerável das assertivas
para código executável. Exemplo:
pElem Lista { pLista } : pElem->pProx != NULL =>
pElem->pProx->pAnt == pElem
AE: pLista aponta para a cabeça da lista a ser controlada
numErros = 0 ;
for ( pElem = pLista->pOrigem ; pElem != NULL ;
pElem = pElem->pProx )
{
if (pElem->pProx != NULL) {
if (pElem->pProx->pAnt != pElem))
numErros ++ ;
}
}
AS: se numErros != 0 a lista contém erros estruturais.
todos nós posteriores
apontam corretam.
para o anterior
Experimentos com sistemas reais…
• … demonstram os benefícios constantes de instrumentação
(assertivas executáveis) à longo prazo
Fonte: Minds @ Work, Dr. João Magalhães
Todos sistemas são
Implementados em C
Alessandro Garcia © LES/DI/PUC-RioJun 2018 11 / 28
06/06/2018
7
Jun 2018 12 / 28Alessandro Garcia © LES/DI/PUC-Rio
Exemplo de assertivas executáveis
A
A
B
B
pElemCorr
pElemCorr
InserirApos( pElemCorr , pElemNovo )
pElemNovo
pElemNovo
C
C
Antes
Após
Jun 2018 13 / 28Alessandro Garcia © LES/DI/PUC-Rio
Exemplo de assertivas executáveis
void InserirElemApos( tpElem * pElemCorr , tpElem * pElemNovo )
{
//Assertiva de entrada
#ifdef _DEBUG
tpElem * pElemAux ;
tpElem * pElemCorrEntra ;
if ( ( pElemCorr == NULL )
|| ( pElemNovo == NULL ))
{
TratarErro( "InserirElem: Argumentos nulos" , __Line__ ) ;
}
if ( ( pElemNovo->pProx != NULL )
|| ( pElemNovo->pAnt != NULL ))
{
TratarErro("InserirElem: Novo elem esta encadeado" , __Line__ ) ;
}
pElemCorrEntra = pElemCorr ;
pElemAux = pElemCorr->pProx ;
if ( pElemAux != NULL )
{
if ( pElemAux->pAnt != pElemCorr )
{
TratarErro("InserirElem: Encadeamento da lista" , __Line__ ) ;
}
}
#endif
Para reduzir o esforço computacional,
verifica somente no entorno do ponto
de inserção
06/06/2018
8
Jun 2018 14 / 28Alessandro Garcia © LES/DI/PUC-Rio
Exemplo de assertivas executáveis
// Efetuar a inserção
// Assertiva de saída
#ifdef _DEBUG
if ( !(( pElemNovo == pElemCorr )
&& ( pElemNovo->pAnt == pElemCorrEntra )
&& ( pElemNovo->pProx == pElemAux )
&& ( pElemCorrEntra->pProx == pElemNovo )))
{
TratarErro( "InserirElem: Encadeamento antes" , __Line__ ) ;
}
if ( pElemAux != NULL )
{
if ( !( pElemAux->pAnt == pElemNovo ))
{
TratarErro( "InserirElem: Encadeamento apos" , __Line__ );
}
}
#endif
} // Fim da função
Jun 2018 15 / 28Alessandro Garcia © LES/DI/PUC-Rio
Função assert de C/C++
• assert( condição )
– se condição verdadeira faz nada
– se falsa gera uma mensagem indicando o nome e a linha do
arquivo fonte que contém a função, e o string do código de
condição e a seguir cancela a execução
• Cancelamento imediato pode provocar problemas mais
adiante, por exemplo
– não se arruma a casa
• estados e dados persistentes podem se tornar inconsistentes
gerando problemas em usos futuros
• transações de alteração persistente podem ficar parcialmente
executadas
• ver aula 13
06/06/2018
9
Jun 2018 16 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: função de contagem
#define CNT_CONTAR( NomeContador ) \
CNT_Contar( NomeContador , __LINE__ )
CNT_tpCondRet CNT_Contar(char * NomeContador, int numLinha);
• Sempre que for chamada o contador será
– se normal: incrementado de 1
– se opcional: se == -1 atribui 1, senão incrementa de 1
– se proibido: emite uma mensagem de erro. Esta contém o
valor numLinha
• Caso o módulo contador não tenha sido inicializado, a
função CNT_Contar fará nada ao ser chamada
• Esta função deverá ser inserida em um ou mais pontos do
módulo a ser medido
Jun 2018 17 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: função de contagem
• Embora um mesmo nome possa aparecer em várias
chamadas, o correto é que cada nome apareça em uma
única chamada a CNT_Contar
– para poder contar vários módulos simultaneamente, inicie o
nome do contador com as letras identificadoras do módulo
06/06/2018
10
Jun 2018 18 / 28Alessandro Garcia © LES/DI/PUC-Rio
Exemplo: medição de cobertura de testes
ARV_tpCondRet ARV_InserirEsquerda( void * ValorParm )
{
tpNoArvore * pCorr ;
tpNoArvore * pNo ;
CNT_CONTAR( "Inserir no a esquerda do corrente" ) ;
if ( pArvore->pRaiz == NULL )
{
CNT_CONTAR( "Inserir a esquerda em arvore vazia" ) ;
return CriarNoRaiz( ValorParm ) ;
}
CNT_CONTAR( "Inserir a esquerda em arvore nao vazia" ) ;
pCorr = pArvore->pNoCorr ;
if ( pCorr->pNoEsq == NULL )
{
CNT_CONTAR( "Efetuar a insercao a esquerda" ) ;
pNo = CriarNo( ValorParm ) ;
assert( pNo != NULL ) ;
pNo->pNoPai = pCorr ;
pCorr->pNoEsq = pNo ;
pArvore->pNoCorr = pNo ;
return ARV_CondRetOK ;
} /* if */
CNT_CONTAR( "Nao e folha a esquerda" ) ;
return ARV_CondRetNaoFolha ;
} /* Fim função: ARV Adicionar filho à esquerda */
Jun 2018 19 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: medição da cobertura de testes
• No arcabouço, contadores podem ser:
– contador normal: inicializado para 0
– contador opcional: inicializado para –1
• exemplo de uso: fragmentos de código de baixo risco
– contador proibido: inicializado para –2
• código “impossível” de ser exercitado
• Se, após a execução de todos os casos de teste sobrar
algum contador com valor igual a zero, o respectivo ponto
(CNT_CONTA) nunca foi executado, o teste foi insuficiente
06/06/2018
11
Jun 2018 20 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: medição da cobertura de testes
• Contadores têm nomes simbólicos strings
– facilita a contagem envolvendo vários módulos
– facilita ativar ou desativar seletivamente a contagem
– tem custo computacional mais alto do que indexação
• Contadores utilizados na função ARV_InserirEsquerda
"Inserir no a esquerda do corrente"
"Inserir a esquerda em arvore vazia"
"Inserir a esquerda em arvore nao vazia"
"Efetuar a insercao a esquerda"
"Nao e folha a esquerda"
• Os contadores precisam ser fornecidos antes de medir para
que possamos determinar se algum deles não foi percorrido
no conjunto de todos os testes
Jun 2018 21 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: comandos de teste
=inicializarcontadores <nome arquivo contadores acumulado>
=terminarcontadores
=registraracumulador <nome arquivo contadores acumulado>
=lercontadores <nome arquivo contadores>
=gravarcontadores <nome arquivo contadores acumulado>
=zerartodoscontadores
=zerarcontador <nome do contador>
=iniciarcontagem
=pararcontagem
=verificarcontagens <número de contadores == 0 esperado>
=contagemcontador <nome do contador> <número esperado>
=exibircontagem <nome do contador>
06/06/2018
12
Jun 2018 22 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: esquema de uso
== Iniciar contagem
=inicializarcontadores ""
=lercontadores "exemplo-conta-arv"
=iniciarcontagem
realizar o teste
== Terminar contagem
=pararcontagem
=verificarcontagens 0
// finaliza mesmo se ocorreu erro ao verificar
== Finalizar
=terminarcontadores
Jun 2018 23 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: arquivo de contadores
////////////////////////////////////////////////
//
// Exemplo de arquivo de declaração de contadores
// Conta módulo Arvore marcado
//
///////////////////////////////////////////////
ARV_InserirEsquerda
ARV_InserirDireita
ARV_CriarArvore
ARV_DestruirArvore
ARV_IrPai
ARV_IrNoEsquerda
ARV_IrNoDireita
ARV_ObterValorCorr
XPTO Ilegal\=-2
ZPTO Opcional\=-1
Normal inicializado\=100
06/06/2018
13
Jun 2018 24 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: medição da cobertura de testes
• O esquema de contagem deve ser escolhido em acordo com
o objetivo do teste, exemplos:
– contar a ativação de cada função
• inserir contador antes de cada chamada de função
– contar cada chamada de função
• inserir contador em cada início de função
– contar a passagem por todas as arestas de execução
• exemplo a ser mostrado
– contar cada condição de retorno
• inserir contador antes de cada retorno
– contar cada o uso de cada widget
• diálogo, mensagem, ícone, elemento de menu,...
Jun 2018 25 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: controle de caminho
Programa: Intercalar arquivos
while ( ( Arq_A.Buffer.chave < MAX )
&& ( Arq_B.Buffer.chave < MAX ))
{
CONTAR( "repete" ) ;
if ( Arq_A.Buffer.chave == Arq_B.Buffer.chave )
{
CONTAR( "chaves iguais" ) ;
TransferirRegistro( &Arq_A , Arq_D ) ;
TransferirRegistro( &Arq_B , Arq_D ) ;
} else if ( Arq_A.Buffer.chave < Arq_B.Buffer.chave )
{
CONTAR( "chave Arq_A menor" ) ;
TransferirRegistro( &Arq_A , Arq_S ) ;
} else
{
CONTAR( "chave Arq_B menor" ) ;
TransferirRegistro( &Arq_B , Arq_S ) ;
}
}
06/06/2018
14
Jun 2018 26 / 28Alessandro Garcia © LES/DI/PUC-Rio
Contadores: controle de caminho
== Teste intercalar arquivos vazios
=zerartodoscontadores
=intercala Vazio Vazio Vazio Vazio // A B S D
=contagemcontador "repete" 0
=contagemcontador "chaves iguais" 0
=contagemcontador "chave Arq_A menor" 0
=contagemcontador "chave Arq_B menor" 0
== Teste intercalar A com dois B com 1, 1o. A == 1o. B
=zerartodoscontadores
=intercala Com-1-5 Com-1 Com-5 Com-par-1
=contagemcontador "repete" 2
=contagemcontador "chaves iguais" 1
=contagemcontador "chave Arq_A menor" 1
=contagemcontador "chave Arq_B menor" 0
Trabalho 4
• Explicar o que precisa ser feito com relação a:
– Assertivas
– Contagem de passagem (analise de cobertura)
– Uso do modulo CONTA
27 / 28Alessandro Garcia © LES/DI/PUC-RioJun 2018
06/06/2018
15
Alessandro Garcia
Eduardo Fernandes (assistente)
LES/DI/PUC-Rio
Junho 2018
Aula 21Instrumentação – Parte 1
Recommended