Open jensjoha opened 4 years ago
Update: Here are tables with using gzip in dart with a compression level of 1 instead, which makes the issue "less pressing".
Transfer speed of 50MB/s:
Compressor name | Compress. | Ratio | Time |
---|---|---|---|
zstd 1.4.3 -4 | 215 | 29.53 | 0.079731 |
zstd 1.4.3 -3 | 260 | 29.69 | 0.080163 |
zstd 1.4.3 -2 | 404 | 31 | 0.0837 |
zstd 1.4.3 -5 | 125 | 28.81 | 0.108 |
gzip -1 in dart | 112.5 | 33.95 | 0.12 |
lz4 1.9.2 | 663 | 44.5 | 0.12015 |
snappy 2019-09-30 | 493 | 44.99 | 0.121473 |
memcpy (aka uncompresed) | 10051 | 100 | 0.27 |
gzip in dart | 30 | 29.8 | 0.45 |
Transfer speed of 30MB/s:
Compressor name | Compress. | Ratio | Time |
---|---|---|---|
zstd 1.4.3 -5 | 125 | 28.81 | 0.129645 |
zstd 1.4.3 -4 | 215 | 29.53 | 0.132885 |
zstd 1.4.3 -3 | 260 | 29.69 | 0.133605 |
zstd 1.4.3 -2 | 404 | 31 | 0.1395 |
gzip -1 in dart | 112.5 | 33.95 | 0.152775 |
lz4 1.9.2 | 663 | 44.5 | 0.20025 |
snappy 2019-09-30 | 493 | 44.99 | 0.202455 |
memcpy (aka uncompresed) | 10051 | 100 | 0.45 |
gzip in dart | 30 | 29.8 | 0.45 |
Transfer speed of 5MB/s:
Compressor name | Compress. | Ratio | Time |
---|---|---|---|
zstd 1.4.3 -5 | 125 | 28.81 | 0.77787 |
zstd 1.4.3 -4 | 215 | 29.53 | 0.79731 |
zstd 1.4.3 -3 | 260 | 29.69 | 0.80163 |
gzip in dart | 30 | 29.8 | 0.8046 |
zstd 1.4.3 -2 | 404 | 31 | 0.837 |
gzip -1 in dart | 112.5 | 33.95 | 0.91665 |
lz4 1.9.2 | 663 | 44.5 | 1.2015 |
snappy 2019-09-30 | 493 | 44.99 | 1.21473 |
memcpy (aka uncompresed) | 10051 | 100 | 2.7 |
I'll probably try to patch up flutter and the vm and test that out to get more "real world numbers".
zstd might be a good one to add. It's been registered as a possible content-encoding for HTTP, and Chrome might implement it. If we add it to dart:io
, it would at least find use by HttpClient
.
Seems like Chrome is going ahead with zstd, and Dart should totally add it. I've opened an issue (#53906) for Brotli as well. Both would find use in HttpClient
.
It would be nice to support more compression algorithms and zstd and Brotli seem to both be good choices.
There is the concern that it would increase the binary size of apps not insignificantly, particularly due to their dictionary sizes. However, standardized Brotli support would allow Flutter apps to use WOFF2 fonts, which might make up for some of the increased size?
Dart supports gzip out of the box (e.g. GZIP.encoder), and it is for instance used in flutter to speedup the transfer to device (https://github.com/flutter/flutter/blob/9666f697fb241db3d7aeb9bd9bf2b965e9c916e8/packages/flutter_tools/lib/src/devfs.dart#L50).
I've experimented with disabling it in flutter, and checking the compression level of a (big, 13.5 MB) partial dill file. I found the following (sending it to an emulator).
As-is (i.e. with gzip compression) it takes ~475 ms to send it to the device.
Disabling compression yields (here I ran it 5 times)
so we have a transfer speed of between 47 and 80 MB/s (between 12.5 ms and 21 ms per MB) (on emulator, on a real device, e.g. connected via wifi or usb2, that could certainly be slower).
I also timed the compression and the input size and output size:
(notice that the sizes aren't all exactly the same as I did this by performing an edit in the program). The compression ratio ~0.298 (i.e. good) and the compression speed: ~30MB/s (i.e. slow).
Assuming that we can transfer a block while compression the next one and that compressing the first block and decompressing the last block it negligible time-wise, the time is going to be something like max(compression time, transfer time, decompression time).
For the 13.5 MB dill used in this test: Assuming transfer of about 50 MB/s, for uncompressed data, this gives us max(0, 13.5/50, 0) = 0.27 seconds.
Assuming transfer of about 50 MB/s and compression rate of 0.298 and compression speed of 30MB/s, (lets assume decompression is free) this gives us max(13.5/30, 13.5*0.298/50, 0) = 0.45 seconds.
This seems consistent with the numbers from above.
Now lets imagine other compression schemes and different transfer speeds.
Running lzbench on it to get an idea of other compression schemes available gives
Caveats: This was run on the partial dill file which contains lots of text and will compress differently than for instance images would. In general I would assume that images (and other resources) does not compress very well as they are already compressed and that this would thus give a good indicator of real-world-performance for this use-case. This could be wrong though. In the below I also assume that all compression schemes can operate in a "streaming" fashion so the discussed formula (max(compression time, transfer time, decompression time)) holds.
Using the calculation from above, with a transfer speed of 50MB/s it gives me this (I've semi-arbitrarily removed most compression schemes here):
Conclusions: At this transfer speed, doing gzip is the worst thing you can do. Also, for this input,
zstd
compresses better thangzip
and does so a lot faster, so will always be better (under the maybe naive assumptions in this text). Usingzstd 1.4.3 -4
instead ofgzip
would make the transfer more than 5 times faster. Usingsnappy 2019-09-30
would make it more than 3 times faster.Lets try with 30MB/s (I expect this to be somewhat realistic via USB2):
Basically the same conclusion as before. Using
zstd 1.4.3 -5
(or-4
) instead ofgzip
would make the transfer more than 3 times faster.snappy 2019-09-30
more than 2 times faster.Lets try with 5MB/s (I expect this to be somewhat realistic via semi-bad wifi):
Here
gzip
gives value for the money compared to not going any compression at all, butzstd
is still faster.Generally I would assume that a developer uses a phone connected via usb (or an emulator) in which case picking another compressor would speed things up a good deal, so: Can we make Dart support more compression schemes, please?
/cc @mraleph @a-siva @aam