The Wolfram System compiler provides an important way both to speed up and also to work with Wolfram Language computations. It does this by taking assumptions about the computations and rewriting them in more efficient ways. These assumptions limit the full generality of the Wolfram Language but are chosen to enhance important classes of computations. For example, computations involving machine-precision arithmetic are enhanced.
In addition to providing speed enhancements for the Wolfram Language, the compiler is also useful since it can analyze and process Wolfram Language computations. This makes it the basis for useful features such as generating external code.
This tutorial will cover details about how the compiler works. It should help you to use it more effectively, for example, showing how to improve the performance of your computations.
A key way to use the Wolfram System compiler is with the function Compile.
You can use the compiled function as any other Wolfram Language function, passing it real number input.
However, if you pass the compiled function an input that is not a real number, a message is issued. The Wolfram Language still returns a result, but this has not used the compiler.
Comparison with Function
You can compare a compiled function with Function. They are created with a similar command structure.
For machine inputs, they return the same result.
It is faster to use CompiledFunction.
If the input is not a machine input, the compiled function issues a message before returning the result.
Compiled Function Internals
In general, Compile creates a CompiledFunction expression that contains a sequence of simple instructions for evaluating the compiled function. The instructions are chosen to be those that can be executed very efficiently by modern computer hardware and software libraries. The contents of the compiled function can be displayed by the input form.
You can get a view into how the compiled function executes with the CompiledFunctionTools` package. This is a key part of the Wolfram Language code generation system, but it can also be useful to show you what the compiled function does.
To use the CompiledFunctionTools` package you have to load it.
CompilePrint will show details of the compiled function.
Calling the Compiler
The Wolfram System compiler is called whenever a CompiledFunction executes. These are created by calls to the Compile function. In addition, a number of functions will attempt to use the compiler as part of their operation.
One important class includes many numerical computation functions, such as NDSolve, FindRoot, and FindMinimum. Typically, these have a Compiled option that can be used to enable or disable use of the compiler. The default operation of these functions is make some analysis of the initial settings and the problem and use the compiler if these indicate it would be beneficial.
The following calls NDSolve but does it without using the compiler.
Another class of uses of the compiler is from programming functions such as Table or Map. These analyze the input and use the compiler if this can be done without changing the result and if the time taken to create the compiled function does not cost too much.
In the following, the compiler is used. You can detect that the compiler was used because the result is a packed array.
Benefits of the Compiler
This section summarizes some of the benefits of the compiler.
A major benefit of the compiler is that it allows certain computations to be faster.
The following creates two expressions, using CompiledFunction and Function.
It is faster to use CompiledFunction.
CompiledFunction computations can be made faster still by using the code generator and by parallel computation.
The compiler works by creating a sequence of simple instructions for evaluating the compiled function. The Wolfram Language contains a virtual machine that can process these instructions. However, it can also use these instructions to create entire functions and programs written in other languages.
The following shows how to use ExportString to convert a CompiledFunction into a C code fragment.
Modern CPU architectures commonly provide multiple cores and these can be used by the compiler to execute a compiled function in parallel. The computations all run efficiently in multiple threads of execution, which is possible because of the simple instructions that the compiler generates.
The following demonstrates a compiled function running in parallel.
This shows the operation running sequentially; it takes twice as long.
Typically, $ProcessorCount is used to determine how many threads to be used.
For this computer $ProcessorCount is 2 and this is why the parallel computation was twice the speed of the sequential computation.