Hacker News new | past | comments | ask | show | jobs | submit login
Investigating Erlang by reading its system calls (jvns.ca)
159 points by ingve on May 13, 2016 | hide | past | favorite | 39 comments



If you run something like:

erl -noshell +sbwt none -smp disable +A 0 -mode minimal -eval 'io:format("Hello world~n").' -s init stop

instead, which is much closer to what python/java et al runs, then at least I get around 2850 syscalls.

The constant ppoll:ing is because erts spins looking for new work from any fd. Specifically "/sys/devices/system/node/node0" is in order to check for cpu topology updates by the operating system, i.e. if for some reason a core/cpu is taken offline of something like that. This is limited in my example above by "+sbwt none"

IIRC the bind is an UDP socket to talk to the local nameserver. This is removed in my example with "-mode minimal".


this feels similar to the overhead of an escript


Maybe some analogy - C is like riding a very fast bike. Python, Java - Starting a truck which will move what you want. Erlang - starting a railway system.

Erlang is like another system inside your system, it's more akin to booting a system inside a vm just to echo some hello world.


This.

Erlang isn't a bare programming language like C, or even a high level, but still fundamentally simple language like Python.

It isn't just an intermediary bytecode running in a VM, like Java, that maps bytecode instructions to OS instructions.

It is instead more like a Smalltalk environment or similar; an entire ecosystem running for the specific purpose of providing you a very particular kind of programming environment.


Terry Davis describes his TempleOS† as a motorbike, Windows a car and Linux a semi truck with a huge gearbox. In TempleOS, you'll crash if you lean over too far. The solution? Don't lean over, then!

† ring-0 only, no memory protection, exploratory dev/art focused


Exactly.

To put it another way, if you run code on a system with concurrency units sharing the memory (the heap), your code is running on DOS or Windows 3.1 which was cool in 1990s.

Erlang/Elixir is like running your code on a modern OS with a process memory separation, preemptable concurrency (processes don't have to yield by hand to others). Built in tracing and monitoring facilities (tracing, observer, dbg). Built in networking (distribution, global process registration, in memory distributed db) etc.


By default, the erl interpreter starts up the otp app, which loads lots of modules (50+?) and multiple (5?) different processes. It takes a second. To get things running faster, you can use the -boot argument to erl. There is a appendix in Joe Armstrong's book that steps you through it.


yeah, also it would be fair to compare a running actor system with Akka (jvm, java, scala), CAF (c++), XUDD (Python), Celulloid (Ruby) vs Erlang

I believe Erlang would do some interesting things there


Bike as in motorcycle, not bicycle I presume?


It depends IMO, small c programs - bicycle, bigger ones - motorcycle. If you want to extend this further, C can be any bike or even a road (linux).


I'd say C is the bicycle and C++ is the motorcycle. Both give you plenty of chances to kill yourself.


A quick suggestion for the author based on the "dude I can't debug anything on OS X" line - take a look at DTrace, which is shipped with MacOS (albeit an old version).

Compared with strace on Linux it is like night and day.


> http://jvns.ca/blog/2016/01/14/a-few-notes-on-my-cusec-talk/

On debugging, second bullet. She seems to agree.


can we have all man pages converted into "zine" pages, as Julia Evans does for strace here :-) http://jvns.ca/strace-zine-unfolded.pdf


Apparently so! I didn't read the author's site beyond the original article.


Good advice, on Windows it's really a nightmare though.. Investigating why the OS seems to 'freeze' a process for 10s once in a while (threading issue?) is really mysterious..


Unfortunately, dtrace does not work any more on El Capitan by default.


DTrace is closer to something like LTTng than to strace, though.


dtrace is an "everything tracer", so it's a superset of strace… and a ton of other stuff.


In other words, you can whip up strace in a few lines with DTrace.


DTrace comes with a syscall tracer called 'dtruss'.

One serious problem - it has to run as root.


sounds kinda like SystemTap?


SystemTap is dtrace for linux, at least in intent (implementation and details differ)


> I wanted to debug something > I've analyzed Erlang strace > "Erlang is complicated"

If you want to debug Erlang program then Erlang/OTP already includes tools to help you do that: http://www.erlang-in-anger.com/ - 92 page manual that includes: - tracing functions called with defined parameters - analyzing crash dumps, memory leaks, cpu scheduling


This is great, if you're planning to do many things with erlang, our you have a lot of time. If your friend has a weird problem and comes to you because you have a reputation for figuring things out that you've earned by using strace, then you use strace. Incidentally, I'm reading this because I use erlang, but it took about a minute to see the problem (tcp port exhaustion) from the strace.


cross posting what I wrote as a comment in the article:

epmd is a separate process, yes. But an erlang node connects to epmd in order to register it's name on it. It will bind a socket to talk with epmd (probably among other things).. See also: http://erlang.org/doc/apps/erts/erl_dist_protocol.html


Erlang is a system not just a language


  $ cat hello.tl
  (pprinl "hello, world")
  $ strace txr hello.tl 2>&1 > /dev/null | wc -l
  77

  $ cat hello.c
  #include <stdio.h>
  int main(void) { printf("Hello, world\n"); }
  $ cc -O hello.c -o hello
  $ strace ./hello 2>&1 > /dev/null | wc -l
  29

  $ strace gawk 'BEGIN { print "hello") }' 2>&1 > /dev/null  | wc -l
  84


  $ cat HelloWorld.java
  public class HelloWorld
  {
    public static void main(String[] args)
    {
        System.out.println("Hello, world");
    }
  }
  $ strace java HelloWorld 2>&1 > /dev/null | wc -l
  122


    $ strace python -c "print('hello world')" 2>&1 > /dev/null | wc -l
    924

    $ strace python3 -c "print('hello world')" 2>&1 > /dev/null | wc -l
    543


Python's site module contributes a lot to this. It attempts to load a lot of other modules, many of which may not exist for a given install.

Using your example:

    $ strace python3 -c 'print("hello world", end="")' 2>&1 | hist
     1. stat                 122
     2. rt_sigaction         68
     3. fstat                67
     4. read                 55
     5. close                47
     6. open                 37
     7. mmap                 34
     8. lseek                30
     9. getdents             18
    10. mprotect             16
        ...                 
        TOTAL:               567

    $ strace python3 -S -c 'print("hello world", end="")' 2>&1 | hist
     1. rt_sigaction         68
     2. stat                 51
     3. fstat                39
     4. mmap                 31
     5. read                 27
     6. close                26
     7. open                 23
     8. mprotect             16
     9. lseek                15
    10. brk                  10
        ...                 
        TOTAL:               350


Wow, that's bad even by interpreted language standards:

  % strace perl -e "print 'Hello, World';" 2>&1 > /dev/null | wc -l
  192


    $ strace node -e 'console.log("hello world")' 2>&1 > /dev/null | wc -l
      304


$ strace lua5.3 -e 'print("hello")' 2>&1 > /dev/null | wc -l

67


  $ strace txr -e '(put-line "hello")' 2>&1 > /dev/null | wc -l
  70
Very similar.

Obviously there are those who care about reasonable startup times and, ... others. :)

By the way, TXR supports setuid operation, and so it makes a few extra syscalls to check its security situation (am I running setuid? setgid?)


Would it make sense to do a large number of iterations (in the millions) of the basic "Hello, World\n" print statement in all the languages to amortize the cost of the BEAM/JVM setup/initialization system calls out?

Isn't it the case that in Java and Erlang we have a large VM environment that also needs to be launched before the first line of the trivial print statement is executed?


Rust:

    $ cargo new --bin hello
    $ cd hello
    $ cargo build --release
    $ strace ./target/release/hello 2>&1 | wc -l           
    124


This comparison is rather meaningless. It is measuring the Runtime startup. - Opening jars/pyc files.

Why not do a specific call before the actual code to segment the strace, or run it with repetitions and subtract+divide to get calls/repetition?


One last thing -- erlang runs bind once when it starts. Why does it need to listen on a TCP socket to run hello world?

My first thought: "So this guy is investigating Erlang with strace, but he couldn't be bothered to Google articles on its design!?" Then I tried Googling this myself. Uh, yeah. I happen to know this stuff, even though I don't use Erlang, but it's not exactly easy to find packaged conveniently in one place.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: