La maquette Google

Premiers résultats

Ces quelques pages décrivent notre participation à l’état des lieux proposé par R.Hundt dans son article Loop Recognition in C++/Java/Go/Scala. Il y compare différents langages via un cas concret d’utilisation.

Nous avons choisi de ne comparer Cawen qu’à la version C++ proposée par R.Hundt.

Comment se comportera Cawen dans cet amical derby?

Présentation des différentes versions en compétition

Les deux versions C++
Version V0 :

Il s’agit de la version mise en ligne par R.Hundt. Cette version est accessible via la commande :

svn checkout http://multi-language-bench.googlecode.com/svn/trunk/ multi-language-bench-read-only
 Version V1:

R.Hundt n’a pas souhaité mettre en ligne la version « pro » de la maquette car elle utilise des sources propriété de Google. En revanche, il décrit assez précisément le chemin conduisant de la version originale à la version finale. Nous avons choisi d’appliquer les plus simples de ses recommandations, a savoir :

  • Additional gain for getting rid of BasicBlockMap and storing dfs_numbers on the BasicBlocks themselves.
  • Converted BasicBlockSet from set<> to vector<>.
  • Changed node_pool from a list<> to a vector<>. Moved definition out of the loop to recycle it.
  • Changed LoopSet from set<> to vector<>.
  • Changed LoopList from list<> to vector<>.
  • Changed EdgeList from list to vector.
Les huit versions Cawen
Version V0.0

Cette version est une transcription littérale de la V0 C++.

A une différence près : par défaut, les pseudo-destructeurs des variables Cawen ne sont pas appelés automatiquement en sortie de scope. Le code Cawen procède donc explicitement au nettoyage de tous les containers utilisés.

Version V0.1

On part de la V0.0 et on décide de satisfaire toutes les demandes de mémoire inférieures ou égales à 64 octets via un allocateur maison.

Version V0.2

On utilise le même allocateur, configuré similairement, mais les libérations ne sont plus explicites : en une ligne de Cawen, nous avons activé un mécanisme de libération propre à Govel, notre « STL » maison…

Version V0.3

Identique à la V0.0. A ceci près que la libération est implicite.

Version V1.0

Equivalent de la V1 C++ avec nettoyage explicite.

Version V1.1

Equivalent de la V1 C++ avec nettoyage explicite + allocateur

Version V1.2

Equivalent de la V1 C++ avec nettoyage implicite + allocateur

Version V1.3

Equivalent de la V1.0 avec nettoyage implicite

Présentation des différentes plateformes

Nous avons mené nos tests sur 4 plateformes :

  • Plateforme A :gcc 4.2.1 / FreeBSD 8.2 / Intel Core i5-2300/64b/2.80GHz /16G RAM
  • Plateforme B :gcc 4.2.1 / FreeBSD 7.1 / Intel Celeron /32b/ 2,66 GHz / 1G RAM
  • Plateforme C :gcc 4.5.3 / Cygwin6.0/ Intel Pentium Dual-Core T4200 /64b/2GHz /4G RAM
  • Plateforme D :gcc-4.0.1 / Mac OS X 10.5.8/ Intel Core 2 Duo /32b/ 2,4GHz /2G RAM

Les mesures

Temps d’exécution :

Nous avons procédé à 7 exécutions. Nous avons fait la moyenne des sommes des résultats « usr » et « sys » de la commande time.

Mémoire utilisée :

Nous avons fait nos premières mesures avec Valgrind qui donne un décompte exact du nombre et de la taille des allocations/libérations.

Puis, pour fournir des résultats comparables à ceux exposés par R.Hundt, nous avons enregistré les colonnes SIZE et RES de la commande top. Nous prenons une mesure par seconde et moyennons les valeurs significatives.

Nombres de lignes :

Nous avons été surpris de ne pas trouver, pour chacun des langages étudiés, d’outils dénombrant le nombres de lignes utiles voire de statements. C’est à dire, d’outils ayant une connaissance suffisante de la grammaire des langages pour faire la différence entre un commentaire, une ligne blanche et une instruction.

Il est probable que nous n’ayons pas suffisamment cherché.

Nous nous contentons donc de la méthode utilisée par R.Hundt : nous comptons toutes les lignes avec

wc -l;

Pour rester honnête vis à vis de C++, il nous a donc fallu reporter tous les commentaires et jusqu’aux erreurs d’indentation..

Temps de compilation:

Nous n’avons installé notre précompilateur que sur la plateforme A. Sur les autres, la génération se limite à la compilation des sources C99 générées sur A.

Les résultats

Les résultats bruts sont disponibles sous forme de tableau.

Nombre de lignes & le temps de compilation
Version 0

V0 - taille du code source [en nombre de lignes]

V0 – taille du code source [en nombre de lignes]

V0 - temps de compilation [en secondes]

V0 – temps de compilation [en secondes]

Version 1

V1 - taille du code source [en nombre de lignes]

V1 – taille du code source [en nombre de lignes]

V1 - temps de compilation [en secondes]

V1 – temps de compilation [en secondes]

 

La différence entre les versions V0.0 et V0.3, V0.1 et V0.2, V1.0 et V1.3, V1.1 et V1.2 ne tient qu’au nombre de lignes Cawen qu’elles nécessitent et à leur temps de précompilation. Elles effectuent exactement les mêmes traitements et nous nous sommes assurés que leurs performances sont identiques. Par la suite, nous ne présenterons donc qu’une série de résultats pour chacun de ces couples.

Taille du binaire
Version 0
V0 - taille du binaire [en octets]

V0 – taille du binaire [en octets]

Version 1
V1 - taille du binaire [en octets]

V1 – taille du binaire [en octets]

Temps d’exécution
Version 0
V0 - temps d'exécution [en secondes]

V0 – temps d’exécution [en secondes]

Version 1
V1 - temps d'exécution [en secondes]

V1 – temps d’exécution [en secondes]

Consommation mémoire
Version 0

V0 - mémoire virtuelle [Mo]

V0 – mémoire virtuelle [Mo]

V0 - mémoire réelle [Mo]

V0 – mémoire réelle [Mo]

Version 1

V1 - mémoire virtuelle [Mo]

V1 – mémoire virtuelle [Mo]

V1 - mémoire réelle [Mo]

V1 – mémoire réelle [Mo]

Analyse et hypothèses

Tout d’abord, les temps de précompilation sont énormes en Cawen et ce, même sur une plateforme assez généreusement dotée. Nous travaillons sur ce point et pensons pouvoir encore progresser…

On constate que les versions Vx.0 Cawen/C99 s’exécutent plus rapidement (de 25% à 64%) et en consommant moins de mémoire que les versions Vx C++ correspondantes (de 14 à 41%).

L’utilisation de l’allocateur se traduit par une réduction de 3,9% à 34% du temps d’exécution. Cette accélération est contrebalancée par une augmentation de l’utilisation mémoire qui rejoint alors le niveau des versions C++.

Nous n’avons pas pour le moment suffisamment de temps pour déterminer d’où provient le net avantage du code C99 généré par le préprocesseur Cawen sur le code C++ :

  • différence d’efficacité des compilateurs C99/C++ ?
  • Lenteur et gourmandise intrinsèque de la STL ?
  • Efficacité de la librairie Judy ?

Le source C est à la disposition des curieux.

Ce que la maquette laisse entrevoir du langage Cawen

Nombre de lignes

Le nombres de lignes consacrées à la maquette semble indiquer que Cawen est très légèrement moins bavard que C++ (de 3% à 6%). Dans le cas présent, les économies ont été faites grâce au « foreach » (présent en C0x11) et aux primitives d’écriture dans les containers qui acceptent tout type de variable comme argument « from ».

Pour donner une idée plus juste de l’expressivité de Cawen, on peut ajouter que Govel, notre bébé STL maison, qui contient un tableau en pile, un tableau en tas, une liste à double-chainage et les encapsulations de Judy1 et JudyL, les itérateurs associés, les différents foreach (runtime & précompilation) ainsi qu’une politique de copie et de libération ne compte que 10081 lignes de code.

Ajout d’un allocateur

En deux lignes de Cawen, on peut réorienter toute demande de mémoire dynamique vers un allocateur. On peut ajouter que la fonction de libération de l’allocateur utilisé ici a besoin d’un argument « taille à libérer».

Activation d’une libération automatique

En une ligne de Cawen, on peut activer la libération automatique des variables en sortie de portée. On peut remarquer que cette politique de libération, qui est codée en 300 lignes de Cawen, est propre à Govel (notre STL) et qu’elle ne fait donc pas partie du langage proprement dit.

Conclusion

La démarche de R.Hundt nous a paru très intéressante. Bien souvent, le débat autour des langages de programmation, leurs défauts et leurs avantages respectifs tourne rapidement à la guerre de religion.

Merci donc à R.Hundt de rappeler avec ces tests que les langages informatiques servent avant tout à exprimer simplement des traitements potentiellement complexes puis à les exécuter efficacement et qu’il existe donc des critères objectifs permettant de mesurer leur pertinence dans un contexte donné.

En s’en tenant à ces principes, nous pensons avoir montré qu’il reste encore beaucoup de place pour de nouvelles solutions…

Nous sommes très conscients qu’à ce jour Cawen reste très perfectible et qu’un long travail nous attend encore…Cependant, même si nous ne savons pas jusqu’où ira le petit Cawen, peut-on s’accorder à dire que ses premiers pas semblent prometteurs ?