Proper way to run C code without crashing the VM

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Proper way to run C code without crashing the VM

asdf asdf
Hello,

I have been reading about NIF’s here: http://erlang.org/doc/tutorial/nif.html but it seems like they are incredibly unsafe: “it is also the least safe, because a crash in a NIF brings the emulator down too”. The problem here is huge, ideally I can’t ever have my Erlang VM close.

What solution do you Erlangers use when you have to run low level code? My goal is to send a sort of “GET” request with a UUID and I will receive back that UUID along with some binary values. My C code works with this, but I can’t jeopardize the entire server crashing.

Thank you for your help!

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Dmytro Lytovchenko
When the stability is important you have several choices:
1. Not use a NIF, write your logic in Erlang. Big industrial Erlang users may prefer this, for better debuggability and predictability at the cost of performance.
2. Write a really safe NIF which doesn't crash. Use defensive programming approach. Use safe language like Rust.
3. Separate your C code from Erlang node, write a port — a console application which accepts input in stdin and prints results to stdout, then use Erlang open port function to start it and port commands to communicate with it. 

2017-08-16 15:53 GMT+02:00 code wiget <[hidden email]>:
Hello,

I have been reading about NIF’s here: http://erlang.org/doc/tutorial/nif.html but it seems like they are incredibly unsafe: “it is also the least safe, because a crash in a NIF brings the emulator down too”. The problem here is huge, ideally I can’t ever have my Erlang VM close.

What solution do you Erlangers use when you have to run low level code? My goal is to send a sort of “GET” request with a UUID and I will receive back that UUID along with some binary values. My C code works with this, but I can’t jeopardize the entire server crashing.

Thank you for your help!

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions



_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Roger Lipscombe-2
In reply to this post by asdf asdf
On 16 August 2017 at 14:53, code wiget <[hidden email]> wrote:
> I have been reading about NIF’s here:
> http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”.

They're not "incredibly unsafe". There's nothing inherently unstable
about a NIF. It's precisely as stable (or unstable) as the underlying
implementation. It's just that it's running inside the BEAM, which
means that *if* it crashes, it's going to crash the whole Erlang node.

So: if you think you can write reliable C, go for it. If not, then you
need to look at other options. See Dmytro's email. He skipped "C Node"
as an option, incidentally. Another option is to host the NIF in
another Erlang node, and use Erlang distribution to talk to it.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Dmytro Lytovchenko
Just an assumption, possibly a false assumption.
If they already have a NIF, it means networked communication would possibly be slower than they expect.

2017-08-16 17:05 GMT+02:00 Roger Lipscombe <[hidden email]>:
On 16 August 2017 at 14:53, code wiget <[hidden email]> wrote:
> I have been reading about NIF’s here:
> http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”.

They're not "incredibly unsafe". There's nothing inherently unstable
about a NIF. It's precisely as stable (or unstable) as the underlying
implementation. It's just that it's running inside the BEAM, which
means that *if* it crashes, it's going to crash the whole Erlang node.

So: if you think you can write reliable C, go for it. If not, then you
need to look at other options. See Dmytro's email. He skipped "C Node"
as an option, incidentally. Another option is to host the NIF in
another Erlang node, and use Erlang distribution to talk to it.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

asdf asdf
That is an interesting note about running it on another node and using it to communicate. For this though, I would then have to monitor when/if the node goes down as well .
On Aug 16, 2017, at 11:07 AM, Dmytro Lytovchenko <[hidden email]> wrote:

Just an assumption, possibly a false assumption.
If they already have a NIF, it means networked communication would possibly be slower than they expect.

2017-08-16 17:05 GMT+02:00 Roger Lipscombe <[hidden email]>:
On 16 August 2017 at 14:53, code wiget <[hidden email]> wrote:
> I have been reading about NIF’s here:
> http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”.

They're not "incredibly unsafe". There's nothing inherently unstable
about a NIF. It's precisely as stable (or unstable) as the underlying
implementation. It's just that it's running inside the BEAM, which
means that *if* it crashes, it's going to crash the whole Erlang node.

So: if you think you can write reliable C, go for it. If not, then you
need to look at other options. See Dmytro's email. He skipped "C Node"
as an option, incidentally. Another option is to host the NIF in
another Erlang node, and use Erlang distribution to talk to it.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Joe Armstrong-2
In reply to this post by asdf asdf
Re NIF's safety etc. Here's my take

NIFs should be used for one reason only - performance.

If performance is not a problem you should use an external port
program, or an external c-node.

Also the NIF should be called many times per second, not just once now
and then - if the NIF is called infrequently then you should use and
external port program.

The only reason for using a NIF is to eliminate the round-trip times
for talking to an external process, and speeding time to convert the
internal data structures used by the programs since the NIFs have
direct access to the stacks and heaps of the Erlang processes
involved.

Using a NIF is breaking the guarantee - if you open the package and mess
around with the bits inside then don't blame me if you break something
...

If you can solve your problem in pure Erlang, then do so and don't use
a NIF.

There are a large number of reasons not to use NIFs

  - Your code might break the system in ways you don't understand
  - Your code will be single-platform and non-portable
  - Your code will not be 'future proof'
  - Understanding your code will require knowledge of Erlang +
    <another language> + a build procedure

I have always believed that large systems should be made from small
communicating components communicating via well-defined protocols -
linking things together in memory makes the individual components
larger and more unmanageable - we should be trying to do exactly the
opposite, making things smaller and isolating them.

The other problem with NIFs is that they make alternative
implementations pf Erlang far more difficult. An Erlang implementation
has four main components:

   1) A compiler from Erlang to beam code
   2) A beam instruction emulator
   3) A load of BIFs (or NIF's if you like)
   4) Huge libraries written in Erlang

Each of these represent massive effort.

Porting Erlang to (say) the JVM or .NET virtual machine would be
relatively easy were it not for 3). Changing the compiler to a new
instruction set and changing 1) and 2) is not that difficult but any
changes the calling sequences would really mess up all the code for
the BIFs and NIFs.

Never forget that NIFs are an optimization and nothing else
(since the same effect can be achieved in an external process) -

"Premature Optimization is the root of all evil"

[The best form of optimization is patience - in 20 years Erlang has become
 at least million times faster - of this probably a factor 10 comes from
 smarter compilation - and 100,000 from faster clock speeds and better hardware.
 (These are just guess but in 20 years Clock speeds  have gone from Mhz to GHz
  and memories increased from MBytes to GBytes)

 Pure Erlang code written 30 years ago ofter runs fine and is way faster
 than it was but the BIFs of 30 years ago are long dead and will not
 even compile.

  Patience is a virue]

Cheers

/Joe



On Wed, Aug 16, 2017 at 3:53 PM, code wiget <[hidden email]> wrote:

> Hello,
>
> I have been reading about NIF’s here:
> http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”. The problem here is huge, ideally I can’t
> ever have my Erlang VM close.
>
> What solution do you Erlangers use when you have to run low level code? My
> goal is to send a sort of “GET” request with a UUID and I will receive back
> that UUID along with some binary values. My C code works with this, but I
> can’t jeopardize the entire server crashing.
>
> Thank you for your help!
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Attila Rajmund Nohl
Hello!

I used to use NIFs a couple of times. These were really simple,
practically a wrapper around a libc call (e.g. realpath(3)). I think
the whole NIF code was less than 100 lines including boilerplate,
copyright message comment, etc. and worked on both Linux and Solaris
(our target platforms). It seemed easier to setup the build process
and bundle the libs with the result than go with an external port. I
think it *is* possible to write this small correct C code, so safety
wasn't really compromised. On the other hand it was also an
opportunity to learn about NIFs :-)

2017-08-18 11:13 GMT+02:00 Joe Armstrong <[hidden email]>:

> Re NIF's safety etc. Here's my take
>
> NIFs should be used for one reason only - performance.
>
> If performance is not a problem you should use an external port
> program, or an external c-node.
>
> Also the NIF should be called many times per second, not just once now
> and then - if the NIF is called infrequently then you should use and
> external port program.
>
> The only reason for using a NIF is to eliminate the round-trip times
> for talking to an external process, and speeding time to convert the
> internal data structures used by the programs since the NIFs have
> direct access to the stacks and heaps of the Erlang processes
> involved.
>
> Using a NIF is breaking the guarantee - if you open the package and mess
> around with the bits inside then don't blame me if you break something
> ...
>
> If you can solve your problem in pure Erlang, then do so and don't use
> a NIF.
>
> There are a large number of reasons not to use NIFs
>
>   - Your code might break the system in ways you don't understand
>   - Your code will be single-platform and non-portable
>   - Your code will not be 'future proof'
>   - Understanding your code will require knowledge of Erlang +
>     <another language> + a build procedure
>
> I have always believed that large systems should be made from small
> communicating components communicating via well-defined protocols -
> linking things together in memory makes the individual components
> larger and more unmanageable - we should be trying to do exactly the
> opposite, making things smaller and isolating them.
>
> The other problem with NIFs is that they make alternative
> implementations pf Erlang far more difficult. An Erlang implementation
> has four main components:
>
>    1) A compiler from Erlang to beam code
>    2) A beam instruction emulator
>    3) A load of BIFs (or NIF's if you like)
>    4) Huge libraries written in Erlang
>
> Each of these represent massive effort.
>
> Porting Erlang to (say) the JVM or .NET virtual machine would be
> relatively easy were it not for 3). Changing the compiler to a new
> instruction set and changing 1) and 2) is not that difficult but any
> changes the calling sequences would really mess up all the code for
> the BIFs and NIFs.
>
> Never forget that NIFs are an optimization and nothing else
> (since the same effect can be achieved in an external process) -
>
> "Premature Optimization is the root of all evil"
>
> [The best form of optimization is patience - in 20 years Erlang has become
>  at least million times faster - of this probably a factor 10 comes from
>  smarter compilation - and 100,000 from faster clock speeds and better hardware.
>  (These are just guess but in 20 years Clock speeds  have gone from Mhz to GHz
>   and memories increased from MBytes to GBytes)
>
>  Pure Erlang code written 30 years ago ofter runs fine and is way faster
>  than it was but the BIFs of 30 years ago are long dead and will not
>  even compile.
>
>   Patience is a virue]
>
> Cheers
>
> /Joe
>
>
>
> On Wed, Aug 16, 2017 at 3:53 PM, code wiget <[hidden email]> wrote:
>> Hello,
>>
>> I have been reading about NIF’s here:
>> http://erlang.org/doc/tutorial/nif.html but it seems like they are
>> incredibly unsafe: “it is also the least safe, because a crash in a NIF
>> brings the emulator down too”. The problem here is huge, ideally I can’t
>> ever have my Erlang VM close.
>>
>> What solution do you Erlangers use when you have to run low level code? My
>> goal is to send a sort of “GET” request with a UUID and I will receive back
>> that UUID along with some binary values. My C code works with this, but I
>> can’t jeopardize the entire server crashing.
>>
>> Thank you for your help!
>>
>> _______________________________________________
>> erlang-questions mailing list
>> [hidden email]
>> http://erlang.org/mailman/listinfo/erlang-questions
>>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Vincent de Phily
In reply to this post by asdf asdf
On 2017-08-16 15:53, code wiget wrote:
> Hello,
>
> I have been reading about NIF’s
> here: http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”. The problem here is huge, ideally I can’t
> ever have my Erlang VM close.

Whatever you do, your node *will* close someday, if only due to hardware
failure. If you have high uptime requirements, you should tackle node
redundancy/failover first before worrying about individual node stability.

> What solution do you Erlangers use when you have to run low level code?

The general advice with NIFs is to keep them small/simple/auditable
enough that you can consider them bug-free. Most NIFs are just wrappers
around existing libs, so they're going to be as stable as the underlying
lib.

If the underlying lib is unstable, interface with it using an Erlang
port or via the network.

If you're writing a complex lib yourself (so using NIFs for
performance's sake rather than code reuse), maybe write it in Rust
rather than C/C++ ? I'm looking for an excuse to do that myself. See
https://www.youtube.com/watch?v=lSLTwWqTbKQ
http://hansihe.com/2017/02/05/rustler-safe-erlang-elixir-nifs-in-rust.html
https://github.com/hansihe/Rustler

> My goal is to send a sort of “GET” request with a UUID and I will
> receive back that UUID along with some binary values. My C code works
> with this, but I can’t jeopardize the entire server crashing.

Sounds like you're querying an external server, not doing a lot of
computation locally ? If that's the case, going low-level with NIFs,
ports, etc is probably overkill, you're better off implementing it in
pure Erlang.

Actually, even if you do heavy computation locally, try implementing it
in pure Erlang first : chances are that performance will be good enough,
and you'll have an easyer time debugging and tuning Erlang than C.

--
Vincent de Phily

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Proper way to run C code without crashing the VM

Jesper Louis Andersen-2
In reply to this post by Joe Armstrong-2
I did an experiment a couple of years ago:

1. Run an OCaml program behind a port from Erlang
2. *Pipeline* requests to the port. That is, don't wait for the roundtrip of each message, just shove as many requests you can to the port and have it handle them. The OCaml program just reflects whatever it got back (an integer counter).
3. Use one CPU core for Erlang, once for OCaml.

This ran about 1 million req/s on a typical modern laptop. That is, the amortized message overhead is about 1us. It suggests that the NIF usecase is that you have many small calls which are latency bound (my above test is a throughput one due to the amortization). If you have large datastructures there may also be a reason for a NIF in some cases.

Measurement is key. I think there are many cases where you don't really need a NIF and a port would do fine.

On Fri, Aug 18, 2017 at 11:13 AM Joe Armstrong <[hidden email]> wrote:
Re NIF's safety etc. Here's my take

NIFs should be used for one reason only - performance.

If performance is not a problem you should use an external port
program, or an external c-node.

Also the NIF should be called many times per second, not just once now
and then - if the NIF is called infrequently then you should use and
external port program.

The only reason for using a NIF is to eliminate the round-trip times
for talking to an external process, and speeding time to convert the
internal data structures used by the programs since the NIFs have
direct access to the stacks and heaps of the Erlang processes
involved.

Using a NIF is breaking the guarantee - if you open the package and mess
around with the bits inside then don't blame me if you break something
...

If you can solve your problem in pure Erlang, then do so and don't use
a NIF.

There are a large number of reasons not to use NIFs

  - Your code might break the system in ways you don't understand
  - Your code will be single-platform and non-portable
  - Your code will not be 'future proof'
  - Understanding your code will require knowledge of Erlang +
    <another language> + a build procedure

I have always believed that large systems should be made from small
communicating components communicating via well-defined protocols -
linking things together in memory makes the individual components
larger and more unmanageable - we should be trying to do exactly the
opposite, making things smaller and isolating them.

The other problem with NIFs is that they make alternative
implementations pf Erlang far more difficult. An Erlang implementation
has four main components:

   1) A compiler from Erlang to beam code
   2) A beam instruction emulator
   3) A load of BIFs (or NIF's if you like)
   4) Huge libraries written in Erlang

Each of these represent massive effort.

Porting Erlang to (say) the JVM or .NET virtual machine would be
relatively easy were it not for 3). Changing the compiler to a new
instruction set and changing 1) and 2) is not that difficult but any
changes the calling sequences would really mess up all the code for
the BIFs and NIFs.

Never forget that NIFs are an optimization and nothing else
(since the same effect can be achieved in an external process) -

"Premature Optimization is the root of all evil"

[The best form of optimization is patience - in 20 years Erlang has become
 at least million times faster - of this probably a factor 10 comes from
 smarter compilation - and 100,000 from faster clock speeds and better hardware.
 (These are just guess but in 20 years Clock speeds  have gone from Mhz to GHz
  and memories increased from MBytes to GBytes)

 Pure Erlang code written 30 years ago ofter runs fine and is way faster
 than it was but the BIFs of 30 years ago are long dead and will not
 even compile.

  Patience is a virue]

Cheers

/Joe



On Wed, Aug 16, 2017 at 3:53 PM, code wiget <[hidden email]> wrote:
> Hello,
>
> I have been reading about NIF’s here:
> http://erlang.org/doc/tutorial/nif.html but it seems like they are
> incredibly unsafe: “it is also the least safe, because a crash in a NIF
> brings the emulator down too”. The problem here is huge, ideally I can’t
> ever have my Erlang VM close.
>
> What solution do you Erlangers use when you have to run low level code? My
> goal is to send a sort of “GET” request with a UUID and I will receive back
> that UUID along with some binary values. My C code works with this, but I
> can’t jeopardize the entire server crashing.
>
> Thank you for your help!
>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions