Le Renard bleu ou le terrier du néophyte

"Le début ne laisse pas présager la fin." [Hérodote]

Aller au contenu | Aller au menu | Aller à la recherche

jeudi 21 février 2008

VFP Studio

Merci Mister Boyd... Merci Bo,

Graig Boyd et Bo Durban viennent de puplier sur le site SweetPotato.com un excellent travail sur l'IDE de Visual FoxPro.

On peut le voir à: http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,b71ea97e-8fb8-4401-ace4-b5a536fe0a37.aspx

jeudi 27 décembre 2007

Rushmore

Rushmore est plus qu’une technologie, c’est un mythe.

http://en.wikipedia.org/wiki/Mount_Rushmore

Cela ne devrait cependant pas nous empécher de vouloir découvir ce qu’il y a derrière ce mythe. Il est primordial de séparer les faits de la fiction. Dans la décade précédente la règle était de créer un index sur DELETED() le contraire est vrai aujourd’hui. Pourtant, aucune de ces deux propositions n’est totalement valide en réalité. L’origine de la performance de Visual FoxPro a deux fondements. L’une de ces fondations est Rushmore, l’autre est l’utilisation intensive du cache. La différence de performance avec d’autres systèmes de base de données ayant, comme Rushmore, des algorithmes de recherche centrés sur une image des données, est surtout due à Rushmore, plutôt qu’à la stratégie de l’utilisation du cache et de l’accès optimisé au réseau.

Rushmore est un algorithme centré sur une image des données (Bitmap). Visual FoxPro crée une liste de chaque condition pouvant être optimisé avec Rushmore. Cette liste détermine si un enregistrement respecte ou non les critères de recherche. Visual FoxPro n’utilise qu’un seul bit pour chaque enregistrement, car il n’y a que deux états possible. Huit enregistrements sont contenus dan un octet, Pour une table de 8 millions d’enregistrements, chaque condition de recherche requiert 1 MB de mémoire. Chaque bit est d’abord à 0 – non déterminé – et l’enregistrement correspondant est de ce fait dans le jeu résultant. Lorsque les images sont déterminées elles sont combinées bit à bit. Si la condition suivante est utilisée dans une requête :
NAME = "Smith" AND InvoiceDate < DATE()-60

Cette requête implique la création de deux images indépendantes, chacune contenant tous les enregistrements pour "Smith" et tous les enregistrements ayant une facture depuis moins de 60 jours. Peu importe, dans chaque diagramme que l’autre condition ne soit pas remplie. Après que les deux images aient été combinées bit à bit avec AND il en résulte une image ne comportant que les seuls enregistrements remplissant les deux conditions.
Il n’est pas difficile d’imaginer que le besoin en mémoire pour batir ces images peut rapidement grossir et ralentir une requête. Si une seule condition doit être vérifiée, le vieux style de code xBase peut être utilisé :

SET ORDER TO MonIndex
SEEK Value
SCAN WHILE Champ=Values
_Exécute_quelque_chose
ENDSCAN

Dans bien des cas, c’est même plus rapide qu’une requête Rushmore optimisée car Visual FoxPro n’a pas à créer de bitmap. D’un autre coté, cette technique n’utilise pas le cache de la même manière que Rushmore qui accélère des requêtes répétées sur les mêmes données. Rushmore travaille beaucoup comme la boucle SCAN ci-dessus pour la mise à jour du bit à l’intérieur de cette boucle.

Comment cette boucle est elle effectivement créée? Le facteur principal est que les index dans Visual FoxPro sont stockés comme un B-tree, soit un arbre équilibré qui est composé d'un nombre identique de niveaux dans chaque branche. Chaque nœud est un bloc de 512 octets qui peut contenir jusqu’à 100 pointeurs de nœuds inférieurs. Le nœud le plus proche de la racine de réfère à la clé, seules des nœuds des feuilles correspondent aux enregistrements. Chaque noeud ne se référant pas uniquement à deux autres blocs, comme on pourrait le penser, la hierarchie dans le fichier index peut généralement se retrouver très aplatie. En outre, tous les nœuds sont reliés horizontalement.

Lorsque Visual FoxPro recherche une valeur, il traverse l’arbre verticalement jusqu’à trouver l’enregistrement, puis continue sa lecture horizontalement jusqu’à ce que la valeur de la recherche corresponde à celle de l’index. Cette stratégie d’analyse réduit le nombre de nœuds d’index à lire, mais accroit le nombre de noeuds à modifier lors de la mise à jour de l’index. Lors de la lecture horizontale, met à jour le bit correspondant à chaque enregistrement trouvé, ceci est possible car les entrées d’index contiennent tant les numéros d’enregistrements que les valeurs de clés. Les données étant toutefois stockées compressées. L’opérateur égal fonctionne de cette manière.

D’autres opérations agissent de manière similaire. Par exemple, si des enregistrements qui ne soient pas égaux doivent être trouvés, Visual FoxPro génère d’abord une image de tous les enregistrements, puis en élimine les enregistrements correspondant à l’égalité. De manière comparable pour une recherche sur une inégalité.
Avec Rushmore, Visual FoxPro peut déterminer quels enregistrements n’appartiennent pas au résultat, pas ceux qui en font partie. C’est pourquoi la phase « Rushmore » est suivie par une phase de post-scan. Chaque enrgistrment relevé par Rushmore est lu complétement depuis le disque. Sans une expression optimisée ce serait tous les enregistrements de toutes les tables concernées. Chacun de ces enregistrements est ensuite vérifié pour les conditions non optimisables. En outre, toutes les expressions optimisées sont évaluées à nouveau, un changement pouvant être intervenu depuis la création du bitmap. Un résultat pourrait ainsi ne pas contenir tous les enregistrements correspondant à la requète, mais jamais un enregistrement qui n’y correspondrait pas.

Il y a cependant une exception à cette règle. Pour compter des enregistrements, Visual FoxPro tente d’éviter la phase de post-scan. Lorsque le bitmap est construit et qu’il ne subsiste aucune condition non optimisée, Visual FoxPro commence à compter le résultat. De ce fait COUNT FOR et SELECT CNT(*) FROM sont extrémement rapides si la requète est totalement optimisée. Une optimisation partielle n’est pas suffisante. Il n’est pas non plus profitable d’utiliser d’autres méthodes telles SELECT SUM(1) FROM…
Lorsque de la création du bitmap Visual FoxPro doit lire tous les blocs d’index qui corespondent aux critères de recherche. Lors d’accès répétés Visual FoxPro récupère ces blocs du cache. Toutefois, le cache est ignoré si une station modifie un champ d’index où ajoute un nouvel enregistrement. Visual FoxPro peut seulement déterminer qu’une autre station a changé l’index, mais pas ce qui a exactement changé. Le cache entier est alors ignoré. Vous pouvez exploiter cela pour mesurer la performance. En utilisant une deuxième instance de FoxPro qui remplace un champ d’index dans le premier enregistrement dans une boucle.

Il y a quelque temps il fut constaté qu’un index sur DELETED() n’est pas toujours la solution optimale. Une sorte d’école apparu, condamnant complétement cet index, ce qui n’est pas non plus une bonne idée. Déterminer si Rushmore est la bonne voie est aisé : si plus d’octets sont lus dans le fichier index que d’enregistrements retirés pendant le post-scan, la performance de Rushmore décroit. Une comparaison des octets transférés doit être faite.

Il faut cependant garder en mémoire que le cache a un impact avec Rushmore et que les index CDX sont stockés compressés. Le commencement identique de mots n’est stocké qu’une fois. Le réél montant de données peut être déterminé avec le système de Monitoring de Windows, et de manière plus précise encore avec un moniteur réseau tel NETMON.EXE qui apparu avec Windows 2000 server, ou par Ethereal, disponible gratuitement chez http://www.ethereal.com. Un tel moniteur réseau révèle quelle partie d’un fichier est effectivement lue. Combinée avec la structure des fichiers, un grand nombre de détail peut en être déduit. Si de nombreuses données sont modifiées par une application, le cache est fréquement invalidé. Une telle application bénéficiera moins de Rushmore que, par exemple un catalogue sur CD qui aura placé en cache toutes les données après une courte utilisation.

Une application ayant de nombreux enregistrements annulés tirera aussi bénéfice de Rushmore. Si l’application visite un enregistrement plusieurs fois, l’algorithme requierant par exemple de naviguer vers l’enregistrement précédent ou suivant, Rushmore, par la réutilisation du bitmap, est supérieur aux anciens styles de code xBase qui doivent lire et relire les données.

Pour éviter de longues attentes aux utilisateurs lors des requètes, celles-ci doivent être pleinement optimisables, cela donne un réél avantage, car la création d’un bitmap est significativement plus rapide que l’entière lecture de la table, et le bitmap peut être réutilisé.
Un autre facteur important est la distribution des valeurs dans le fichier index. Il y a une différence considérable entre la recherche d’une valeur unique comme la recherche d’une clé primaire, où dans une donnée ne contenant qu’une dizaine de valeurs, comme un statut. Un exemple extrème en est l’index sur DELETED() pour lequel tous les champs ont généralement la même valeur. De tels index doivent généralement être évités sauf si leur besoin s’impose (pour des comptages par exemple).

Quelques liens remarqués sur Rushmore :

http://www.foxprohistory.org/rushmore.htm

http://support.microsoft.com/?scid=kb%3Ben-us%3B114781&x=10&y=9

http://my.advisor.com/articles.nsf/aid/18772!OpenDocument&Click=

http://bcook.cs.georgiasouthern.edu/cs575/rushmore.htm

http://fox.wikis.com/wc.dll?Wiki~VFP9RushmoreAndCodepage~VFP

http://f1technologies.blogspot.com/2006/01/vfp-gridoptimize-gotcha.html

http://wwwmsdner.com/dev-archive/38/17-60-382155.shtm

mercredi 31 octobre 2007

Au coeur de Visual FoxPro (suite)

Gestion de la Mémoire

La gestion de la mémoire dans Visual FoxPro n’est pas moins complexe. Il y a eu deux versions de FoxPro 2.x, une version 16-bit et une 32-bit utilisant une extension du DOS. L’extension du DOS changea elle même ente 2.0 et 2.6. Il existe pour les applications DOS différents types de mémoire qui sont tous régis par différents gestionnaires de mémoire. Il existe les modes concurrents XMS et EMS. Il y a HIMEM qui étend la mémoire conventionnelle et DPMI, l’interface Mode Protége du DOS, qui est encore supportée par Windows. Tous ces types de mémoire ont été pris en compte par les différentes versions de FoxPro, et du code en reste présent dans Visual FoxPro, quoiqu’il ne soit plus utilisé. Par exemple, la plupart des fonctions de contrôle de la mémoire, non documentées entre SYS(1001) et SYS(1016) sont toujours opérationnelles. Microsoft ajouta d’autres modèles de mémoire dépendant des versions de Windows. Même dans la version 32-bits actuelle de Windows plusieurs types de mémoire cohabitent. (Mémoire physique, fichiers d’échange–swap, locale, globale, virtuelle, paginée, etc.)

Au dessus de la mémoire physique et des différents modèles de mémoire mis en œuvre par le système d’exploitation, VFP gère son propre système. VFP distingue 5 types de mémoire: piles, tampons hors écrans, handle pool, page pool, et fichiers temporaires. La pile est utilisée pour les processus temporaires, et n’est pas significative pour le développeur. La pile apparaît généralement dans des conditions d’erreurs telles que "insufficient stack space" (Espace de pile insuffisant Erreur 1308). Seuls les développeurs C/C++ écrivant un FLL ont a se préoccuper de la pile.

Le groupe d’handles, “Handle Pool”, est la mémoire utilisée pour différents objets VFP tels les fenêtres, les menus, les classes, les objets, les curseurs, les sessions etc. Ce pool n’a aucune limite arbitraire et ne dépend que de la quantité de mémoire disponible. Visual FoxPro met en œuvre un modèle astucieux prohibant l’accès direct à la mémoire, rendant ainsi portable VFP sur différentes plateformes (Windows, Unix, Mac).

De nombreuses données doivent être gardées en mémoire. Cela inclu variables, menus, fenêtres, chaînes mais aussi définitions de classe, formulaires, et plus encore. Chaque fois que Visual FoxPro requiert de la mémoire, le gestionnaire de mémoire est appelé avec la taille de bloc de mémoire demandé. Plutôt que de retourner une adresse, il renvoie un gestionnaire de mémoire (memory handle). Cela peut s’assimiler à une sorte de clé primaire. A chaque fois qu’un programme veut accéder à cette mémoire, Il doit auparavant verrouiller la mémoire un peu comme un enregistrement doit l’être. L’adresse peut ensuite être déterminée par une fonction interne. Lorsque cet accès mémoire est terminé, le code doit déverrouiller le handle, de manière similaire au déverrouillage d’un enregistrement.

La finalité de ces verrous est cependant différente de ceux concernant les enregistrements. Il ne s’agit pas de prévenir des accès concurrents à la mémoire, mais d’éviter la dispersion des blocs. Lorsque des blocs sont constamment alloués et libérés, au fil du temps la mémoire devient fragmentée. Cela arrive de la même manière aux disques durs lors de la création et de l’annulation de fichiers. Après un certain temps, cela peut conduire à une situation ou il y a suffisamment de mémoire disponible, mais ou aucun bloc n’est assez grand pour contenir la donnée requise. Cela serait fatal à un système de base de données qui devrait tourner sans cesse pour des jours ou des semaines, et ou une telle situation conduirait au crash.
Pour éviter cela, le ramasse miette (garbage collection) est susceptible de déplacer les blocs mémoire. En interne, Visual FoxPro exécute une sorte de défragmentation lorsqu’il est inactif (idle). Mais la défragmentation n’a pas été la seule raison de mettre en œuvre ce modèle. La mémoire n’est pas en outre toujours disponible en lecture. Par exemple, la mémoire étendue DOS devait être transposée en mémoire conventionnelle avant que les versions étendues de FoxPro puissent y accéder. Lorsqu’un handle FoxPro est verrouillé, les fonctions de gestion de FoxPro peuvent s’assurer que ce bloc mémoire est immédiatement disponible en lecture pour le programme appelant. Après le déverrouillage, FoxPro peut réaffecter au bloc sa position originale.

Une partie du Handle Pool est visible aux développeurs par la commande LIST MEMORY mais pas tous les handles. Visual FoxPro fait aussi un usage intensif des handles en interne. Toutes le fenêtres d’édition sont par exemple de tels handles. Ainsi il est possible d’utiliser ACTIVATE WINDOW non seulement pour nos propres fenêtres, mais pour toutes les fenêtres FoxPro, y compris les barres d’outils. Avec Visual Foxpro, le Handle Pool n’est limité que par la mémoire physique disponible, ou par la mémoire virtuelle.
La fonction SYS(1001) retourne la taille maximale du Handle Pool. La fonction, (non documentée) SYS(1011) retourne le nombre de handles alloués. Cette fonction se doit de retourner la même valeur avant, et après l’appel d’une fonction. Toute autre valeur indique une fuite de mémoire. SYS(1016) renvoie la taille de la partie du Handle Pool déjà allouée. SYS(1104) initie manuellement un garbage collection. Cette dernière fonction est officiellement documentée depuis VFP 7.0. Toutes ces fonctions renvoient des valeurs variables lorsqu’elles sont exécutées dans la fenêtre de commande, car cette fenêtre de commande initie constamment un état d’attente et donc une purge des tampons (garbage collection). Certaines fonctions filtrent en interne les handles utilisés, d’autres non. Quoiqu’il en soit, ces fonctions sont de bons indicateurs de l’utilisation de la mémoire.
Pratiquement, tout ce qui n’est pas temporaire est mémorisé quelque part dans le Handle Pool cela inclus les transactions et les modifications dans un tampon mémoire en attente de validation par une commande TABLEUPDATE().

Le groupe de pages (Page Pool) est la zone mémoire contrôlée par SYS(3050). Visual FoxPro y stocke les images crées par Rushmore et l’utilise pour le cache des tables et index. Cette partie de la mémoire est essentiellement responsable de la vitesse remarquable de Visual FoxPro Tout ce qui est lu du disque est mis là en cache pour une utilisation ultérieure. La taille maximum de cette zone mémoire peut être contrôlée en adaptant la mémoire allouée par Visual FoxPro aux zones tampon de premier plan et d'arrière-plan. La zone tampon de premier plan représente celle qui permet à Visual FoxPro de fonctionner au premier plan en tant qu'application actuellement active. La zone tampon d'arrière-plan représente la mémoire qui permet à Visual FoxPro de fonctionner à l'arrière-plan lorsqu'une autre application est au premier plan. Cela signifie qu’il est possible d’indiquer à Visual FoxPro d’utiliser plus ou moins de mémoire si l’utilisateur travaille sur l’application ou non. Cette mémoire n’est pas allouée immédiatement, mais suivant nécessité. Une très grande valeur peut donc être attribuée sans avoir à craindre qu’elle soit immédiatement utilisée.
SYS(3050) essaye d’allouer la mémoire de Windows qui ne soit pas “swappée” vers le disque. Il n’y a toutefois aucune garantie. Il y aura un effet sensible sur la performance si Visual Foxpro essaye d’allouer de la mémoire pour des caches qui ne puisse exister que par une mémoire virtuelle sur le disque dur. Réduire la valeur de SYS(3050) libère immédiatement toute mémoire superflue. La valeur minima étant 256 KB (pas MB) le code suivant peut être utilisé pour libérer la mémoire au-delà de 256 KB:

lcMemory = Sys(3050,1)
Sys(3050,1,1)
Sys(3050,1,Val(lcMemory))

Pour autant, avoir le contrôle complet sur le Page Pool n’assure pas que ce soit vrai pour l’utilisation de la mémoire. Si Visual FoxPro pense devoir utiliser plus de mémoire, par exemple pour stocker une image d’optimisation RushMore, il n’hésitera pas à créer un fichier temporaire si le Page Pool n’est pas assez vaste. FoxPro continuera à s’exécuter, même si la valeur spécifiée de SYS(3050) est trop faible, peut être à la même vitesse, mais peut être plus lentement voire plus rapidement. Cela dépendra du type de mémoire assignée à Visual FoxPro et de la rapidité du support concerné. Celui utilisé par Windows pour la mémoire virtuelle, ou celui utilisé par Visual FoxPro pour stocker les fichiers temporaires? Windows pouvant aussi utiliser un cache pour les fichiers temporaires, la rapidité de l’application pourrait s’avérer soudainement plus rapide.

Le répertoire utilisé pour les fichiers temporaires dépend des réglages sauvegardés dans le registre: la clé TMPFILES=… (pas TEMPFILES!) et de différents réglages de Windows. Parfois, toutefois, Visual FoxPro est susceptible de discrètement permuter vers un autre répertoire. Cela semble causé par nombre de facteurs. Dans tous les cas il est possible de vérifier la valeur courante de SYS(2023) qui peut différer du répertoire normalement utilisé par Windows pour les fichiers temporaires. La pire situation serait celle où Visual FoxPro utiliserait le répertoire Home de l’utilisateur, ou le répertoire des programmes, ceux-ci se trouvant souvent sur le serveur. Pour s’assurer de la destination réelle des fichiers temporaires, un curseur test peut être créé dont la position sera vérifiée par la fonction DBF(). Car même si un curseur est généralement créé dans le répertoire indiqué par SYS(2023) il se peut que ce ne soit pas toujours être le cas.

vendredi 5 octobre 2007

Au coeur de Visual FoxPro (suite)

Variables, Tableaux et Objets

L’une des questions les plus fréquemment posée par les développeurs qui viennent juste d’apprendre que Visual FoxPro ne peut gérer que 65.000 variables est de savoir si cela s’applique aussi aux éléments de tableaux. Aucun doute: NON. Un tableau ne compte que comme une variable, quel que soit le nombre d’éléments qu’il contienne. Le nombre d’éléments étant aussi limité à 65.000 vous pouvez créer jusqu’a 65.000 tableaux de 65.000 éléments. Une masse de données peut être placée en mémoire avec Visual FoxPro. Quoique aucune application performante ne vienne approcher ces limites en raison de la rapidité. La cause de toutes ces limitations est une fois encore la table des noms. En fait, Visual FoxPro sait seulement y gérer des variables, de simples variables. Et le traitement des tableaux, et plus tard des objets a été adapté à ce design. Mais qu’est ce qu’une variable dans Visual FoxPro? Les Variables dans FoxPro peuvent contenir des données de tout type. Cependant, comme Visual FoxPro est lui même écrit en C, les variables de FoxPro, doivent aussi à un moment être stockées dans un format C similaire à celui ci:

typedef struct {

 char              ev_type;
 char              ev_padding;
 short             ev_width;
 unsigned          ev_length;
 long              ev_long;
 double            ev_real;
 CCY               ev_currency;
 MHandle           ev_handle;
 unsigned long     ev_object;

} Value;

Outre le type, il y a l’indication de chaque type de données supporté. Visual FoxPro utilise différents champs en fonction du type de donnée à stocker. La structure explique pourquoi les chaînes peuvent contenir n’importe quels caractères (leur longueur étant stockée séparément) et comment Visual FoxPro gère les décimales dans les valeurs à virgule flottante pour autoriser des différences entre 1.0 et 1.00. La chaîne même, et les objets dont la taille peut varier considérablement ne sont pas stockés directement dans cette structure. Pour accéder aux chaînes, Visual FoxPro utilise ce qui est appelé “memory handle”. Les objets sont identifiés par une valeur 32-bit peu documentée, curieusement il n’est pas fait état des tableaux. Pour chaque nouvelle variable créée par un programme, Visual FoxPro alloue un bloc mémoire avec cette structure Son adresse doit être stockée quelque part, tout comme le nom, qui ne fait pas partie de la structure. La sauvegarde de ces informations est dévolue à la table des noms. Chaque entrée de la table contient, outre le nom et l’étendue, les détails relatifs au type de l’entrée (variable, champ, alias, etc.) et son emplacement dans la mémoire. Cette liste est limitée à 65.000 entrées, et par conséquent détermine le nombre maximum de variables. Un tableau, cependant ne peut être stocké dans une structure unique. Chaque élément en est stocké dans une structure comme une variable. C’est le seul moyen de pouvoir stocker des items de différents types dans le même tableau. Comme dans l’exemple suivant, où tous les éléments du tableau sont définis comme NULL:

LOCAL laArray
laArray = .NULL.

Cette simple entrée est celle utilisée pour passer un tableau par référence. Le tableau lui même, par ailleurs, est la simple liste d’une table qui contient les pointeurs de tous les éléments individuels. La référence au tableau dans la table des noms contient un pointeur vers cette liste. Il n’y a évidemment pas de moyen pour accéder directement à un élément du tableau comme vous pourriez le faire pour une variable. Lorsque l’index de la table des noms (NTI), utilisé par VFP pour identifier de manière unique une entrée de la table des noms, est passé à une fonction en retournant un élément, seul la référence au tableau entier sera renvoyée, une autre fonction recevra cette valeur pour retourner l’élément particulier. Les objets sont stockés de manière similaire. La valeur dans la structure est l’adresse d’un autre nom de table. Pour chaque objet, Visual FoxPro semble créer un nouveau nom de table. Cette voie a probablement été choisie parce que la table des noms gère déjà le nom et l’étendue. Les propriétés dans Visual FoxPro sont en fait des variables gardées dans une place cachée. Plus étonnamment, c’est aussi vrai pour les méthodes, qui sont aussi des variables. Pour cette raison vous ne pouvez créer une classe ayant plus de 65.000 méthodes, propriétés et événements.

Cette conception offre nombre d’avantages, car sinon, les tableaux et les propriétés consommeraient rapidement l’espace disponible de la table des noms. L’inconvénient le plus évident, toutefois, est le passage des paramètres par référence, utilisant le caractère @. Dans ce cas, VFP ne copie des valeurs, comme il le fait d’habitude, mais purement le NTI, l’index de table des noms Il est gentiment demandé à la fonction appelante de mettre le résultat dans la variable numéro x. Cependant un tableau a uniquement un tel index de table des noms. Il n’y a aucune possibilité de spécifier dans quel élément le résultat devrait être écrit. Par conséquent, vous pouvez seulement passer un tableau entier par référence. Dans VFP il est impossible de passer un seul élément par référence. Vous devez copier l’élément dans une variable, passer une référence à cette variable et mettre à jour la valeur dans le tableau. Il en est de même pour les propriétés d’objet. En théorie vous ne pouvez passer une propriété par référence, car c’est une partie intrinsèque de l’objet. Le passage d’une propriété par référence briserait l’encapsulation. La vraie réponse, pourtant, est que la propriété ne possède pas d’entrée dédiée dans la table des noms, et que le passage par référence est donc impossible.

Les propriétés dont la valeur est un tableau sont bien entendu particulièrement affectées par cette conception. Ni les tableaux, ni les propriétés ne peuvent être passées par référence. Vous n’avez donc pas d’autre possibilité que de copier le tableau dans une variable locale, et passer par cette alternative, puis recopier le tableau entier, en utilisant ACOPY() dans les deux cas. Associé avec les méthodes access et assign cette manière de procéder a même plus d’inconvénients que simplement réduire la vitesse d’exécution. Heureusement, VFP 8 apporta la classe collection qui ressemble beaucoup à un tableau, et peut contourner cet obstacle.

L’accès aux variables a été optimisé par VFP. Visual FoxPro traduit à la compilation les noms en des valeurs entières facile à gérer. Les lignes:

LOCAL lcName, lcZIP
? lcName

Sont converties dans le pseudo code suivant lors de la compilation:

LOCAL #1, #2
? #1

Dans le fichier FXP qui en résulte, toutes les variables sont listées à la fin du fichier. A l’intérieur du code compilé, des valeurs 16 bits en indiquant la position sont alors utilisées.

A l’exécution du programme compilé, VFP créé une liste qui assigne un nom dans l’index de la table des noms à chaque variable du code. La longueur du nom de la variable n’est pas pertinent, des noms de variables longs, souvent mieux lisibles, n’ont pas d’effets significatifs sur la vitesse d’exécution. La situation diffère concernant les tableaux, une fonction interne de VFP évalue le paramètre passé par la table des noms pour accéder à l’élément du tableau. Accéder aux éléments d’un tableau est par conséquent toujours plus lent que d’accéder à une variable. Pour compliquer encore les choses, VFP accepte les parenthèses et les crochets, aussi bien pour les tableaux que pour les fonctions. Il n’y a pas distinction claire entre les deux à priori, et VFP doit vérifier si un tableau du même nom existe à chaque appel de fonction. C’est un peu plus difficile pour l’accès aux objets. Une fois encore, les noms de propriétés sont convertis en nombres par l’usage du même algorithme. Cependant objet1.name n’est pas tout à fait la même chose que objet2.name Si VFP rencontre un code tel que :

LOCAL loLabel
loLabel = CREATEOBJECT("Label")
? loLabel.Caption

Il ne lui est pas difficile de déterminer la référence à loLabel de la 3ème ligne. La fonction pour obtenir une valeur de la table des noms retourne une structure qui représente l’intégralité de l’objet. L’étape suivant est beaucoup plus complexe. Les objets contiennent leur propre table de noms. La liste permettant la conversion des noms vers la NTI n’est dès lors d’aucune utilité. VFP doit chercher le nom du code (Caption dans l’exemple) dans la table de l’objet et en charger à chaque fois la structure, cela revient à utiliser le nom réel plutôt que d’utiliser une valeur de l’index et les résultats ne peuvent être traités comme de simples valeurs. L’accès aux propriétés d’un objet est ainsi plus long que l’accès à une variable ou à un élément de tableau.

Cela explique pourquoi WITH…ENDWITH peut notablement améliorer la performance. La structure des valeurs de noms de propriétés pour l’objet est simplement gardée en mémoire, et rend inutile la première partie de la recherche. Cela explique aussi l’intérêt d’utiliser intensivement des variables locales qui en contiendront la valeur, et dont le traitement sera beaucoup plus rapide que celui des propriétés.

mardi 17 juillet 2007

Au Coeur de Visual Fox Pro

Ce billet entame une description sommaire du fonctionnement interne de FoxPro



Il est inspiré du travail de Christof Wollenhaupt, Foxpert

How FoxPro works internally FoxPro Inside Out

A l’origine, xBase était un outil de manipulation des données, pas un langage de programmation. Les utilisateurs n’en étaient pas des développeurs, mais des experts dans une variété considérable de domaines qui utilisaient pour gérer leurs données FoxBase, dBase, etc. FoxPro devint un environnement de développement qui évolua en 1995 de la programmation procédurale vers les concepts orientés objet. Contrairement à la plupart des langages, Visual FoxPro contient toujours ses racines. Du code écrit dans les années 80 peut tourner aujourd'hui en VFP 9 prés de 20 ans après avoir été écrit. Visual FoxPro offre une compatibilité ascendante presque totale. L’orientation Objet réside au dessus des couches de FoxPro, pas le contraire, ce qui explique bien des comportements de VFP.

L’index de table des noms (Name Table Index - NTI)

Visual FoxPro assigne un nom (name) à différents items: variables, noms de tableaux (array), procédures, fonctions, alias de tables, noms de champs et d’objets. Chacun de ces éléments reçoit un label et une plage de référence. La visibilité (l’étendue) d’une variable dépend de son type, alors que l’étendue d’un alias est la session de données. Un nom de champ doit être unique dans une table et une procédure est visible dans un fichier programme.
A chaque création de variable, ouverture de table, etc, Visual FoxPro crée une nouvelle entrée dans une liste interne, la Table des Noms (Name Table). La position interne à cette liste est l’index de la table des noms Name Table Index – (NTI). Chaque nom dans cette liste reçoit un numéro unique entre 1 et 65,000, (c’est une valeur 16-bit). C’est la raison de la limitation du nombre de variables à 65,000. Réduite du nombre de zones de travail allouées et d’instances d’objets (depuis Visual FoxPro 6.0).
Cette liste est purgée par un processus appellé Garbage Collection, terme se référant à la suppression des entrées invalides de la liste, la libération des tampons périmés, le compactage de la mémoire utilisée, la vérification de l’accès aux fichiers temporaires, etc.
VFP l’exécute dans l’idle loop. VFP entre dans cette boucle dès qu’une condition d’attente intervient: READ, READ EVENTS, INKEY(), ou WAIT WINDOW, même si une option nowait est indiquée.
WAIT WINDOW "" NOWAIT est un “truc” utilisé pour vider la mémoire.

Apparu dans la documentations de VFP 7.0 SYS(1104) permet, depuis au moins Foxpro 2.6, de déclencher une Garbage Collection, ce n’est pas identique à un état d’attente, car celui ci en fait un peu plus, comme l’affichage des messages systèmes. En exécution d’un programme, VFP n’éxécute pas idle loop. Jusque VFP 5.0 cela avait l’inconvénient d’un encombrement de la table des noms, avec des conséquences sur la performance, mais aussi la stabilité. A chaque nouvelle entrée dans la table, VFP vérifie la possibilité de conflits potentiels. Par exemple, une variable PUBLIC ne peut être créée si une variable LOCAL de même nom existe, un ALIAS identique dans la même session de données etc. Ce processus de vérification entraine une dégradation exponentielle des performances quand la table des noms grandit (de quelques naosecondes à la minute du 1er au 60000ème objet).

Les applications qui n’atteignent jamais un état d’attente comme des routines d’import ou des fournisseurs de services deviennent de plus en plus lentes pendant leur exécution. D’autres fonctions (Comme le recalcul d’une vue, REQUERY() ) requièrent une entrée nouvelle dans la table des noms. Le ralentissement n’est pas le seul problème, lorsqu’une application approche de la limite, elle devient instable, avec un peu de chance, VFP emet le message « Too many names used » (Error 1201) mais, le plus souvent elle “plante”.
VFP 6.0 a beaucoup amélioré ce comportement en lançant un garbage collection automatique lorsque la table des noms approche 95 % de la limite.

VFP 7.0 apporta une amélioration majeure. Toutes les versions précédentes comptaient les objets.
Quand 2 labels étaient créés:

LOCAL loLabel1, loLabel2
loLabel1 = CreateObject("Label")
loLabel2 = CreateObject("Label")

Visual FoxPro ajustait la propriété “name”. Le premier label étant appelé “Label1”, le second “Label2” pour cela, VFP enregistrait chaque objet dans la table des noms.
En conséquence, chaque création d’objet durait plus longtemps que la précédente. L’utilisation de SYS(2015) dans l’évènement init pouvait bypasser cela jusqu’à un certain point. Quoiqu’il en soit, ce comportement limitait le nombre d’objets qui pouvaient être instanciés à 65000.
De VFP 3.0 à VFP 6.0 il n’était pas possibe de créer plus de 65000 objets, y compris ceux contenus dans les formulaires. Cette limite atteinte, le générateur de Formulaires ne pouvait même pas être ouvert.

A partir de VFP 7.0 un nom unique n’est plus requis pour les objets, dont le nom n'est plus enregistré dans la table des noms. De ce fait la limite de 65000 objets peut être dépassée, et la rapidité en est accrue. L’inconvénient est que les noms d’objets ne sont plus uniques, un petit prix à payer.

mercredi 30 mai 2007

Optimiser le code

Comme souvent, Thierry Nivelet nous remet en mémoire quelques règles de bonne conduite.

A lire absolument : http://www.atoutfox.com/articles.asp?ACTION=FCONSULTER&ID=0000000446

La fenêtre de commande (Command Window)

C’est une fenêtre système de Visual FoxPro, le premier élément d’interface avec le Menu, elle est « Dockable » et est accessible par le raccouci clavier Ctrl+F2. Quasiment toutes les commandes VFP pouvant être lancées au sein d’un programme peuvent l’être de la fenêtre de commande. Le clic sur une des commandes de menu affiche les commandes équivalentes du langage dans la fenêtre de Commande, elles peuvent également être tapées directement dans la fenêtre de Commande.
Cette dernière vous permet notamment de :
• Ré exécuter une commande en positionnant le curseur n'importe où dans la ligne de commande, puis en appuyant sur ENTRÉE.
• Ré exécuter un bloc de code en le sélectionnant, puis en appuyant sur ENTRÉE.
• Fractionner de longues commandes en tapant, dans la fenêtre Commande, un point-virgule précédé d'un espace à l'endroit du fractionnement, puis en appuyant sur ENTRÉE. • Déplacer du texte à l'intérieur de la fenêtre Commande ainsi que vers d'autres fenêtres d'édition, en sélectionnant le texte désiré, puis en le faisant glisser jusqu'à l'endroit souhaité.
• Copier du texte dans la fenêtre Commande et le coller dans d'autres fenêtres d'édition sans utiliser les commandes du menu Édition, en sélectionnant le texte désiré, en maintenant la touche CTRL enfoncée et en faisant glisser le texte jusqu'à l'endroit souhaité.
• Supprimer du texte en appuyant sur ÉCHAP si vous n'avez pas encore appuyé sur ENTRÉE afin d'exécuter la commande.
Outre différentes possibilités de pagination, (Indentation, Commentaires) Il est possible de modifier la police, l'interligne, les mises en retrait en cliquant sur la commande appropriée dans le menu Format.
En cliquant sur le bouton droit de la souris dans la fenêtre Commande, s’affichera un menu contextuel contenant différentes options.
L'utilisation pour des tests de la fenêtre de commande permet souvent d'éviter l'édition d'un .prg pour le même résultat.
Le contenu de la fenêtre de commande est sauvegardé dans un fichier (_Command.prg par défaut) à la sortie de Visual FoxPro, qui est relu au démarrage.

J'aborderai prochainement la "TaskPane", et en particulier le gestionnaire d'environnement qui m'est d'un grand secours.

dimanche 20 mai 2007

Environnement de développement (IDE)

Nous avons souvent la tentation de mettre la charrue avant les boeufs, pressés par le temps, de vouloir aller au plus vite pour livrer nos applications, et de ce fait négligeons le nécessaire apprentissage de notre outil de développement.
VFP9 apporte de nombreuses améliorations de l’interface utilisateur, et des outils associés (TaskPane, ToolBox, DocumentViewer, ObjectBrowser, IntelliSence etc.) Une bonne utilisation de l’interface de développement amènera amélioration des performances et confort.
L’environnement de développement peut être adaptés à vos besoins propres. Ces règlages s’effectuent pour l’essentiel au chapitre Outils->Options. Ils sont sauvegardés dans le fichier Foxuser où le fichier « Ressource » défini dans l’onglet « Files ». La suppression du fichier Ressource résout parfois des problèmes de comportement d’affichage, consécutifs à des manipulations de fenêtres malencontreuses. Certains réglages peuvent être définis dans le fichier Config.fpw lu au démarrage de VFP. Enfin un programme (.prg) peut contenir des instructions de démarrage.

Le premier outil de l'IDE est bien entendu la Fenêtre de commande (Command window) Quasiment toutes les commandes VFP pouvant être lancées au sein d’un programme peuvent l’être de la fenêtre de commande. Elle est accessible par le raccouci clavier Ctrl+F2.

J'aborderai dans les billets suivants la présentation de ses aspects les plus intéressants.

jeudi 5 avril 2007

Liste des fonctions de Visual FoxPro 9

Sur le lien ci dessous : un article présentant, en Français, la liste exhaustive, par ordre alphabétique des fonctions de Visual FoxPro9.
http://www.rf-informatique.com/FONCTIONS_Visual_%20FoxPro_9.html

jeudi 29 mars 2007

Bleu le Renard

Quelques images de LaMu
http://www.lamu-design.com/

Lire la suite

lundi 26 mars 2007

Portée des variables

Les variables utilisées dans Visual FoxPro peuvent avoir une portée (étendue) différente suivant la manière dont elles ont été déclarées. De cette déclaration dépendra leur visibilité par les programmes, procédures, et objets; ainsi que leur durée de vie.

Il existe 3 sortes de variables, dont font aussi partie les variables issues du passage de paramètres. On distingue les variables locales, privées et publiques (globales). Par défaut une variable est privée (private) et le fait de créer une variable par exemple par lnvar=150 crée une variable privée. L'aide de Visual Foxpro 6 donne les définitions suivantes :
Variable
Emplacement de la mémoire de l'ordinateur dans lequel sont stockées des données. Vous pouvez modifier le contenu d'une variable, mais son nom et sa zone de stockage sont réservés jusqu'à ce que vous terminiez la session Visual FoxPro ou que vous supprimiez la variable. Les variables et leurs valeurs ne sont pas conservées, sauf si vous les enregistrez sur disque avant de quitter Visual FoxPro.
Durée de vie
Terme se rapportant à une variable qui continue d'exister après qu'un appel de fonction ou un programme soit terminé. Les variables globales continuent d'exister, mais pas les variables locales.

Variables PRIVEES - Commande PRIVATE
Variable supprimée dès que la routine dans laquelle elle est définie prend fin. Les variables privées sont utilisées par défaut dans Visual FoxPro et ne nécessitent aucun mot réservé particulier pour être définies. Leur étendue peut néanmoins être limitée à l'aide du mot réservé PRIVATE s'il existe déjà une variable du même nom à un niveau supérieur. PRIVATE ne crée pas de variable, contrairement à LOCAL et PUBLIC qui créent les variables avec une valeur logique à .F. (Faux).

Variables LOCALES - Commande LOCAL
Les variables locales et les tableaux locaux de variables peuvent uniquement être utilisés et modifiés au sein de la procédure ou de la fonction dans laquelle ils ont été créés.
Un programme de niveau supérieur ou inférieur n'y aura pas accès. Une fois que la procédure ou la fonction qui les contient a terminé son exécution, les variables et tableaux de variables locaux sont supprimés.
Les variables et tableaux créés à l'aide de LOCAL sont initialisés à la valeur Faux (.F.). Il convient de déclarer "Local" une variable ou un tableau avant qu'une valeur ne lui soit affectée. Si une valeur à la variable ou au tableau est affectée avant de l'avoir déclaré comme local à l'aide de LOCAL, Visual FoxPro renvoie un message d'erreur.
Les variables locales peuvent être passées par référence.
La commande LOCAL ne doit pas être abrégée, (il y aurait confusion avec la commande LOCATE).

Variables GLOBALES - Commande PUBLIC
Ces variables (variable publique) sont définies à l'aide du mot réservé PUBLIC, elles sont accessibles à toutes les procédures et fonctions, et pas seulement à celles dans lesquelles elle sont définies.

LPARAMETERS Affecte des données provenant d'un programme appelant à des variables, et crée des variables ou tableaux locaux au sein d'un programme, d'une procédure ou d'une fonction utilisateur appelés. PARAMETERS permet de créer des variables ou tableaux privés.

Les bonnes règles de la programmation objet avec Visual FoxPro, et le souci de la performance, recommandent d'éviter, autant que possible, l'utilisation de variables publiques, et de privilégier leur remplacement par les propriétés des objets.

mercredi 14 mars 2007

De la Rigueur de l'écriture

Visual FoxPro est un langage permissif, c'est sûrement le principal reproche qu'on puisse lui faire, même si on peut apprécier, parfois, ces facilités et cette souplesse.
Ainsi on peut déclarer à n'importe quel endroit du code une variable d'un nom et d'un type quelconque, et affecter une valeur d'un autre type, plus tard dans le code.
Ces pratiques, ne sont, bien sur, pas recommandables, elles peuvent produire des effets catastrophiques, entraînant des erreurs mal maîtrisées. La rigueur dans l'écriture du code doit donc être l'un des leitmotivs du développeur Visual FoxPro. Quelques bonnes habitudes doivent permettre au programmeur débutant d'éviter ces ecueils. Donnez à vos objets et à vos variables des noms les identifiant clairement. Concernant les variables, adoptez la convention suivante: Prefixez l'étendue et le type de données: Pour l'étendue :
l Locales - p Privées (par défaut) - g Publiques (Globales) - t Paramètres Pour le Type :
a - Tableau c - Caractère y - Monétaires d - Date t - DateHeure (Time) b - Double f - Flottant l - Logique n - Numérique o - Objet u - Inconnu

Ainsi, une variable locale de type caractére sera nommée par exemple lcChaine, et à la lecture du code, on s'attendra à ce que son contenu soit effectivement une chaîne de caractères de portée locale.

Vous trouverez ici une liste pour les types de données de VFP9

Et ce tableau suggère une convention pour les objets de VFP9

Le fait de préfixer suivant ces convention, ne présagera pas de la réalité du contenu de la variable, mais rendra le code plus lisible, et vous guidera dans la recherche d'erreurs éventuelles.

J'explorerai dans un prochain billet la portée des variables. Les remarques et les notes à cet égard sont les bienvenues. Richard

lundi 26 février 2007

Vingt fois sur le métier...

Vingt fois sur le métier remettez votre ouvrage; Polissez-le sans cesse, et le repolissez.

Nicolas BOILEAU, L'Art poétique

Lire la suite