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.