Skip to content

Instantly share code, notes, and snippets.

@danthedaniel
Last active August 25, 2018 23:46
Show Gist options
  • Save danthedaniel/c7b181f7bc543ee9c37cfd45df5f8856 to your computer and use it in GitHub Desktop.
Save danthedaniel/c7b181f7bc543ee9c37cfd45df5f8856 to your computer and use it in GitHub Desktop.
Comparison of Crystal and C binary sizes

Crystal Source Code:

def factorial(n)
    n < 2 ? 1 : n * factorial(n - 1)
end

if ARGV.size > 0
    n = ARGV.first.to_u64
    puts factorial(n)
else
    puts "No arguments provided"
    exit 1
end

C Source Code:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h> 

uint64_t factorial(uint64_t n) {
    return (n < 2) ? 1 : n * factorial(n - 1);
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("No arguments provided\n");
        return 1;
    } else {
        uint64_t n = strtol(argv[1], NULL, 10);
        printf("%lu\n", factorial(n));
        return 0;
    }
}

It can be seen that the binary produced by Crystal is significantly larger than the C binary:

-rwxr-xr-x 1 daniel daniel    7168 Jun 24 19:46 hello_c
-rw-r--r-- 1 daniel daniel     385 Jun 24 19:49 hello.c
-rwxr-xr-x 1 daniel daniel 1270216 Jun 24 20:02 hello_cr
-rw-r--r-- 1 daniel daniel     177 Jun 24 20:01 hello.cr

177x larger in fact.

@akzhan
Copy link

akzhan commented Jun 25, 2017

A lot of data is debug information.

@faustinoaq
Copy link

faustinoaq commented Jul 21, 2017

@teaearlgraycold big binaries contains a lot of debug info as @akzhan said. It's intend to use on development environment.

On production, you can compile using: (warning: basic debug info is still very useful on production environments)

>>> crystal build --release --no-debug hello.cr
>>> ls -l
-rwxr-xr-x 1 main main 185600 Jul 21 17:19 hello_cr

185600B is 6.8x smaller that a binary compiled without flags release and no-debug (1270216B)

Optionally you can strip symbols to make the binary even more smaller:

>>> strip -s hello_cr
>>> ls -l
-rwxr-xr-x 1 main main 158344 Jul 21 17:22 hello_cr

strip removes about 30K of unnecessary symbols, then 158344B is about 22X bigger that C binary compared with 177X you got. However Crystal lang is more High level than C and it simplify a lot of things when you code, type inference by example.

Experimenting with smaller binaries

All the above is using standard prelude, you can get even smaller binaries just linking LibC and using empty prelude like:

class String
  def to_unsafe
    pointerof(@c)
  end
end

@[Link("c")]
lib LibC
  fun printf(s : UInt8*, ...) : Int32
end

def factorial(n : UInt64)
  n < 2_u64 ? 1_u64 : n * factorial(n - 1_u64)
end

LibC.printf "%d\n".to_unsafe, factorial(10_u64)

And then:

>>> crystal build fac.cr --prelude="empty" -p --release --no-debug
-rwxr-xr-x 1 main main 8488 Jul 21 17:26 hello_cr

8488B is just 1.2X of C binary and if you strip it is like 0.8X of C binary.

>>> strip -s hello_cr
>>> ls -l
-rwxr-xr-x 1 main main 6216 Jul 21 17:30 hello_cr

You can see a experiment to get an even smaller crystal binary here ๐Ÿ‘‰ https://github.com/kubo39/tinycr (just 146 bytes ๐Ÿ˜… )

@danthedaniel
Copy link
Author

Thanks for the info, @faustinoaq

Copy link

ghost commented Aug 25, 2018

@faustinoaq doing god's work ๐Ÿ—ก๏ธ ty

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment