• Aucun résultat trouvé

Dans le cadre de cette thèse, nous nous sommes surtout concentrés sur la gestion de gros blocs. Ceci, notamment pour limiter les interactions avec l’OS et éviter les problèmes observés en section4.5. Pour ce faire, la source mémoire constitue elle même un allocateur en maintenant ses segments pour une réutilisation future. On remarquera que pour les gros segments, le coût d’allocation se trouve concentré principalement sur les fautes de pages du fait de la pagination paresseuse. C’est donc ces dernières que l’on vise à réduire. Pour cela, on peut comparer le temps d’allocation d’un élément de 1 Mo à son temps de premier accès. Le résultat est présenté par la figure4.9en effectuant les allocations à l’aide de l’allocateur de la glibc ou directement à partir

4.7. Réutilisation des gros segments

de mmap. Ces graphiques mettent clairement en évidence l’existence d’une source différente de surcoût d’allocation. Les petites allocations sont essentiellement impactées par le temps de la fonction malloc. Les grosses sont majoritairement impactées par les fautes de pages.

1e−06 1e−05 0.0001 0.001 0.01 0.1 1 10 100 1000 32 1K 32K 1M 32M 1G

Temps par octet

Taille (Ko)

Cout relatif d’allocation et libération malloc free Fautes de pages 1e−06 1e−05 0.0001 0.001 0.01 0.1 1 10 100 1000 32 1K 32K 1M 32M 1G

Temps par octet

Taille (Ko)

Cout relatif d’allocation et libération mmap munmap Fautes de pages

(a) (b)

FIGURE4.9 – Source des différents surcoûts d’allocation en fonction de la taille. L’impact des fautes

de pages est mesuré à partir de la différence de temps entre un premier et un second accès aux données en ayant vidé les caches entre temps. Les coûts sont donnés par unité de taille (cycles par octet).

4.7.1 Méthode de réutilisation de TCMalloc

TCMalloc dispose à sa manière d’une méthode de réutilisation. Cet allocateur ré-implémente toutefois l’équivalent complet du couple mmap/munmap avec la gestion de ses span. Leur ap- proche est intéressante du point de vue de leur contrôle du débit de libération basé sur l’utilisa- tion de madvise. Mais leur implémentation limite toutefois les chances de réutilisation des gros segments en introduisant des problèmes de fragmentation à grande échelle. On remarquera que le critère de performance tient plus au contrôle des débits d’allocation que de libération. On peut toutefois montrer que ces derniers sont pour partie reliés sous certaines conditions. Supposons la libération d’un tableau de p pages à un instant t0et une allocation de ces mêmes p pages à t1.

Avec une consigne de c pages maximum libérées par secondes, à t1 on aura libéré ∆t ∗ c pages,

ce nombre étant limité à p. Sur cet intervalle de temps, on a un débit d’allocation correspondant aux pages libérées, d’où un débit d’allocation inférieur ou égal à la consigne.

Avec un temps tf de faute de page on montre alors que le surcoût lié à l’OS est au maximum

de s = tf ∗ ∆t ∗ c, on a donc un ratio temps effectif sur temps système borné par ∆ts = tf ∗ c.

Remarquons toutefois que l’on ne contrôle pas le débit instantané d’allocation (contrairement à la libération), mais moyen. Or, le débit instantané est celui qui peut avoir une influence sur tf si

l’OS ne passe pas à l’échelle. Nous verrons que c’est malheureusement le cas de Linux. De plus, on notera que la proposition précédente n’est vérifiée que si l’on est en capacité de réutiliser 100% des pages en attente. Or, du fait de la fragmentation à grande échelle, ce n’est pas le cas de TCMalloc. Cette approche, bien qu’intéressante, ne permet donc de contrôler les débits d’allocation que de manière approximative.

4.7.2 Méthode proposée

Nous avons vu avec l’application Hera que nous avons beaucoup d’allocations de grandes tailles (de l’ordre de quelques Mo) ainsi que de nombreuses réallocations. Dans ce contexte, nous avons plutôt choisi de centrer notre politique de réutilisation sur les fonctions mmap,

munmap, mremap en ne contraignant pas le placement des blocs à des adresses précises. Le cache de macro-bloc est contrôlé sur la base de deux paramètres :

Taille maximum de segment : Cette limite permet d’ignorer tous les segments au-delà d’une

certaine taille. Les segments trop grands ont en effet peu de chances d’être facilement réutilisables tout en générant une surconsommation mémoire importante.

Mémoire maximum : Ce paramètre permet de borner la quantité de mémoire totale que l’on

autorise à maintenir en attente sur chaque nœud NUMA, ceci afin d’éviter tout risque d’explosion inopiné de la mémoire.

Si une requête est en dessous du seuil de réutilisation, l’algorithme recherche le bloc dispo- nible ayant la taille la plus proche de la requête. Si la taille ne correspond pas, alors le segment est redimensionné à l’aide de mremap. Les trois sémantiques de recyclage de blocs de taille in- adapté sont décrites dans la figure4.10. Remarquons principalement la présence du dernier cas qui n’est gérable que sur la base d’un emploi de la sémantique mremap. Cette approche permet d’assurer la réutilisation de segment même pour des tailles très variables. On assure de la sorte la propriété de réutilisation à 100%. Ceci peut à permettre à terme d’obtenir un meilleur contrôle des débits moyens via une méthode basée sur madvise(). Ceci, si l’on dispose d’un OS passant à l’échelle. D’autre part, notre méthode à l’intérêt est de parvenir de limiter le nombre de fautes de pages en maintenant un contenu minimal en page physique pour les segments renvoyés même s’ils ne sont pas entièrement projetés physiquement.

4 Mo

6 Mo

8 Mo

6 Mo

FIGURE 4.10 – Méthode de réutilisation des gros segments à base de mremap pour une requête

de 6 Mo. À gauche un exemple de réutilisation d’un segment plus petit impliquant une fraction du segment final non paginé. À droite la réutilisation d’un segment trop grand conduisant à une scission pour réutilisation futur. En bas, un cas nécessitant un déplacement éliminant le problème de fragmentation puisqu’il est toujours possible de réutiliser les pages du segment.

4.7.3 Recomposition de gros segments

L’utilisation de mremap sous Linux permet de déplacer volontairement des blocs de pages à une adresse déterminée. Ceci peut permettre de recomposer des segments plus grands à partir de segments plus petits. Cette voie n’a pour l’instant pas été explorée du fait des risques d’écra- sement de données induit par la méthode et des limites de portabilité de cette dernière. Il n’est d’ailleurs pas sur que cela apporte de réels gains. On remarquera en effet que l’utilisation de mremap pour grandir un segment suffit à pouvoir disposer d’une part non négligeable fournie en pages physiques. Les échanges avec l’OS même si non nuls, s’en trouvent donc déjà fortement