Author: Christian.Queinnec@lip6.fr

## Portability and Efficiency

One reason to compile to an abstract machine is to produce an executable independent of the architecture of the real machine where it runs. A native compiler will produce more efficient code, but the binary can only be executed on the architecture it was compiled for.

### Standalone Files and Portability

To produce a standalone executable, the bytecode compiler links the bytecode object file `example.cmo` with the runtime library, the bytecode interpreter and some C code. It is assumed that there is a C compiler on the host system. The inclusion of machine code means that stand-alone bytecode executables are not portable to other systems or other architectures.
This is not the case for the non-standalone version. Since the Zinc machine is not included, the only things generated are the platform independent bytecode instructions. Bytecode programs will run on any platform that has the interpreter. `Ocamlrun` is part of the default Objective CAML distribution for Sparc running Solaris, Intel running Windows, etc. It is always preferable to use the same version of interpreter and compiler.
The portability of bytecode object files makes it possible to directly distribute Objective CAML libraries in bytecode form.

### Efficiency of Execution

The bytecode compiler produces a sequence of instructions for the Zinc machine, which at the moment of the execution, will be interpreted by `ocamlrun`. Interpretation has a moderately negative linear effect on speed of execution. It is possible to view Zinc's bytecode interpretation as a big pattern matching machine (matching `match` ... `with`) where each instruction is a trigger and the computation branch modifies the stack and the counter (address of the next instruction).
Without testing all parts of the language, the following small example which computes Fibonacci numbers shows the difference in execution time between the bytecode compiler and the native compiler. Let the program `fib.ml` as follows:

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

and the following program `main.ml` as follows:

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

Their compilation is as follows:

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

These commands produce two executables: `fib.exe` and `fibopt.exe`. Using the Unix command time in Pentium 350 under Linux, we get the following data:

`fib.exe` (bytecode) | `fibopt.exe` (native)
7 s | 1 s

This corresponds to a factor 7 between the two versions of the same program. This program does not test all characteristics of the language. The difference depends heavily on the type of application, and is typically much smaller.