-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add transparent compression of the .mem file, to make deployment easier #4
Comments
LIkely yes, they're probably using a whitelist of file types that can be gzipped and cached. Incidentally this is one of the reasons I was experimenting with an external CDN, which gives you more control ovr caching behaviour. (The other reason is so I can upload pre-zipped versions of the large assets, and do a better job of it than the default gzip-encoding settings in most webserver software). |
But we can use this as a trigger. Because other users will also used a default server configuration and run into the same "Problem"... So, what's about to change the extension? |
Good idea. I'm a little hesitate to change too much from the way emscripten does it, but we do ultimately have control over the name of this file because of https://github.com/pypyjs/pypyjs/blob/master/tools/extract_memory_initializer.py So we need to find an extension that will (1) ensure the content-type is set to something binary like |
(Although I note that it does seem to cache correctly for me, but it's not gzip-encoded so it takes around 12 seconds to download) |
According to http://githubengineering.com/rearchitecting-github-pages/ the github pages setup is a pretty standard nginx install with fastly in front of it, meaning the default set of types that will get compressed is likely as described here: https://www.fastly.com/blog/new-gzip-settings-and-deciding-what-to-compress I don't think I'd be comfortable pretending that this binary blob is any of those file types :-( |
Hm. That's boring. The best solution would be a file type that worked on every server defaults. Btw. is there no way to compress the file on creation and decompress it on-the-fly in browser? Maybe with a better compression ratio, like LZMA... e.g.: https://github.com/nmrugg/LZMA-JS So we independent on server configuration and maybe faster loading, because of better compression. Maybe use LZMA on all file requests to speedup ?!? |
Yes, we should definitely try that. LZMA does produce much better compression on these files, but I haven't benchmarked the LZMA-JS implementation on it. The downside is it would break the browser's native caching facilities, but the tradeoff may be worth it. Feel like trying it out to see? :-) |
lzma package exist in python since 3.3... I have made a test script to see how long it takes and how good is the compression ratio the script: https://gist.github.com/jedie/95225b0ecb89f23688f3 Results: I don't know if the compressed data is really compatible with https://github.com/nmrugg/LZMA-JS Interesting question is how good/bad the server gzip do the job. Maybe by default, it's configured for speed than for good compression ratio?!? |
Thanks! That's definitely an improvement over gzip even at the highest compression level. I guess the next question is: how quickly does it decompress using LZMA-JS?
Likely, I think it defaults to something like |
I have made the same test for gzip... (Used zlib.compress) and add a "efficiency" value: efficiency is the relation between compression ratio to duration: (EDIT big output removed -> https://gist.github.com/jedie/d650de636711aa786235 ) sources: https://gist.github.com/jedie/95225b0ecb89f23688f3 Some zlib file sizes: I try to compare... I used level=9 from zlib and use the lzma entry that used a similar time:
lib/pypy.vm.js.mem
So: similar time results in better compression with lzma... No surprise ;) (Note: i used results from different runs. So the values vary a little bit here and there ;) ) |
With 3b0e3e6 i created a new branch here: https://github.com/pypyjs/pypyjs.github.io/tree/lzma_test There are three files:
In compress_lzma.py i used preset=3... This result in 2,88MB (both files and uncompressed is 19,2MB ;) )... Using a higher preset results in much more compression time, but didn't shrinks the files really more... How to tryout:
I'm not a JavaScript Junkie. So maybe i have make a few Bugs. The Web Workers variant doesn't really work. It seems to take a very long time... The no Web Workers variant works good here with Firefox 31.7.0 and chrom 43.0...
4 and 5sec sounds good, isn't it? Chrome is a little bit faster: 2 and 2sec. (Maybe the non ESR version of firefox is also faster?!?) Again, i'm not a JavaScript Junkie, so i didn't really know how to implement this in the pypy.js loading mechanism. |
Great, thanks for diving into this! I'll try to make some time this weekend to take your work here and plug it into the pypy.js loading mechanism to see how it performs.
That's certainly good compared to a cold load of the uncompressed file! The downside may be that we have to pay that overhead every time, even if the compressed file is loaded from the browser's cache. I was (somewhat naively) hoping that it would be around 1 second, and I guess Chrome's speed is not too far from that. |
I run another tests on a different computer... It's a old Intel Q9550 (quad code with 2,83GHz) under Linux Mint... IMHO it's a question of existing bandwidth... btw. found this: https://wiki.mozilla.org/LZMA2_Compression |
Another option may be to use a compression algorithm that's faster but has poorer compression, such as LZ4 or snappy. Here's a quick comparison using lz4:
Doing a pure-javascript lz4 decompression of the memory would still save a lot of download time compared to loading the raw file, and IIUC would be substantially quicker to decompress than LZMA. And it could still be combined with gzip content-encoding for folks who are able to tweak their server setup appropriately. |
Another candidate: http://liblzg.bitsnbites.eu/ I try to make a normal python package for lzg here: https://github.com/jedie/python-lzg |
Interesting benchmarks : https://quixdb.github.io/squash-benchmark/ --But no liblzg ;(-- EDIT: liblzg is there. Just named 'lzg'... I choose "dataset" the "Tarred source code of Samba 2-2.3"
Yes, lz4 seems to be really fast at decompression.
Here a cleaned chat with "samba sources" on RPi2: And here on beagleboard: But i didn't found a JavaScript implementation of "doboz" and "lzham"... zlib:deflat seems to be here: https://github.com/dankogai/js-deflate for lzo i only found "miniLZO" in JavaScript here: https://github.com/abraidwood/minilzo-js |
OK, i have done a first test: zlib:deflate is lighting fast compared to lzg!!! On the same machine, where lzg needs 12Sec:
204ms and 157ms is IMHO faster then we need, isn't it? EDIT: compression:
Compared to your values:
EDIT: Test code is here: a2c3253 |
Wow, that's pretty impressive! I'd be willing to bet we can get the time down even more by special-casing some of the logic for our needs a well.
From a quick look at the source, this implementation works with arrays of integers rather than with native |
Can you try to compile lzham via emscripten to JavaScript? See: richgel999/lzham_codec#9 |
I'll try, but I haven't got a lot of experience using it with CMake-driven C++ projects. Will let you know how I go... |
my try is here: richgel999/lzham_codec#9 (comment) |
Found some interesting pages: http://mainroach.blogspot.de/2013/07/the-state-of-web-compression_8.html |
With e62d9c8 i hacked to test https://github.com/google/zopfli zopfli should be compress more than zlib, but is compatible with it... It seems it's not worth it:
For this, i have used https://github.com/wnyc/py-zopfli |
With b4a3cea i refactor my test code and run a complete test with pypy.vm.js + pypy.vm.js.mem and all levels of zlib, bzip2 and lzma Results here: https://gist.github.com/jedie/d650de636711aa786235 I will cleanup this issues and remove all test results that exist in the gist ;) |
I have look at the WebAssembly examples:
In both cases the caching seems also not working... |
I expect WebAssembly to be really useful for reducing the size fo the code download (js vs bytecode) but it probably won't have much effect on the size of the memory data download - if it's the same compiled program then it would require the same memory image layout. So anything we do here will still be useful in a WebAssembly world. |
btw. I created a thread in "encode.ru" (Seems to be the biggest forum about data compression): Currently no suggestions :( Maybe my English is too bad... EDIT: Just forgot: zlib vs. bzip2: bzip2 makes also no sense. Is slower than LZMA with less compression ratio... This is also consistent with my compress measurements: pypy.vm.js:
pypy.vm.js.mem:
(Only best compress ratio/durations) |
With jedie@4af3e54 i started hacking to request/decompress a deflate files... |
Back to this question. The tests from #7 shows that .tar.gz and .zip is a usable file ending, that "activate" the caching ;) |
With jedie@e0b2cb1 i have made a rudimentary worked version. I have only worked on the editor page with a local copy of pypy.js here: https://github.com/jedie/pypyjs.github.io/blob/gh-pages/pypy_compression_test.js try out here: https://jedie.github.io/pypyjs.github.io/editor.html It fetches "./download/pypyjs.zip" witch contains these two files:
I have a little problem to use the mem file. But i found this: emscripten-core/emscripten#3187 and use memoryInitializerRequest see: https://kripken.github.io/emscripten-site/docs/tools_reference/emcc.html?highlight=memoryinitializerrequest (The --memory-init-file note box) The init process blocks the browser. Maybe while processing the mem file?!? And there is somewhere a bug, running the editor VM again. Maybe around the memoryInitializerRequest stuff... |
@jedie thanks for continuing to push on this. To be honest, I'm dubious about zipping the .js file because webservers are already good at this, and because we'll have to pay the cost of unzipping it on every startup even if it's loaded from the cache. I'm willing to be convinced by numbers though :-) I'm also hacking on a hand-written asmjs unzip implementation for loading the memory file, similar to #148 but using zip. Will be interesting to see how it compares performance-wise to the jszip stuff. |
Yes, .zip was not my first choice. But it seems that this is currently the best choice :( I just compare my startup with the "normal" startup: With empty cache, it's: ~9sec vs. ~11sec on my ~14MBit downlink. I would like to see your "hand-written asmjs unzip implementation" compared to my tests. |
Hm! I just found: https://github.com/ukyo/zlib-asm and the benchmark: http://imaya.github.io/demo/zlib/index.html than compares:
Then, i looked more on your work here: pypyjs/pypyjs@a1cb945#commitcomment-11928467 You use a sub-set of zlib:deflate... Would be interesting to compare this with zlib-asm,a full deflate implementation in asm.js... EDIT: With jedie@263862f i appy a bugfix: Now the "run" worked, too. I just cache the .mem file content into a global variable -> jedie@263862f#diff-cff69e84371ac601d670eba337a2b1d8R119 EDIT2: With jedie@151e18e i cache 'index.json' in similar way. |
I assume the smaller number is when things are zipped - so significantly faster in both cases? Hopefully I'll get a chance to run some tests like this myself at some stage this week. |
TODO: also include /lib/modules/index.json into the .zip file! I've been thinking about "Why not just put all files into a .json" (from #7 (comment) ) Actually, there are different questions to be answered:
We can merge request by put these "init" files into one (.tar, .zip, .json etc.):
Use .json container:
.json disadvantage:
To prevent the .json size bloat: There are some other "binary serialization format" stuff out there. e.g.:
But then, we have the same problem as with .zip or .tar:
Will this be faster then a uncompressed .tar usage? The current .zip solution can be also enhanced: Currently i use https://github.com/Stuk/jszip this used https://github.com/nodeca/pako for decompression. Using .tar and pako was not a good combination: See results here: #7 (comment) Maybe using .json (or msgpack/ubjson) with pako is maybe faster than the current solution?!? This should also enhanced the compression result. Because it's something like the 7-Zip "Solid compressing" (As I mentioned at the .tar.gz solution) Conclusion: I will try to create a test for "nativ .json usage" today... |
With jedie@e494644 i implemented a plain .json test. I only change the way how python packages are loaded. Not the init part, this stays by fetching pypyjs.zip... Just hit the "run" button on the page to compare:
Results with empty caches:
With filled caches (just hit run button several times):
Hm. parsing json is so slow in firefox 38.0 under linux?!? Maybe i made something wrong?!? btw. the github-server compression is not the best, but ok:
A very strange idea:
:-/ |
Now i can compare chrome vs. firefox...
Wow. Chrome is faster:
It the JSON parser in Chrome so much faster than in Firefox?!?
Seems to run a tick slower, but it's almost equal. |
OK, i try to figure out where the bottleneck is. The "runtime analyser" in firefox and chrome didn't help me here. So i add some "debug(duration)" in JS with: jedie/pypyjs.github.io@d705210...548a1c1 There my results: Firefox ".zip" solution: https://jedie.github.io/pypyjs.github.io/editor.html
Chrome ".zip" solution: https://jedie.github.io/pypyjs.github.io/editor.html
Firefox ".json" solution: https://jedie.github.io/pypyjs.github.io/json_test.html
Chrome ".json" solution: https://jedie.github.io/pypyjs.github.io/json_test.html
IMHO this duration outputs didn't cover the bottleneck :( EDIT: Just some "numbers game": I added up all duration (but not the "run in" times): |
@jedie this
I'm not seeing the same results - when I run your tests, AFAICT with a warm cache it runs in a few hundred milliseconds and almost all of that time is spend in the file loading routines. |
I have only generate and add platform to the git repro. So, you can only import this module... |
Seems that it will be re-downloaded every time :(
Maybe because of the ending .mem ?
The text was updated successfully, but these errors were encountered: