Author: Christian.Queinnec@lip6.fr

## Portabilité et efficacité

L'intérêt de compiler vers une machine abstraite est de produire un exécutable indépendant de l'architecture de la machine réelle où il tourne. Son principal inconvénient provient de l'interprétation de ces instructions virtuelles. Un compilateur natif produira un code plus efficace, mais ne pouvant s'exécuter que sur un seul type d'architecture. Il est donc souhaitable d'avoir le choix entre ces deux types de compilation selon le type d'application développée. L'autonomie d'un exécutable, c'est-à-dire l'indépendance de celui-ci de l'installation de la distribution d'Objective CAML, fait aussi perdre la propriété de portabilité.

### Autonomie et portabilité

Pour produire un exécutable autonome, le compilateur de code-octet a effectué une édition de liens du code-octet `t.cmo` avec la bibliothèque d'exécution, l'interprète de code-octet et une amorce de programme écrite en C. Cela sous-entend qu'il y avait un compilateur C sur la machine hôte. À ce moment là même si la partie importante de l'exécutable contient les instructions en code-octet, cet exécutable n'est plus portable sur d'autres systèmes ou d'autres architectures machine.
Cela n'était pas le cas pour la version non autonome. En effet les instructions de code-octet ne diffèrent pas d'une machine à une autre, car la machine Zinc n'existant pas, seul son interprète compte. Si l'interprète de code-octet existe sur des machines d'architecture ou de système différents, rien ne les empêche d'exécuter les instructions de code-octet produites par d'autres compilateurs Objective CAML en utilisant la commande `ocamlrun`. Celle-ci fait partie des différentes distributions d'Objective CAML pour Sparc sous Solaris, Intel sous Windows, etc. Cependant, il est toujours préférable d'utiliser des versions de l'interprète de code-octet et du compilateur de même numéro.
La portabilité des fichiers objets en code-octet autorise la diffusion de bibliothèques directement sous cette forme et immédiatement utilisables sur les machines possédant l'interprète de code-octet.

### Efficacité d'exécution

Le compilateur de code-octet produit une suite d'instructions de la machine Zinc, qui, au moment de l'exécution, seront interprétées par `ocamlrun`. Cette phase d'interprétation a un certain coût pour la rapidité d'exécution du programme. On peut se représenter l'interprète de code-octet comme une grande structure d'aiguillage (filtrage `match` ... `with`) où chaque instruction est un motif et les branches de calcul modifient la pile et le compteur ordinal (adresse de la prochaine instruction). Ce filtrage, bien qu'optimisé, induit une perte de performance.
Bien que ne testant pas toutes les parties du langage, le petit exemple suivant qui calcule la fonction de Fibonnacci montre les différences de temps d'exécution entre le compilateur de code-octet et le compilateur natif. Soit le programme `fib.ml` suivant :

    let rec fib n =
      if n < 2 then 1
      else (fib (n-1)) + (fib(n-2));;

et le programme `main.ml` suivant :

    for i = 1 to 10 do
      print_int (Fib.fib 30 );
      print_newline()
    done;;

et leurs compilations suivantes :

    $ ocamlc -o fib.exe fib.ml main.ml
    $ ocamlopt -o fibopt.exe fib.ml main.ml

produisant les exécutables `fib.exe` et `fibopt.exe`. On obtient avec la commande Unix `time` sur un Pentium 350 sous Linux les temps suivants :

`fib.exe` (code-octet) | `fibopt.exe` (natif)
7 s | 1 s

Ce qui correspond á un facteur 7 entre les deux versions du même programme. Ce programme ne teste pas toutes les caractéristiques du langage. Le gain dépend fortement du type d'application.