Michael-F-Bryan / include_dir

The logical evolution of the include_str macro for embedding a directory tree into your binary.
https://michael-f-bryan.github.io/include_dir
MIT License
339 stars 38 forks source link

Warn on very large assets #20

Open Michael-F-Bryan opened 7 years ago

Michael-F-Bryan commented 7 years ago

I accidentally tried to include about 400MB of stuff the other day and rustc ended up using stupidly huge amounts of RAM trying to compile it all. It's probably a good idea to emit a warning if the embedded assets will be larger than about 100MB or so...

ExpHP commented 6 years ago

Even 100MB is way too big.

Today I had a reported issue where rustc used over 8GB of memory because a single 12MB file was misplaced into the directory.

Michael-F-Bryan commented 6 years ago

I'm quite surprised. If you look at the implementation, files are embedded by creating a normal &'static [u8]. I'm not sure why it's using so much memory when this is just another constant...

ExpHP commented 6 years ago

I do admit it that it is a fairy simple implementation (and I would not have expected the immensely popular quote! macro to have such problems!), but I can confirm on my own machine that stable or nightly, release or debug all use over 8GB of memory to embed a 15MB file.

On linux:

# Make a 15 MB file
dd if=/dev/zero of=src/item bs=1M count=15

# Limit this shell process and all children to approx 8GB for ease of testing
ulimit -v 8000000

cargo build
# eventually dies with 'memory allocation of 171872600 bytes failed'

I notice that quote is a macro_rules! macro, which surely must expand to many smaller helper macro invocations. Perhaps this is the root of the inefficiency? I haven't looked too far into it.


What about having the proc_macro expand to a call to include_bytes? Something like:

impl ToTokens for File {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let path = self.path.display().to_string();

        let tok = quote!{
            File {
                path: #path,
                // FIXME: might need adjustment to account for CARGO_MANIFEST_DIR
                contents: include_bytes!(#path),
            }
        };

        tok.to_tokens(tokens);
    }
}

I'm going to try playing around with this.

ExpHP commented 6 years ago

Okay, so I tried my suggestion above, and:

ExpHP commented 6 years ago

Sorry for hijacking this issue, by the way. I've created #33 as a separate actionable item or for continuing this discussion.