When I initially encountered the idea of embedded Erlang at Erlang Factory 2010, I was sceptical. But the more I thought about it, the more it made sense. Now I'm convinced that it's not only a viable option, but a great idea for certain embedded applications. To put my money (in the opportunity cost sense of the word) where my mouth is I've started developing a UAV autopilot in Erlang. Here are the reasons why I believe it's such a good match.
In embedded systems, if your program has bugs, and most likely it does, what happens when a bug is triggered? Think about an air traffic control system. Or perhaps a nuclear power station. How hard it is to recover from the problem? Will your system react like the Ariane 5 rocket because of insufficient error handling?
Erlang/OTP is advocated by some because of it's concurrency model. In my opinion the actor model approach to concurrency is far more robust and far less error-prone than threads. But it's important to remember that the concurrency approach of Erlang is not it's raison d'être. The concurrency approach stems from the primary requirement for being fault tolerant, and it turns out that in order to be fault tolerant, you need robust concurrency.
One step to achieving robust concurrency is to avoid shared state. If you have shared state, it can become quite difficult to recover from errors because shared state can be like a virus, infecting the entire program with invalid values. And then there is condition of shared state when exceptions occurs - it is very difficult to ensure that the handling of exceptions leave shared state in a valid condition.
Fault tolerance is not the only way to reduce program failures. There are formal verification methods to determine if your program is correct. And you can invest a lot of time in testing. But both these activities can be very expensive.
Erlang/OTP is designed for fault tolerance, and provides methods and patterns for achieving fault tolerant programs. It has been used for many years in embedded systems, some reporting nine nines of reliability. The application patterns like supervisors, servers and state machines are proven to be robust. Shared-nothing state ensures that process can be terminated and restarted without infecting the rest of you application.
There's nothing stopping you from implementing all these features yourself in another language. But do you have NASA's budget?
Hot Code Loading
Hot loading is awesome.
Imagine for a moment that you have a website and you discover a bug in your code. How hard is it to roll out a fix? Depending on how critical the problem, you might have to take down and restart your server during peak times, if you're lucky you can do it when everyone's asleep. What about rolling out a new feature? Difficult?
Now imagine you have a embedded device running on a blimp which provides WiMax access to a town, or a disaster area. What do you do when you discover a critical security flaw in your software? And how do you upgrade your system in the field? Do you need to build some special re-flashing mechanism into your device?
In general, for embedded systems, the cost of change is higher, since changing the program can be difficult. But you don't want to change the program only when there's a problem, you also want to change your programs when you want to add functionality. Achieving uptime is not just about program correctness and fault tolerance. It is also about upgradeability. If you can make it cheaper to change your programs, you reduce the cost of bugs and upgrades.
Erlang is a great choice for reducing the costs of change. Erlang's hot code loading make it simpler, but not trivial, to change your program while it's running. OTP provides recommended, and proven, application structure patterns that you can use to upgrade your programs while they are running.
How can you make developers more productive? You can
- let then work in a highly production programming environment
- reduce the build/deploy/test cycle
- leverage existing libraries
Erlang/OTP is highly productive. A study done by Motorola and the Heriot-Watt University showed that Erlang/OTP can achieve 66% code savings. Another C++/Erlang comparison showed 75% code savings. Features such as first class functions, pattern matching, memory management and simplified error handling can make Erlang programs simpler than using alternatives.
For embedded systems, testing cycles can be exaggerated compared to developing applications for traditional servers and desktop machines. When developing embedded applications, a developer has to often compile, then deploy on the target system, then test. It is much more cost-effective to develop and test on the same machine and avoid the compile/deploy/test loop. Erlang/OTP's message passing paradigm makes it easy to architect a decoupled system, of which the constituent parts can be developed separately, some on the desktop, and some on the target system, so you can reduce the cost of compile/deploy/test.
Erlang/OTP has an excellent collection of standard libraries. It's not a new language, so doesn't suffer so much from the missing library syndrome that new languages struggle with. Granted, it may have a reduced set compared to other languages like Ruby and Java, but Erlang has a good support for integrating with the most-used embedded language...
C is still by far the most-used embedded language, especially on smaller devices. This is no surprise considering the requirements of size and speed on limited resources. If you want to use a more productive language for complex applications than C, it will count in your favour if you can re-use what you've got, especially all the low-level drivers for non-commoditised hardware and sensors.
Erlang has excellent support for interacting with C. The new Natively Implemented Functions (NIFs) in Erlang make this interaction even easier. C and Erlang have a strong symbiosis, and Erlang/OTP is a good choice if you want to combine a higher-level language with your C codebase.
Make no mistake. You're not going to run Erlang on an Arduino. But you can run it on a Beagleboard or a Gumstix device. Erlang has quite modest memory requirements. A fresh virtual machine (VM) I just started uses about 7 MB of real memory and 55.4 MB of virtual memory on the machine I'm writing this on. CouchDB uses 14.4MB of real memory and 43.8MB of virtual memory. A JVM with a small program that does nothing but sleep every 100ms uses 25MB of real memory and 349.5MB(!) of virtual memory. If your embedded device is running or is going to run embedded Linux, then consider Erlang/OTP. Devices of this class are powerful enough to run one or event multiple Erlang VMs. Most smartphones with embedded linux will easily run an Erlang VM.
- Erlang has great support for networking protocols like TCP, UDP, HTTP etc.
- Remote access to a VM with full REPL functionality so you can inspect and change it's current state.
- Reproducing data terms for debugging in Erlang is really as easy as copy-and-paste. There is no shared state, and no obscure objects that print as #<object-1234>. I.e. you can relatively easily dump the state of a system into a development machine and reproduce the problem.
In retrospect, if you consider that Erlang was designed for embedded use, it's no surprise that the design choices favour embedded systems. If your embedded system is of sufficient capability, e.g. running embedded linux, then I believe for the reasons mentioned that you can build it in less time, do it faster, and have a resulting application that's more robust and cheaper to maintain. I'll keep you posted.