A client and server solution
This is what you need to be a client in the distributed computation:
The server is not much more complicated:
Improving the calculation
We can of course do the depth calculation more efficient. The first attempt would be to be smarter and avoid constructing tuples on the heap for every complex number in the recursion. If you explore this option you might end up with a test/3 function that looks as follows (the real and imaginary parts have been broken out):
test(M, _Zr, _Zi, _Cr, _Ci, M) ->
test(I, Zr, Zi, Cr, Ci, M) ->
Zr2 = Zr*Zr,
Zi2 = Zi*Zi,
A2 = Zr2 + Zi2,
A2 < 4.0 ->
Sr = Zr2 - Zi2 + Cr,
Si = 2*Zr*Zi + Ci,
test(I+1, Sr, Si, Cr, Ci, M);
Running a benchmark on my laptop this will cut the execution time in half.
Native code to do the calculation
The next step is to implement this in C and then load it as a foreign function (NIF). This will require some C skills but you will quickly get something up and running since this is a very simple function that only handles floating point arithmetic. Here is an example of a C file and Erlang file that will do the trick.
The C file needs to be compiled as a shared library and is then included in the Erlang virtual machine -- doing this is not recommended, if the C function crashes the whole Erlang machine crashes . If you want to give it a try you compile like this:
unix> gcc -o depth.so -I/usr/lib/erlang/usr/include -fpic -shared depth.c
windows> cl -LD -MD -Fe depth.dll depth.c
This will cut the execution time down another factor five so we are now a factor 10 from our original code.
If we now parallelize the code we gain another factor 3 (on my 4 core Intel machine) so we are now 30 times faster than the original code.
Marcel Eschmann tried the NIF interface on OSX and here are his findings using the C complex library.
To compile the depth.c code:
> gcc -std=c99 -fPIC -shared -o depth.so depth.c -I /usr/local/lib/erlang/erts-8.2/include/ -flat_namespace -undefined suppress;
Of course the –std=c99 is optional and is only required for the <complex.h> import. On OSX, the normal Unix compile command will tell you that the enif_* functions are not supported for your architecture, so you have to:
- Add the absolute path to the erlang "erl_nif.h"
- Add “-flat_namespace -undefined suppress”
The image he generated: