Skip to content
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

Use only level 1 and 2 with python-isal #142

Merged
merged 4 commits into from
Jan 17, 2024
Merged

Use only level 1 and 2 with python-isal #142

merged 4 commits into from
Jan 17, 2024

Conversation

rhpvorderman
Copy link
Collaborator

@rhpvorderman rhpvorderman commented Jan 17, 2024

Zlib compression level 0 outputs uncompressed deflate format, which consists of 64K blocks in the following format:
1 byte signifying data is uncompressed. (Actually it is a two-bit code, but I am not going to rewrite the spec here). 2 bytes with an unsigned 16 bit integer that holds the length of the following block. 2 bytes with the unsigned 16 bit integer complemented for parity checking. Then follows the uncompressed block of up to 64K in length.

ISA-L however compresses the data with a special algorithm. This is an area where zlib and ISA-L differ. That is okay, but xopen should behave somewhat consistently in terms of output for the same parameters and not let it be backend dependent. Also level 0 should be quite fast on zlib and zlib-ng as well, there is no reason to use ISA-L for speed here.

Next is level 3. For FASTQ data, I find that this has very little extra value in terms of compression. Other libraries, such as zlib-ng and zlib do a better job here. Also it is much slower than levels 1 or 2, so it is a bit of a useless level for FASTQ data. ISA-L level 1 and 2 outperform anything by huge margins and since level 1 is the default I don't see why level 3 can't be done by a library that compresses better.

All right: benchmarks. Not done very cleanly, with processes runniing in the background and n=1, but at least it gives a good ballpark indication.

before:

python benchmark_levels.py ~/test/nanopore_100000reads.fastq ramdisk/test.fastq.gz
Compressed at level 0 with 0 threads; filesize: 1241299982, time: 4.584214687347412 seconds
Compressed at level 1 with 0 threads; filesize: 987346940, time: 4.9248528480529785 seconds
Compressed at level 2 with 0 threads; filesize: 988121796, time: 5.152158260345459 seconds
Compressed at level 3 with 0 threads; filesize: 990344221, time: 8.79483151435852 seconds
Compressed at level 4 with 0 threads; filesize: 953739158, time: 34.5846734046936 seconds
Compressed at level 5 with 0 threads; filesize: 945597849, time: 50.54869747161865 seconds
Compressed at level 6 with 0 threads; filesize: 936937471, time: 96.95266628265381 seconds
Compressed at level 0 with 1 threads; filesize: 1241490149, time: 4.322765588760376 seconds
Compressed at level 1 with 1 threads; filesize: 986751063, time: 4.7672388553619385 seconds
Compressed at level 2 with 1 threads; filesize: 987497150, time: 4.939749240875244 seconds
Compressed at level 3 with 1 threads; filesize: 989851198, time: 8.73461651802063 seconds
Compressed at level 4 with 1 threads; filesize: 934568019, time: 27.754233360290527 seconds
Compressed at level 5 with 1 threads; filesize: 932150001, time: 33.990896701812744 seconds
Compressed at level 6 with 1 threads; filesize: 926300592, time: 57.50165820121765 seconds

after:

 python benchmark_levels.py ~/test/nanopore_100000reads.fastq ramdisk/test.fastq.gz
Compressed at level 0 with 0 threads; filesize: 1719300551, time: 1.0877585411071777 seconds
Compressed at level 1 with 0 threads; filesize: 987346940, time: 4.940786123275757 seconds
Compressed at level 2 with 0 threads; filesize: 988121796, time: 5.1339592933654785 seconds
Compressed at level 3 with 0 threads; filesize: 944408772, time: 23.135488033294678 seconds
Compressed at level 4 with 0 threads; filesize: 934668651, time: 28.04243803024292 seconds
Compressed at level 5 with 0 threads; filesize: 932283422, time: 34.2128050327301 seconds
Compressed at level 6 with 0 threads; filesize: 926345773, time: 57.90689778327942 seconds
Compressed at level 0 with 1 threads; filesize: 1719316928, time: 0.9414026737213135 seconds
Compressed at level 1 with 1 threads; filesize: 986751063, time: 4.759371519088745 seconds
Compressed at level 2 with 1 threads; filesize: 987497150, time: 4.957266092300415 seconds
Compressed at level 3 with 1 threads; filesize: 944154982, time: 22.834784269332886 seconds
Compressed at level 4 with 1 threads; filesize: 934568019, time: 27.81139039993286 seconds
Compressed at level 5 with 1 threads; filesize: 932150001, time: 33.65570855140686 seconds
Compressed at level 6 with 1 threads; filesize: 926300592, time: 57.73633337020874 seconds

The benchmark show that there was also a fault in the logic introduced at some point (EDIT: due to an if->elif replacement in the refactoring). If python-isal with threads=0 threw a ValueError for a bad compression level, zlib-ng was skipped and zlib used instead. This is now also fixed.

As you can see zlib-ng gets a nice improvement over python-isal in terms of compressed size at level 3. "Compression" at level 0 is now non-existent as expected and as a result is a lot faster, also as expected.

Overall I am very happy with the minimal code size required to affect these changes. Python-isal is a special case, so I don't mind a bit more specific special-casing in the code.

@rhpvorderman rhpvorderman requested a review from marcelm January 17, 2024 13:49
@marcelm marcelm merged commit 9940fe8 into main Jan 17, 2024
19 of 20 checks passed
@marcelm marcelm deleted the igziplevels branch January 17, 2024 14:00
@rhpvorderman
Copy link
Collaborator Author

Thanks for the quick merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants