|
F# uses the compilation facilities of the .NET CLR to generate high performance
native code via the Common IL intermediary form.
F# has the succinctness of a scripting language,
and yet static type-checking and type-inference ensure that compact data representations are used
and high performance efficient code is generated for all language constructs.
This page gives further tips on improving the performance of your F# code.
Faster code is produced by using
the cross module optimizer (the "-O" options).
Not all optimizations are on by default.
Good profiling tools are essential for achieving good performance in practice.
F# works seamlessly with a range of memory and CPU profiling tools
(see tool support).
It is important to learn to use a profiler when developing code for high performance scenarios.
Applications will start-up faster if you produce .NET install-time
compiled binary images using ngen.exe. This will work with both
verifiable and non-verifiable code, and both debug and non-debug images.
When using .NET 2.0 use a single invocation of ngen.exe for the final exe of the application:
ngen install myprogram.exe
When using .NET 1.1 (or 1.0) use:
ngen mylibrary.dll
ngen myprogram.exe
-
Use
profiling tools
to identify the key time and space performance characteristics of your code.
-
Exception handling is implemented relatively inefficiently on many virtual machines.
As a result, do not use exceptions for control within ML
programs. This is the primary cause of poor performance in F# code. You can
determine if your program is raising and catching exceptions by running under
an interactive debugger
such as cordbg.exe or Visual Studio.
These will typically display exceptions as they are generated, even if subsequently caught.
-
The code generation works best with a .NET Common Language Runtime that
supports generics.
In order to run on non-generic CLRs, an erasure-to-Object model is
used over the generated IL bytecode. This results in some
inefficient code sequences, especially when box/unbox operations need to be
inserted on arguments in the middle of a complex call sequence.
Another result is that some functions will generate many locals and intermediate
unwrapping operations. This may also prevent tailcalls from being
taken - this happens if the
operation returns a polymorphic ('a) value that must be unwrapped/unboxed.
-
Top-level values are not GC'd by the .NET CLR.
If you have large objects which you wish to be collected then
make them local to a function.
-
Some corner constructs use implementation techniques that lead to slower
execution than would be expected. These can be avoided by using the --fast-sublanguage-only
compiler switch that prevents you from using these constructs.
|