Some musl for your C programs

hacker_compmusl is a lightweight C standard library implementation for Linux. If you are looking for an alternative of glibc musl is worth your time. The project is maintained by the musl community and is under active development at the time of writing. Several standard libraries are implemented in musl.

musl is the default C library on Alpine Linux, a lightweight Linux distribution which is also the current choice of Docker or stal.li, a 34MB statically linked Linux distro. musl is designed for static linking with extra care taken not to pull in large amount of code or data that the application will not use. Even dynamic linking is efficient as the full library (including the dynamic linker) is a single shared library, greatly reducing the startup time and memory needed for dynamic linking.

For a quantifiable list of differences between musl, glibc and some more C libraries visit the comparison matrix from Eta Labs.

I tested one of my programs in musl with mixed results. In some cases it performed better than glibc and vice versa. However, binary sizes generated by musl are surprisingly small. The gain is significant in case of static linking.

Let’s try some hands-on! The program I chose finds the 1500th Prime Palindrome with 13 digits. GitHub source.

To install musl on Ubuntu, run:

$ sudo apt-get install musc musl-dev musc-tools

Dynamically linked binary size

glibc

$ make; ll pp-glibc
gcc -Wall -Wextra -Werror -O3 -march=native -o pp-glibc primepalindrome.c -lm
strip pp-glibc
-rwxrwxr-x 1 neo neo 10408 Mar 5 01:13 pp-glibc*

musl

$ make CC=musl-gcc; ll pp-musl
musl-gcc -Wall -Wextra -Werror -O3 -march=native -o pp-musl primepalindrome.c -lm
strip pp-musl
-rwxrwxr-x 1 neo neo 9816 Mar 5 01:14 pp-musl*

Statically linked binary size

glibc

$ make; ll pp-glibc
gcc -Wall -Wextra -Werror -O3 -static -march=native -o pp-glibc primepalindrome.c -lm
strip pp-glibc
-rwxrwxr-x 1 neo neo 1000768 Mar 5 01:15 pp-glibc*

musl

$ make CC=musl-gcc; ll pp-musl
musl-gcc -Wall -Wextra -Werror -O3 -static -march=native -o pp-musl primepalindrome.c -lm
strip pp-musl
-rwxrwxr-x 1 neo neo 13520 Mar 5 01:15 pp-musl*

Notice the jaw-dropping binary-size gain in case of static linking!

Execution times

Statically linked binaries

$ time ./pp-glibc
Sat Mar 5 01:17:53 IST 2016
Sat Mar 5 01:18:00 IST 2016
1015834385101
6.44user 0.00system 0:06.45elapsed 99%CPU (0avgtext+0avgdata 2008maxresident)k0inputs+0outputs (0major+324minor)pagefaults 0swaps
$ time ./pp-musl
Sat Mar 5 01:18:22 IST 2016
Sat Mar 5 01:18:29 IST 2016
1015834385101
6.45user 0.00system 0:06.44elapsed 100%CPU (0avgtext+0avgdata 2008maxresident)k
0inputs+0outputs (0major+379minor)pagefaults 0swaps

Dynamically linked binaries

$ time ./pp-glibc
Sat Mar 5 01:19:00 IST 2016
Sat Mar 5 01:19:05 IST 2016
1015834385101
5.91user 0.00system 0:05.90elapsed 100%CPU (0avgtext+0avgdata 2032maxresident)k
0inputs+0outputs (0major+422minor)pagefaults 0swaps
$ time ./pp-musl
Sat Mar 5 01:19:19 IST 2016
Sat Mar 5 01:19:26 IST 2016
1015834385101
6.44user 0.00system 0:06.44elapsed 100%CPU (0avgtext+0avgdata 1956maxresident)k
0inputs+0outputs (0major+342minor)pagefaults 0swaps

As you can see, pp-glibc performs better when dynamically linked.

Here comes the twist – when I re-implemented the function ltoa() using lldiv() musl performed much better in dynamically linked mode. Here’s my modified snippet:

/* Convert long to ASCII */
char *ltoa(long val, int base, int *len){
        int i = 30;
        lldiv_t q;

        ascbuf[31] = '\0';

        for(; val && i ; --i, val = q.quot) {
                q = lldiv(val, base);
                ascbuf[i] = "0123456789abcdef"[q.rem];
        }

        *len = 30 - i;

        return &ascbuf[++i];
}

Here’s the execution time:

$ time ./pp-glibc
Sat Mar 5 01:37:45 IST 2016
Sat Mar 5 01:37:52 IST 2016
1015834385101
6.46user 0.00system 0:06.47elapsed 99%CPU (0avgtext+0avgdata 2040maxresident)k
0inputs+0outputs (0major+417minor)pagefaults 0swaps
$ time ./pp-musl
Sat Mar 5 01:37:29 IST 2016
Sat Mar 5 01:37:35 IST 2016
1015834385101
5.92user 0.00system 0:05.93elapsed 99%CPU (0avgtext+0avgdata 2012maxresident)k
0inputs+0outputs (0major+341minor)pagefaults 0swaps

However, if we remember that these libraries are implemented independently the above results make sense.

As you can see, it’s very easy to install and start developing using the musl library. Do try it out the next chance you get!

2 thoughts on “Some musl for your C programs”

Leave a Reply

Your email address will not be published. Required fields are marked *