Mon ami grep

grep, c'est mon ami. C'est d'ailleurs probablement l'ami de pas mal d'administrateurs système (enfin, les vrais quoi*). De temps en temps, il faut quand même bien vérifier que son ami est au mieux de sa forme, s'enquérir de ses performances, évaluer d'un œil critique si son environnement lui convient bien.

Quand vous avez un millier de chaînes de caractères, dont vous souhaitez retrouver toutes les occurrences dans un gros fichier de 685000 lignes, vous pouvez utiliser grep de deux manières :

  1. vous dites à votre ami grep de chercher toutes les chaînes en même temps dans le gros fichier,
  2. vous utilisez une boucle pour dire à grep de chercher une chaîne dans le fichier, puis de passer à la chaîne suivante, …

La solution 1 semble la plus intéressante. Une seule commande, pas de boucle, on se dit naturellement que c'est plus économique, et donc plus rapide. La solution 2, on se dit qu'elle est moche, complexe, et que les performances vont être mauvaises.

Petit test grandeur nature sur un serveur FreeBSD 7.x virtualisé, 2 CPU, 2Go de RAM :

Méthode 1 :
grep -i -f liste_emails maillog
opération terminée en 370 min environ.
Méthode 2 :
while read email; do grep -i $email maillog ; done<liste_emails
opération terminée en 1 min 32 s.

Bien sûr, le résultat est le même en terme de contenu, la seule différence est l'ordre des lignes. La méthode moche et supposée lente est juste 240 fois plus rapide que la méthode académique. Shame on you grep. Shame on you.

L'environnement est aussi important. On pourrait se dire qu'avec plus de CPU (en puissance, pas en nombre), plus de RAM, tout irait tellement plus vite. Essayons la même chose sur un Mac Pro Xeon quad-core, avec 12 Go de RAM, sous Mac OS X 10.6.

Méthode 1 : 223 min.
Méthode 2 : 35 min 45 s.

Ce qui prouve une fois de plus que Mac OS X est un gros tromblon quand il s'agit de fork. Comprendre que le coût du lancement d'un programme, en terme de ressources système, est beaucoup plus fort que sur d'autres OS, comme FreeBSD par exemple. Ce qui fait de Mac OS X un très mauvais candidat pour les scripts shell utilisant des boucles de manière très intensive.
On voit aussi que la vitesse d'exécution de la méthode 1 est essentiellement liée à la puissance de calcul du CPU, alors que la vitesse de la méthode 2 est essentiellement liée à la capacité du système d'exploitation de créer des process rapidement.

Pour conclure, j'ai fait un petit test avec awk, sur les mêmes fichiers. Moyennant quelques aménagements triviaux pour transformer le fichier liste_emails en programme awk, j'ai pu lancer la commande awk -f liste_emails maillog qui est l'équivalent de la méthode 1 pour grep. Le temps d'exécution est tombé à moins de 15 minutes sur Mac OS X, et moins de 30 minutes sur le FreeBSD.

* ceux qui ont fait 5 ans d'études dans une autre branche, avant de passer à l'informatique, par exemple.

2 comments

  1. réaction fort tardive, je n'en disconvient pas !
    Il serait intéressant de passer la chaîne de recherche via regex-opt avant de la faire traiter par grep.
    Sauf à ce que les chaînes recherchées n'est strictement rien en commun, on peut s'attendre à des gains intéressants.

  2. En effet, c'est tardif :)
    J'ai un gros doute sur la possibilité d'optimiser la requête en question, il s'agit simplement d'adresses email sans aucune expression régulière : un millier d'adresses email distinctes, à trouver dans des logs de serveurs qui voient passer des messages à destination de ~50000 adresses différentes.
    Depuis je suis passé à quelque chose d'un peu plus industriel : splunk, bien pratique et plus rapide.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.