Erlang: How to integrate C with Erlang program example or Erlang NIFs (Native Implemented Functions) usage

Erlang programmers know that Erlang/OTP platform can reduce the program code length and speed-up development process about 75% compared to C. However Erlang is interpreted language, so overall Erlan program will be slower than equal one written in C. Thanks to Erlang developers Erlang HiPe is quite fast (you can see its speed compared to C GNU gcc here) and in some cases it even shows very similar to C results . But it still slow in many operations, for examle in numeric computation (actually above test shows this) and there are reasons for this slowness. So, it is natural to use native code in such cases. Erlang manual explains NIFs quite well, but it was not enough for me to look through their sample code to understand it and I decided to write some small test code and play with Erlang/C types conversion.

Erlang code is very simple, as I am going just to play with Erlang and C data types and not going to make something really complicated here.

-module(mynif).
-export([start/0, hello/3]).

% Automatically load native code module
-on_load(start/0).

start() ->
    erlang:load_nif("./mynif", 0).

hello(_A, _B, _C) ->
      "NIF library not loaded".

Here I should point out that you may want to load native code module automatically or may not and would like to load the module just  when you need it.

Here is C code of the module. I am just experimenting with the different Erlang types here passing 2 unsigned integers and a tuple to the function, than returning tuple containing length of the tuple, and two values, as you can see from the code..

/* mynif.c */
#include "erl_nif.h"

static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM** argv)
{
	int ar; // length o a tuple
	unsigned long a,b,c,a1,b1,c1;
	const ERL_NIF_TERM** tuple;
        enif_get_ulong(env, argv[0], &a);
        enif_get_ulong(env, argv[1], &b);
        enif_get_tuple(env, argv[2], &ar, &tuple);
        c = a*b;
        enif_get_ulong(env, tuple[0], &a1);
        enif_get_ulong(env, tuple[1], &b1);
        c1 = a1*b1;

        return enif_make_tuple3(env, enif_make_ulong(env, ar), enif_make_ulong(env, c), enif_make_ulong(env, c));
}

static ErlNifFunc nif_funcs[] =
{
    {"hello", 3, hello}
};

ERL_NIF_INIT(mynif,nif_funcs,NULL,NULL,NULL,NULL)

So, now we should compile C code. I have created simple shell script to simplify my tests

ERL_ROOT="/usr/lib64/erlang"

gcc -fPIC -shared -o mynif.so mynif.c -I $ERL_ROOT/usr/include/

And now we are ready to start erlang shell and see the results of the work...

Erlang R14B04 (erts-5.8.5) [source] [64-bit] [smp:3:3] [rq:3] [async-threads:0] [kernel-poll:false]

Eshell V5.8.5  (abort with ^G)
1> c(mynif).
{ok,mynif}
2> mynif:hello(2,3,{2,3}).
{2,6,6}
3> 

Overall everything is very simple and I am going to write and post here some reall world examples of NIF usage, where speed is important. So, follow my blog, as I am exited with possible speed improvement  and going to post more as soon as I will have a minute for that.

Posted by:
Enjoyed this post? Share and Leave a comment below, thanks! :)