# Reducing mirageos image size using ocamlclean?

**URL:** https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481
**Category:** Ecosystem
**Tags:** mirageos
**Created:** [August 27, 2018, 9:21am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481 "2018-08-27T09:21:25Z")
**Posts on this page:** 19
**Page:** 1

<div class="post-metadata">

### Author: ![Keiko](https://avatars.discourse-cdn.com/v4/letter/k/ecae2f/32.png) [@Keiko](https://discuss.ocaml.org/u/Keiko)
#### Post date: [August 27, 2018, 9:21am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/1 "2018-08-27T09:21:25Z")

</div>

I am looking into how to reduce the size of mirageos images. Currently I am playing around with the ukvm target.

Using 4.06.1+lto, the size of hello.ukvm is 6M (stripped). (–gc-sections gets me to 5.5M.)

I have read somewhere that I can use ocamlclean to reduce the image size. Is this still the case? I could not figure out how to do so.

I would be very grateful if someone could point me in the direction of reducing mirageos image size.

---

<div class="post-metadata">

### Author: ![avsm](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/avsm/32/6_2.png) [@avsm](https://discuss.ocaml.org/u/avsm)
#### Post date: [August 27, 2018, 10:53am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/2 "2018-08-27T10:53:50Z")

</div>

ocamlclean is only for bytecode binaries, so for native code (which is the main backend for MirageOS unikernels these days), the LTO patch is the way to go. It would be good to do some investigations into why the hello world is so big; for example, a [fix merged today](https://github.com/mirage/ocaml-cstruct/pull/204) to the ppx libraries stopped compiler-libs from being accidentally linked into the runtime unikernel.

---

<div class="post-metadata">

### Author: ![Keiko](https://avatars.discourse-cdn.com/v4/letter/k/ecae2f/32.png) [@Keiko](https://discuss.ocaml.org/u/Keiko)
#### Post date: [August 27, 2018, 12:14pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/3 "2018-08-27T12:14:06Z")

</div>

Cool. ppx\_tools\_versioned 5.2.1 gets hello.ukvm to 1.8 M 🙂

Out of curiosity: this paper [Unikernels: Library Operating Systems for the Cloud](http://anil.recoil.org/papers/2013-asplos-mirage.pdf) in 2013 reports that the size of mirageOS images was much smaller, Web Server 0.673 MB (and 0.172 MB after ocamlclean). I wonder why we cannot have a similar size for native-code mirageos?

---

<div class="post-metadata">

### Author: ![samoht](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/samoht/32/81_2.png) [@samoht](https://discuss.ocaml.org/u/samoht)
#### Post date: [August 27, 2018, 12:16pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/4 "2018-08-27T12:16:26Z")

</div>

@Keiko: you can use `upx --best` and/or `strip` to reduce the binary size even further. The hello-world for native apps should be between 500k and 850k (depending on the target).

---

<div class="post-metadata">

### Author: ![Keiko](https://avatars.discourse-cdn.com/v4/letter/k/ecae2f/32.png) [@Keiko](https://discuss.ocaml.org/u/Keiko)
#### Post date: [August 27, 2018, 12:30pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/5 "2018-08-27T12:30:59Z")

</div>

@samoht: 1.8 M is `strip`-ed and linked with `--gc-sections`. The target is `ukvm`.

`upx --best hello.ukvm` fails with `UnknownExecutableFormatException` :’-(

---

<div class="post-metadata">

### Author: ![mato](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mato/32/326_2.png) [@mato](https://discuss.ocaml.org/u/mato)
#### Post date: [August 27, 2018, 12:47pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/6 "2018-08-27T12:47:27Z")

</div>

`upx` will only work on a `unix` target. In any case, it only reduces the  
on-disk executable size, not the memory requirement.

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [August 27, 2018, 4:21pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/7 "2018-08-27T16:21:31Z")

</div>

I asked about rising binary sizes before: [Large binaries - break down the size by library?](https://discuss.ocaml.org/t/large-binaries-break-down-the-size-by-library/1098/3?u=lindig) Is there a chance that the PPX mechanism is responsible for this (at least in part)?

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [August 30, 2018, 1:02pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/8 "2018-08-30T13:02:24Z")

</div>

Triggered by the discussion here I looked into modules linked into our binaries and I see a lot of modules that I suspect belong to PPX processors but should not be in the binary. @hannes discovered such a problem in a pull request [avoid compiler-libs runtime dependency in ppx\_cstruct](https://github.com/mirage/ocaml-cstruct/pull/204). Examples for modules are:

- Ast\_407
- Migrate\_parsetree
- Ppxlib\_ast
- Typedtree

I expect that these modules are used by a PPX implementation at compilation time but are not required at run time.

Does this point to a common misunderstanding how PPX processors are packaged or used with jbuilder/dune? I am sure that we don’t request these libraries explicitly and I suspect they are introduced by PPX processors.

---

<div class="post-metadata">

### Author: ![mseri](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mseri/32/91_2.png) [@mseri](https://discuss.ocaml.org/u/mseri)
#### Post date: [August 30, 2018, 6:03pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/9 "2018-08-30T18:03:48Z")

</div>

Is there a way to (semi-)automatically infer which library brings them in?

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [August 30, 2018, 6:12pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/10 "2018-08-30T18:12:36Z")

</div>

`ocamlfind query -r package` shows all dependencies of `package`. These should include compile-time dependencies. I looked at the binary directly and also inspected the linking step. I don’t know of a good way to find the packages that brings in certain dependencies. Opam 2 during installation of a package shows what other packages are installed and why. Maybe there is a way to query it.

---

<div class="post-metadata">

### Author: ![reynir](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/reynir/32/6496_2.png) [@reynir](https://discuss.ocaml.org/u/reynir)
#### Post date: [August 30, 2018, 6:49pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/11 "2018-08-30T18:49:13Z")

</div>

You can use `opam list --recursive --required-by some-package` to list all recursive dependencies for some-package. Unfortunately I’ve found this includes the union of dependencies for all versions of some-package. To avoid this you should specify a specific version of some-package: `opam list --recursive --required-by some-package.3.2.0`

---

<div class="post-metadata">

### Author: ![fugmann](https://avatars.discourse-cdn.com/v4/letter/f/c68b51/32.png) [@fugmann](https://discuss.ocaml.org/u/fugmann)
#### Post date: [August 31, 2018, 9:07am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/12 "2018-08-31T09:07:32Z")

</div>

I fixed a similar problem very recently, where one of the libraries we used were pulling in ppx\_deriving. After fixing, the resulting binary size was reduced by more than 10Mb.

Would it be possible to have dune warn if a library is listed in both `libraries` and `pps` statements in the dune configuration file? This would have caught the errors I found (and fixed).

Maybe the dune documentation could be more explicit in mentioning that ppx rewriter libraries should not be also be listed in libraries list, as its already considered a build time dependency.

/Anders

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [August 31, 2018, 12:43pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/13 "2018-08-31T12:43:12Z")

</div>

Here is a Ruby script that I have used to inspect the size of modules inside an OCaml binary on Linux by analyzing its nm(1) output: [https://gist.github.com/lindig/7ab6c663f7bb763322f65b7cda60f29c](https://gist.github.com/lindig/7ab6c663f7bb763322f65b7cda60f29c). It can also take two binaries. Output looks like this:

````auto
$ ~/src/tmp/size.rb _build/default/xc/xenops_xc_main.exe  
# modules in _build/default/xc/xenops_xc_main.exe (size in Kb)
Arg 10.7
Arg_helper 3.1
Array 11.5
ArrayLabels 0.3
Ast_402 54.5
Ast_403 56.0
Ast_404 56.8
Ast_405 59.3
Ast_406 60.1
Ast_407 60.1
Ast_convenience 4.9
Ast_helper 30.3
Ast_invariants 2.5
Ast_iterator 12.5
Ast_mapper 36.3
Astring 3.1
Astring_base 2.2
Astring_char 1.5
Astring_escape 4.4
Astring_string 23.7
Astring_sub 21.2
Astring_unsafe 0.3
Attr_helper 0.8
B64 2.7
Backtrace 10.3
Base 10.0
Base__Applicative 5.1
Base__Applicative_intf 0.5
Base__Array 20.6
Base__Array0 0.9
Base__Array_permute 0.4
Base__Avltree 8.7
Base__Backtrace 1.0
Base__Binary_search 2.4
Base__Binary_searchable 0.6
Base__Binary_searchable_intf 0.0
Base__Blit 2.3
Base__Blit_intf 0.0
Base__Bool 1.3
Base__Buffer 0.7
Base__Buffer_intf 0.0
Base__Bytes 3.8
Base__Bytes0 0.3
Base__Bytes_set_primitives 0.0

...omitted...

Xenbus_utils 0.8
Xenctrl 1.3
Xenctrlext 0.0
XenguestHelper 6.4
Xenops_client 1.4
Xenops_helpers 0.9
Xenops_hooks 2.6
Xenops_interface 294.1
Xenops_migrate 4.9
Xenops_server 139.4
Xenops_server_plugin 1.8
Xenops_server_skeleton 3.3
Xenops_server_xen 133.1
Xenops_task 3.6
Xenops_types 116.0
Xenops_utils 28.8
Xenops_xc_main 2.0
Xenopsd 8.0
Xenstore 3.6
Xenstore_watch 0.1
Xmlm 41.5
Xmlrpc 14.0
Xs_client_unix 12.1
Xs_handle 0.9
Xs_protocol 18.2
Xs_transport 0.6
Xs_transport_unix_client 0.9
Yojson 155.5
_startup 39.2
_system        
```
````

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [August 31, 2018, 1:47pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/14 "2018-08-31T13:47:38Z")

</div>

Could you describe the fix in more detail? We are also using ppx\_deriving.

---

<div class="post-metadata">

### Author: ![samoht](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/samoht/32/81_2.png) [@samoht](https://discuss.ocaml.org/u/samoht)
#### Post date: [August 31, 2018, 4:33pm UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/15 "2018-08-31T16:33:48Z")

</div>

@lindig just don’t use `ppx_tools_versioned.5.2` which is broken.

---

<div class="post-metadata">

### Author: ![fugmann](https://avatars.discourse-cdn.com/v4/letter/f/c68b51/32.png) [@fugmann](https://discuss.ocaml.org/u/fugmann)
#### Post date: [September 1, 2018, 8:07am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/16 "2018-09-01T08:07:41Z")

</div>

Just never include `ppx_driver` or any ppx rewriter library in the list of library dependencies. One of the commits I did to fix thix can be seen [here](https://github.com/andersfugmann/ppx_protocol_conv/commit/b608269d5d800d6c4a8141c4b3982036c83d9016).

/Anders

---

<div class="post-metadata">

### Author: ![lindig](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lindig/32/532_2.png) [@lindig](https://discuss.ocaml.org/u/lindig)
#### Post date: [September 1, 2018, 8:15am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/17 "2018-09-01T08:15:56Z")

</div>

Thank you. Just to be explicit: when a PPX rewriter introduces a runtime dependency for the code it generates, has this dependency to be declared at all where the PPX rewriter is used? Or is this automatically taken care of by the PPX rewriter’s META data?

In the latter case, any mention of PPX libraries in jbuild files are likely to be wrong. From your commit I get the impression that runtime libraries need to be declared by the user of a PPX.

A small experiment with `ppx_deriving` suggests to me that it is enough to declare `(preprocess (pps (ppx_deriving.std)))` and that the runtime code is linked into the final result without having to mention it explicitly in the `jbuild` file. [https://github.com/lindig/hello/tree/ppx](https://github.com/lindig/hello/tree/ppx)  
`

---

<div class="post-metadata">

### Author: ![mseri](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mseri/32/91_2.png) [@mseri](https://discuss.ocaml.org/u/mseri)
#### Post date: [September 1, 2018, 8:27am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/18 "2018-09-01T08:27:07Z")

</div>

I think this discussion may be also relevant in this regard: [https://github.com/ocaml/opam-repository/issues/11852](https://github.com/ocaml/opam-repository/issues/11852)

---

<div class="post-metadata">

### Author: ![hannes](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/hannes/32/2302_2.png) [@hannes](https://discuss.ocaml.org/u/hannes)
#### Post date: [September 1, 2018, 11:06am UTC](https://discuss.ocaml.org/t/reducing-mirageos-image-size-using-ocamlclean/2481/19 "2018-09-01T11:06:18Z")

</div>

> [@lindig](#):
>
> Thank you. Just to be explicit: when a PPX rewriter introduces a runtime dependency for the code it generates, has this dependency to be declared at all where the PPX rewriter is used? Or is this automatically taken care of by the PPX rewriter’s META data?

This is tricky to answer, PPX rewriter themselves don’t contain any magic to add runtime dependencies to META files (that’s why we have [nocrypto](https://github.com/ocaml/opam-repository/pull/12062), [tls](https://github.com/mirleft/ocaml-tls/commit/be4f0ef67a666ccc866fd7fbbc0120a25effd032) (thx to diml), and a similar patch in x509 to include runtime dependency of ppx).

OTOH dune, as diml mentioned [here](https://github.com/ocaml/opam-repository/pull/11898#issuecomment-387355221), handles runtime dependencies of PPX rewriters automatically.

> [@lindig](#):
>
> `ocamlfind query -r package` shows all dependencies of `package` . These should include compile-time dependencies

AFAICT, `ocamlfind query` uses the META files, which only list runtime dependencies, and thus no compile-time dependencies are involved. I first look into `ocamlfind` output, and then into the META files directly to find these dependencies.

> [@lindig](#):
>
> Here is a Ruby script that I have used to inspect the size of modules inside an OCaml binary on Linux by analyzing its nm(1) output: [size.rb · GitHub](https://gist.github.com/lindig/7ab6c663f7bb763322f65b7cda60f29c)

This looks great!
