Optimisation de la gestion du cache avec 4D 2004

Jérôme Tarantino

Maîtriser l’utilisation du cache est de la plus haute importance si vous souhaitez optimiser vos bases. Comprendre les mécanismes sous-jacents et l’influence de la structure de votre base permet de paramétrer le cache de manière optimale. Regardons ceci de plus près et voyons ce qu’apporte 4D 2004. ♪

- Titre : Optimisation de la gestion du cache avec 4D 2004

- Auteur : Jérôme Tarantino

- Parution : 1 mars 2005

- Licence : Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- I. À qui s’adresse ce document ?

- II. Notions prérequises

- III. Terminologie

- IV. Mémoire principale

- V. Accès disque

- VI. Cache de 4D

- VII. Taille optimale du cache de 4D

- VIII. Améliorations apportées par 4D 2004

- IX. Comment configurer le cache de 4D pour obtenir un résultat vraiment optimal ?

- X. Conclusion

I - À qui s’adresse ce document ?

Ce document s’adresse à toute personne souhaitant paramétrer le cache de manière optimale. Autrement dit à tout développeur souhaitant obtenir les performances maximales de sa base. Il s’adresse également aux curieux cherchant à connaître en détail les améliorations apportées à 4D 2004.

II - Notions prérequises

Vous devez être familier avec les notions d’index, de chargement des enregistrements et de sélections. Il sera fait référence aux transactions et tables d’allocations, toutefois leur maîtrise n’est pas primordiale à la compréhension de l’article. Certaines autres notions élémentaires seront expliquées au cours de l’article ou dans le lexique.

III - Terminologie

Dans ce document, le terme « 4D » désigne indifféremment toute application de la gamme 4D : 4e Dimension, 4D Serveur ou 4D Runtime. Les termes en italique sont référencés dans le lexique.

IV - Mémoire principale

La mémoire principale est nécessaire à l’ensemble des process (applications, services) pour calculer, transférer ou transformer les données. Aucune donnée ne peut être traitée sans passer par la mémoire principale. Sous Windows 2000/XP ou MacOS X, l’attribution est effectuée par le gestionnaire de mémoire et conservée en mémoire physique (RAM) tant qu’elle est suffisante. Dans le cas où celle-ci viendrait à manquer, le système se charge de stocker sur disque dur les blocs de mémoire les moins récemment ou fréquemment utilisés(1) et libère ainsi de la place pour les opérations en cours.

Ce type de mémoire est appelé « mémoire virtuelle », car les adresses mémoire utilisées ne correspondent pas à une adresse physique, mais à une référence qui pointe vers un bloc situé, selon les cas, en RAM, sur disque ou non encore alloué. Le gestionnaire divise les blocs de mémoire virtuelle en sous-blocs (appelés pages) qui ne sont réellement alloués qu’à leur première utilisation. Ce sont également ces pages et non les blocs entiers qui sont parfois stockées sur disque. On appelle d’ailleurs ce type de mémoire virtuelle : « mémoire paginée ».

Sur ces OS, l’utilisation du disque est complètement transparente parce que l’échange entre une page devant être chargée et une autre devant être écrite sur le disque (opération appelée « swap ») est rare et optimisée(2). L’application est assurée que ses données sont en RAM quand elle les utilise.

Sur une machine disposant de 1,5 Go de RAM, l’ensemble des process peut demander 2 Go sans qu’il y ait de swap. Les swaps ne commencent que lorsque la mémoire réellement allouée atteint 1.5 Go. Ils sont alors imperceptibles si au moins une partie de la mémoire virtuelle n’est pas utilisée (par exemple lorsqu’un process ne travaille plus). Si l’activité de la machine augmente, les swaps deviennent importants et les performances commencent à chuter.

V - Accès disque

Parallèlement à la gestion de la mémoire, le système prend en charge les accès au disque. Là encore MacOS X et Windows XP présentent de grandes similitudes.

Sur les machines actuelles(3), un accès disque est généralement 50 à 2000 fois plus lent qu’un accès mémoire (dans le cas respectivement de grosses et petites données). Cette différence notable incite les fabricants à ajouter une mémoire cache interne au disque dur (de 4 à 16 Mo). Par ailleurs, cette dernière étant généralement insuffisante, l’OS gère un cache disque supplémentaire avec une partie de la mémoire principale.

Dans ces deux caches, les blocs disque les plus récemment ou fréquemment utilisés sont conservés. Ils seront écrits, si nécessaire, sur le disque de manière périodique ou lorsqu’une application le demande explicitement.

Pour certaines opérations, comme une copie de fichier par exemple, le cache est inutile, car les données ne sont utilisées qu’une seule fois. Dans ce cas, l’application utilise des accès disque « non cachés » qui évitent de le remplir inutilement.

Pour les autres opérations, lorsque les données sont utilisées en boucle, le cache apporte des gains considérables.

VI - Cache de 4D

Comme expliqué lors de précédentes notes techniques(4), 4D utilise la mémoire principale pour stocker la table d’allocation, les tables d’adresses (index et enregistrements), les index eux-mêmes et les enregistrements. Ce cache améliore les performances de 4D lorsque les bases deviennent plus grosses que le cache système. Il permet également de stocker des données volatiles (sélections courantes, transactions) plutôt que d’utiliser un fichier temporaire. Il a, en outre, la particularité de définir des priorités et d’être en grande partie contrôlable par le développeur 4D.

Lorsque le cache de 4D devient insuffisant, des objets sont retirés en utilisant un ordre spécifique. Il est alors partiellement vidé pour y stocker des objets de priorité égale ou plus élevée. Généralement cette opération retire uniquement des enregistrements. Dans certains cas extrêmes, elle peut retirer des pages d’index ou des tables d’adresses.

L’opération qui consiste à sauvegarder ce cache sur le disque s’appelle l’opération de « flush ». Elle peut être effectuée périodiquement en utilisant les préférences de la base ou ponctuellement à l’aide de la commande ECRIRE CACHE (ou en Mode Utilisation, Menu Fichier, Ligne Ecrire le cache).

Le flush automatique du cache a pour but de protéger la base d’accidents tels qu’un crash, une panne matérielle ou une coupure de courant. Si la base est amenée à fonctionner en continu (ou sur de longues périodes) avec des moments d’inactivité, une écriture automatique est sécurisante. En effet, l’inactivité aura pour conséquence de ne pas remplir le cache et donc ne pas générer de flush. Les données peuvent ainsi rester sans sauvegarde pendant des heures. Il vaut mieux toutefois ne pas choisir un flush trop fréquent pour éviter une surcharge pendant les périodes d’activité. Une fourchette de 5 à 30 min est raisonnable. Ne confondez pas l’écriture automatique du cache (tel que défini dans les préférences du cache) avec la sauvegarde automatique. La sauvegarde automatique (Backup) est une sécurité supplémentaire qui permet d’éviter les fichiers data corrompus (par exemple après une coupure de courant).

D’autres paramètres ont une influence primordiale sur les performances de ce cache. Toutefois, de même que l’apport du cache disque du système dépend des opérations effectuées, celui de 4D dépend du mode de fonctionnement de la base. Plus particulièrement des enregistrements. Voyons dans un premier temps comment optimiser la taille du cache.

VII - Taille optimale du cache de 4D

La taille optimale du cache dépend avant tout des objets que votre base doit/peut stocker. Dans l’ordre de priorité, nous trouvons la table d’allocation qui est quasiment toujours maintenue en cache (nécessaire pour presque toutes les opérations ; la charger augmenterait de manière considérable le temps d’exécution).

Les tables d’adresses des index et les pages d’index devraient être conservées en cache dans la limite du possible parce que les performances obtenues par les recherches indexées ne sont optimales que s’il n’y a pas besoin d’accéder au disque pendant la recherche. En réalité les performances dépendent du nombre d’enregistrements trouvés. Plus vous chargerez d’enregistrements suite à cette recherche, moins les accès disque pendant la recherche sont pénalisants (ils deviennent négligeables).

Les tables d’adresses des enregistrements devraient également être conservées en cache. Si toutes vos recherches sont indexées, celles-ci sont moins importantes que les tables d’adresses des index. Elles sont toutefois nécessaires dès que vous effectuez des recherches séquentielles ou des opérations binaires avec des ensembles et des sélections. Les performances optimales sont donc obtenues lorsque ces tables restent toutes en cache.

Les choses sont un peu plus compliquées pour les enregistrements. Nous avons vu que le cache est utile pour les données utilisées de manière répétée. Ceci signifie que les enregistrements utilisés régulièrement devraient rester en cache. À l’inverse, les enregistrements utilisés qu’une seule fois ne devraient pas être maintenus en cache parce que l’opération de mise en cache pourrait devenir coûteuse. Exemple : si vous chargez 1 million d’enregistrements, le gestionnaire de cache va tenter de conserver chacun d’entre eux en utilisant un très court temps processeur. Si vous les utilisez une deuxième fois, le gain en vitesse obtenu est suffisant pour négliger le temps de mise en cache.

D’autre part, le cache des enregistrements fonctionnant de la même façon que la pagination de la mémoire (swap), vous pouvez rencontrer des problèmes si votre cache est légèrement sous-dimensionné. Imaginez que votre base utilise tous les enregistrements avec la même fréquence et de manière séquentielle. Si seulement 1 % d’entre eux ne tient pas en cache, tous les enregistrements seront continuellement retirés puis rechargés les uns après les autres. Ce type d’utilisation est pire que ne pas avoir de cache du tout(5).

Enfin il faut prendre en considération les transactions (arborescences et flux de données) et les sélections. Si vous utilisez des transactions et souhaitez éviter un flush du cache, vous devez prévoir la place maximale nécessaire pour celles-ci. Les sélections nécessitant 4 octets par enregistrement, elles n’influent que sur les petits caches ou les très grosses bases.

VIII - Améliorations apportées par 4D 2004

Avec 4D 2004, l’utilisation de la mémoire et du cache ont été optimisés pour MacOS X et Windows XP (qui sont préemptifs) et les machines modernes (jusqu’à 8 Go de RAM, débit disque > 50 Mo/s).

La première amélioration est liée à la taille du cache, qui peut à présent être beaucoup plus grosse. Jusqu’à 4D 2003 les bases se limitaient à des caches de 32/64 Mo en moyenne. Ceci était lié aux performances du gestionnaire de cache qui pouvait considérablement ralentir avec des tailles plus importantes. Principalement par des phénomènes de fragmentation. La fragmentation du cache apparaît lorsque la base charge, décharge et efface beaucoup d’enregistrements. Elle apparaît à présent très rarement et permet d’atteindre des tailles de cache de 512/1024 Mo(6). Les gains en performance peuvent dans ce cas atteindre 100 % sur les 2 plateformes en augmentant simplement la taille du cache sur les grosses bases.

La seconde amélioration concerne l’option d’optimisation du cache (commande FIXER PARAMETRE BASE avec le sélecteur 26). Celui-ci n’est généralement plus nécessaire. L’optimisation du cache permet de réordonner les enregistrements dans le cache afin de limiter le nombre d’écritures pendant le flush. Cette option accélérait l’opération de flush, notamment sous Mac OS X. La plupart des tests effectués avec le nouveau gestionnaire de cache montrent que cette option devient inutile. Dans certains cas elle est même pénalisante. Vous devriez conserver celle-ci uniquement si votre fichier de données est très fragmenté.

L’écriture du cache elle-même a été améliorée. Particulièrement sous Mac OS X. Vous pouvez à présent atteindre un débit lors du flush proche du débit théorique maximal. Une base qui sauvegarde 256 Mo d’enregistrements avait un débit moyen de 10 à 15 Mo/s sur un disque à 60 Mo/s (PowerMac G5) avec 4D 2003. Depuis 4D 2004 la même base atteint 40 à 45 Mo/s. Ces gains s’appliquent à toutes les bases, sans changement.

Le chargement des enregistrements a également été optimisé. Si un enregistrement n’est pas dans le cache de 4D et qu’il est chargé depuis le disque, le cache système est mieux mis à profit et les performances sont meilleures sur les machines les plus puissantes (environ 50 % sur un PowerMac G5). Là encore le gain est automatique et ne nécessite aucune modification.

Ces nombreuses améliorations permettent d’atteindre des performances équivalentes sur les deux plateformes dans la plupart des opérations.

IX - Comment configurer le cache de 4D pour obtenir un résultat vraiment optimal ?

Si vos enregistrements ne sont, d’une manière générale, utilisés qu’une seule fois, vous devriez régler le cache pour qu’il puisse contenir les tables d’adresses et d’enregistrements. Pour cela utilisez l’Explorateur d’exécution et vérifiez que le taux de réussite du cache est proche de 100 % pour les pages d’index et < 20 % pour les enregistrements. Si la taille de vos sélections ou transactions est non négligeable, prenez-les en compte également.

Si vos enregistrements sont utilisés de manière répétée avec une fréquence égale pour toutes les tables, assurez-vous de pouvoir les conserver tous en cache (en ajoutant 10 % pour éviter le problème de chargement/déchargement séquentiel). Pour calculer la taille des enregistrements, utilisez la méthode traditionnelle (4) et vérifiez le taux d’utilisation du cache avec l’Explorateur d’exécution (proche de 100 %). Utilisez encore celui-ci pour surveiller la taille requise par les transactions. Elles sont visibles par défaut avec le détail des arborescences et des flux de données. Assurez-vous que le taux de réussite soit proche de 100 %. Pour les sélections vous devez afficher le détail des statistiques tel qu’il est visible avec 4D 2004 (à l’aide du menu contextuel, choisissez « Afficher le suivi de l’activité » puis déployez les « Statistiques du cache »). Vous pouvez alors vérifier la présence des sélections.

Ce mode d’affichage détaillé permet également de surveiller la disponibilité des tables d’adresses. Si les informations en pourcentages ne sont pas suffisamment précises (par exemple lors de l’utilisation d’un gros cache avec peu de données chargées) vous pouvez également utiliser l’option « Montrer le numéro de champ et de table », toujours via le menu contextuel, pour voir le nombre d’objets et la taille occupée (en octets). Si vous avez la possibilité d’utiliser un cache suffisamment gros, toutes les catégories de données devraient avoir un taux de réussite proche de 100 %. Rappelez-vous toutefois que votre base doit fonctionner pendant un certain laps de temps avant d’avoir tout chargé.

Enfin, si votre base utilise certains enregistrements plus souvent que d’autres, assurez-vous de conserver ceux-ci en cache (toujours en ajoutant 10 %) et flushez (avec ECRIRE CACHE) après chaque opération qui remplit le cache avec des enregistrements rarement utilisés. L’utilisation de l’Explorateur d’exécution se fera dans ce cas uniquement pour les tables à optimiser. Le flush est également utile après avoir supprimé beaucoup d’enregistrements (> 100 000), afin de libérer la place occupée par les marqueurs d’enregistrements. Ou encore si vous avez utilisé des transactions avec de gros flux de données.

Chaque base est un cas particulier, n’hésitez donc pas à réaliser des tests pour trouver les valeurs optimales. Assurez-vous que les index tiennent en cache et s’ils sont trop gros, vous devriez peut-être reconsidérer chacun d’eux et vérifier leur pertinence(7).

X - Conclusion

Nous avons vu concrètement comment évaluer la taille optimale du cache de 4D en fonction de la mémoire (RAM) disponible et des caractéristiques de votre base. Nous avons vu également comment vérifier le comportement de la base en cours de fonctionnement et quelles sont les améliorations apportées par 4D 2004. Vous devriez donc à présent être en mesure de gagner des performances allant de 10 % à 100 % ou plus, selon les cas, sur les machines les plus puissantes.

Pour conclure, nous rappellerons que votre base fonctionne grâce au système d’exploitation. Celui-ci a besoin de mémoire pour son fonctionnement propre. En particulier le cache disque. Si les performances de votre système s’écroulent par manque de mémoire, les vôtres suivront. Même remarque concernant les process qui pourraient coexister sur la machine. Hormis ces limites, vous pouvez allouer le maximum de mémoire disponible à 4D.

(1)Selon le gestionnaire de cache.

(2)Rare parce que seule une partie de la mémoire allouée est réellement utilisée par les applications. Optimisée, par exemple, parce qu’une page de mémoire virtuelle n’ayant pas changé n’est pas réécrite. Enfin, une partie du travail du gestionnaire de mémoire est réalisée quand la machine est en repos (Idle Time).

(3)Les transferts mémoire sont réalisés à 3 Go/s sur un PowerMacG5 à 2.5GHz ou un AthlonXP 3200+. Les accès disque séquentiels non cachés sont réalisés à 65 Mo/s sur les mêmes machines (Serial ATA), les accès aléatoires non cachés de petite taille (< 4 ko) à 1,5 Mo/s.

(4)Voir notes techniques 4D-200007-21-FR et 4D-200012-32-FR « Chargement d’un enregistrement (1&2) » ainsi que 4D-200305-14-FR « Optimisation de l’écriture du cache sur disque sous 4D 2003 ».

(5)Certains algorithmes du moteur de 4D savent détecter ce phénomène et traitent les enregistrements déjà en cache en priorité (par exemple lors d’une recherche ou d’un tri séquentiel simple).

(6)Le mécanisme connu sous le nom « Airbag » est toujours utilisable pour des performances optimales, même s’il devient moins impératif.

(7)En particulier, prenez soin d’indexer plutôt des entiers longs que des alpha. La taille des index pour les champs alpha peut rapidement devenir pesante. Voir à ce sujet l’article d’Olivier Deschanels paru dans Planète 4D n° 8 (juin 2002) : « Optimiser 4D Server (II) ». Il n’est également pas forcément utile d’indexer des tables qui ne comportent que quelques dizaines d’enregistrements.