Personal tools
You are here: Home Calcul Technique Documentation IBM cluster p690 (Power4) Déboguage
Document Actions

Déboguage

Outils et options de compilation pour éliminer certaines erreurs de programmation

1. Débogueurs

2. Déboguage


Introduction

Les débogueurs sont des auxiliaires précieux pour éliminer les erreurs dans les programmes.

Au premier abord, déboguer un programme consiste à l'arrêter sous certaines conditions pour examiner l'état de la pile d'appels et les valeurs stockées dans les variables.
On arrête l'exécution en insérant des points d'arrêt (breakpoints). Ces points d'arrêt peuvent être inconditionnels (ils engendrent toujours un arrêt du programme lorsqu'ils sont rencontrés) ou conditionnels (ils arrêtent le programme seulement si une condition est vérifiée, condition spécifiée par l'utilisateur).
Ils permettent aussi d'analyser les fichiers core générés lors d'un plantage. Pour cela on autorise la création de tels fichiers avec la commande ulimit coredumpsize.
L'utilisation d'un débogueur nécessite au moins l'ajout des l'options -qnooptimize et -qdbg à la compilation des fichiers sources. La première option inhibe les optimisations et la seconde entraine l'insertion d'informations dans l'exécutable qui permettent au débogueur de suivre les variables locales, les numéros des lignes, etc ...
Le déboguage d'un code est préliminaire et incompatible à toute optimisation.
Pour une liste détaillée des options conseillées pour le déboguage, consultez la page des compilateurs XLF ou XLC.

dbx est un débogueur symbolique textuel.
pdbx est un débogueur parallèle, une extension du débogueur standard, dbx.


flechehaut

dbx

dbx est un débogueur symbolique textuel.
Il permet de déterminer l'origine d'un plantage en étudiant le fichier core pour analyser la pile d'appel du programme :
dbx mon_prog core
On utilise la commande where au prompt qui apparait. En retour s'affiche la file d'appels des fonctions employées ainsi que le nom des fichiers sources et les numéros des lignes ou ont eu lieu ces appels :
(dbx) where
dbx travaille de manière optimale sur un code compilé avec les options -qnooptimize et -qdbg. Cela a pour effet d'inhiber les optimisations et de rajouter des informations de déboguage dans le code objet. Ces informations permettent à dbx de voir les variables locales et de déterminer les numéros des lignes du source. Autrement dbx ne pourra fournir que peu d'informations.

Lien vers la page dbx


flechehaut

pdbx

Le débogueur parallèle est une extension du débogueur standard, dbx. Il permet de définir un "groupe de tâches parallèles" et d'utiliser les fonctions habituelles de déboguage sur une tâche, sur un ensemble de tâches prénommées (all, slaves, master) ou sur un groupe défini par l'utilisateur.

Il fonctionne en mode NORMAL, où l'utilisateur donne le nom du programme à déboguer, ou en mode ATTACH, où l'utilisateur décide en cours d'exécution d'un programme de lancer le débogueur sur une tâche précise.
Il supporte le déboguage de threads : variables, stack, breakpoints, tracepoints et code source.

Lien vers la page pdbx


flechehaut

Options de déboguage

La liste suivante fournit quelques conseils d'écriture de code pour avoir un code portable, lisible et réutilisable :
  • faire un code aéré avec des commentaires ;
  • indenter les lignes du code ;
  • mettre un sous-programme ou un bloc common par fichier ;
  • déclarer explicitement l'ensemble des variables (locales et globales), des fonctions externes appelées, avec leur nom générique ;
  • utiliser les types génériques pour les variables (REAL, INTEGER), voir les conseils pratiques (type de données des flottants) ;
  • construire des blocs common par type de variables et par thème : CHARACTER et LOGICAL à part ;
  • déclarer explicitement les dimensions des tableaux en Fortran (pas de * fourre-tout) et transmettre ces dimensions comme arguments lors des appels ;
  • utiliser les clauses INTENT pour les programmes en Fortran 90.
Ensuite, les principales options de déboguage :
  • aucune optimisation de code : option -qnooptimize ;
  • enrichir la table des symboles pour permettre la localisation de certaines erreurs ou/et l'utilisation efficace d'un débogueur symbolique (par exemple dbx) : option -qdbg ;
  • recherche des variables non initialisées avant utilisation : option -qinitauto=ff, cette option initialise à NaN toutes les variables locales et automatiques mais ne détecte rien, pour cela il faut utiliser l'option -qflttrap (ci-dessous) ;
  • recherche des débordements de tableau : option -qcheck ;
  • vérification des séquences d'appels de sous-programmes : option -qextchk ;
  • capture des signaux des exceptions : option -qsigtrap (empêche la création de fichier core) ;
  • traçage des exceptions flottantes (opérations non conformes sur les nombres réels) : option -qflttrap=ov:und:zero:inv:en ;
  • affichage de tous les messages de la compilation : option -qflag=i:i; on peut éliminer certains messages (warning) qui inondent les sorties à l'aide de l'option -qsuppress=nnnn-mmm. nnnn-mmm est le numéro du message et on peut préciser un seul numéro, soit plusieurs, intercalés avec des double-points ":" .
Il faut ensuite valider à part les différents morceaux d'un code : écrire un petit programme pour tester la subroutine qui effectue le produit matrice vecteur, la factorisation LU, le gradient conjugué, ... au cas ou il n'existe pas déjà la routine adéquate dans une bibliothèque scientifique (comme BLAS, LAPACK, ...)

Résumé :

Une séquence d'options pour le déboguage pourrait donc être :

-qnooptimize -qcheck -qdbg -qextchk -qflttrap=:ov:und:zero:inv:en -qfullpath -qinitauto=FF


flechehaut

Exceptions flottantes

Les exceptions flottantes sont des résultats incorrects qui entrainent un surcoût cpu pour le traitement de l'opération. Ce surcoût peut être très important selon l'ampleur du phénomène. Cela peut se produire même si le code ne plante pas ou si les résultats semblent corrects (présence d'underflows).
Il y a cinq types d'exception : underflow, overflow, divide-by-zero, invalid operation, inexact operation. Il y a aussi une sixième exception concernant les entiers : l'integer overflow.
De manière générale, la présence d'exceptions flottantes correspond à des erreurs dans le programme et il est impératif de les corriger avant de passer à l'exploitation du code. La rubrique précédente propose des outils pour détecter ces exceptions.

  • underflow
Les underflows sont générés lorsqu'une opération arithmétique produit un résultat trop petit pour être représenté comme un nombre flottant normalisé (le premier chiffre de la mantisse est différent de zéro). La valeur renvoyée peut être zéro ou la valeur la plus petite représentable selon le type de la variable.

  • overflow
Les overflows sont générés lorsqu'une opération arithmétique produit un résultat trop grand pour être représenté comme un nombre flottant normalisé (le premier chiffre de la mantisse est différent de zéro). La valeur renvoyée est alors l'infini (Inf), signée.

  • divide-by-zero
Une division par zéro se produit lorsqu'un nombre non nul est divisé par un nombre nul. La valeur renvoyée est alors l'infini (Inf), signée.

  • invalid operation
Une opération invalide se produit lorsqu'au moins l'un ou plusieurs opérandes ne sont pas valides pour l'opération implémentée. La valeur renvoyée est une valeur particulière appelée Not a Number (NaN). Cela peut survenir en divisant deux valeurs infinies, en multipliant une valeur infinie par zéro, en additionnant deux infinis de signe opposé, en prenant la racine carrée (ou le logarithme) d'un nombre négatif (ou nul), etc ...

  • inexact operation
Une opération inexacte se produit lorsqu'une perte importante de précision a lieu ou s'il se produit un overflow non détecté, par exemple dans le cas ou la valeur en sortie diffère de la véritable valeur si le calcul des exposants ou des mantisses ne sont pas bornés. La valeur en sortie est la valeur ainsi calculée.

  • integer overflow
Une opération sur les entiers produit une valeur supérieure au plus grand entier représentable dans le format de la variable.

  • tableau récapitulatif

Calcul résultat par défaut type d'exception
grand * (- grand) - inf overflow, inexact
inf / inf NaNQ invalid, inexact
nombre / 0.0 + inf division par zéro
- nombre / 0.0 - inf division par zéro
0.0 / 0.0 NaNQ invalid
petit * petit 0.0 underflow, inexact
inf * 0.0 NaNQ invalid
petit / grand nombre subnormal underflow, inexact
inf / 0.0 inf oveflow, inexact
0.0 / inf 0.0 underflow, inexact
2.0 / 3.0 2/3 (arrondi) inexact

  • représentation des nombres
La représentations des nombres se fait en base 2 en distinguant la mantisse de l'exposant (pour les nombre flottants), chacun ayant un nombre de bits permettant son codage. Cette représentation est architecture-dépendant, il s'agit de la représentation interne des données en mémoire, ce qui signifie aussi que les fichiers non formatés (qui reprennent cette représentation interne) sont généralement inexploitables sur une machine différente de celle qui les a générés si le codage employé n'est pas reconnu.
Par exemple, sous AIX les intervalles de valeurs pour les différents types de données sont :

Type des données base 2 base 10
integer(*4) -2^31 < I < 2^31 -10^9 < I < 10^9
integer(*8) -2^63 < I < 2^63 -10^18 < I < 10^18
real(*4) (i.e. real) 2^(-125) < |R| < 2^128 10^(-38) < |R| < 10^38
real(*8) (i.e. double precision) 2^(-1021) < |R| < 2^1024 10^(-308) < |R| < 10^308

Sur un IBM p690, les underflows surviennent par exemple lorsque |R| < 10^(-38) en simple précision (soit 4 octets) ou 10^(-308) en double précision (soit 8 octets) et les overflows lorsque |R| > 10^38 en simple précision ou 10^308 en double précision.

  • précision des nombres
La précision des nombres concerne uniquement les nombres flottants. En effet, pour un nombre entier soit la valeur que l'on veut affecter à une variable de type entier est dans l'intervalle de valeurs du type considéré soit elle est en dehors de cet intervalle, ce qui est un overflow.
Un nombre réel a comme particularité que son développement décimal peut être infini. Hors on ne peut pas garder toutes ses décimales : on ne peut en garder qu'un nombre fini, on fait donc un arrondi en tronquant son développement. En général, la simple précision correspond à environ 6-7 décimales, la double précision à environ 14-15 décimales et la quadruple à environ 30-31; à l'exception (liste non exhaustive) des machines Cray où la simple précision se situe vers 14-15 décimales et la double précision vers 30-31 décimales.
Lorsque l'on fait un calcul il est important de connaitre la précision employée, cela permet de relativiser le nombre de décimales significatives des résultats et de déterminer si une "petite" valeur a un sens ou bien s'il peut s'agir d'une erreur d'arrondi ou de troncature.


flechehaut

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: