15 comments

  • danlark13 hours ago
    It&#x27;s a somewhat known tradeoff, you can streamline and make the format friendlier to do memcpy which this library targets, the more memcpys you do, the faster it is overall to decode. On highly compressible data lz4, snappy become faster. Snappy on level 2 has faster decompression speed<p>But you have to pay the price that you need a slower encoding, because finding matches, putting restrictions on match lengths, putting things in different streams have costs you need to pay upfront.<p>Anyway good work, there is probably a need for that.<p>&#x2F;&#x2F; Currently own Google&#x27;s snappy and do compression at Google<p>P.S. if you want better snappy&#x27;s results, compile with clang.<p>P.S.S you can optimize aarch64 speed by movemasks from shrn instruction. <a href="https:&#x2F;&#x2F;developer.arm.com&#x2F;community&#x2F;arm-community-blogs&#x2F;b&#x2F;servers-and-cloud-computing-blog&#x2F;posts&#x2F;porting-x86-vector-bitmask-optimizations-to-arm-neon" rel="nofollow">https:&#x2F;&#x2F;developer.arm.com&#x2F;community&#x2F;arm-community-blogs&#x2F;b&#x2F;se...</a>
    • nonadhocproblem3 hours ago
      Thanks for the feedback!<p>I haven&#x27;t implemented any ARM-specific dispatch yet (there are currently no NEON paths for vector ops either, and we instead trust the compiler to autovectorize), and will do so for upcoming versions.
  • purple-leafy2 hours ago
    Compression is so tricky.<p>I got really into compression experimenting while I was developing my browser game.<p>I was trying to compress entire human gameplay matches into a QR code, for upto 60 minutes of gameplay both single player and multiplayer.<p>My game is a fast paced, grid based, snake x scrabble word game.<p>My first compression attempt was to do run length encoding and cardinal directions, encoded into 1 byte. This was really compressible data.<p>The best approach was to use relative direction changes instead of cardinal directions. Compressed even better as the raw data was more consistent (for the most part you are moving forward etc).<p>Some other attempts were: zone based encoding, double movement pattern encoding (much smaller raw data but less compressible), triple movement pattern encoding, interrupt encoding.<p>I am at a point where I can fit all 30 minute single player games into a QR code, some 60 minute games, and with a special encoding scheme I can fit 15 minute N player multiplayer matches in a QR code<p>For reference qr code max size is about ~3000 bytes
  • wolf550e4 hours ago
    From status in readme in github:<p>- misa77&#x27;s format may change unexpectedly as it&#x27;s still v0.x.y.<p>- The decoder assumes that the input is a valid misa77 stream. Invalid input is UB and I offer no guarantees for whatever misa77 does in this case.<p>- It&#x27;s been through some local fuzzing but is not hardened, so treat it as experimental.
    • cogman102 hours ago
      - Excellent of the author to call these things out.<p>- All 3 things are show stoppers for any real use.<p>An unstable format which trusts input is a CVE and data loss magnet.
      • nonadhocproblem2 hours ago
        I&#x27;ll be resolving issues 2 and 3 in the next couple of weeks (adding a safe decoder and doing a lot of fuzzing).<p>The format, however, might continue to change for some time because I want to push performance even further.
        • cogman102 hours ago
          Which is great and please don&#x27;t take this as me being critical of the approach you are taking. I think it&#x27;s perfectly reasonable during early development have your compressed stream in flux.<p>I&#x27;ve been bitten in the past with other libs that weren&#x27;t as explicit about their stability.
      • vardump2 hours ago
        That is a bit too harsh. Not all applications require those guarantees. It’s fine if you can trust the inputs.
  • mijoharas3 hours ago
    So, I couldn&#x27;t see it in the readme, apologies if I missed it but why?<p>It&#x27;s a very significant speedup in decompression speed (albeit with a compression speed slowdown as a trade-off), but what&#x27;s the insight that makes it faster? What was the idea or approach behind it?
    • nonadhocproblem3 hours ago
      So it&#x27;s essentially &quot;LZ4 unshackled&quot;. I&#x27;ve made several modifications to the LZ4 format, most of which are in service of eliminating branches&#x2F;making them more predictable, and making decompression very friendly to out-of-order cores by hiding false data dependencies behind a rarely taken branch (similar to this: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=48889148">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=48889148</a>).<p>Some concrete changes in the format are:<p><pre><code> - match length per block is capped to 32 - distance to a match must be &gt;= a fixed constant - unlike lz4, tokens and literals have separate streams - format of the token byte has been changed </code></pre> Now, this format allows our decompressor&#x27;s hot loop to be very simple (in terms of the number of branches it has). This simplicity in turn allows our compressor to create a compressed stream that is friendly to the (small number of) branches in the decompressor.<p>The experimental compression modes (see readme) attempt to exploit this even further (but are even slower at compression). I define a &quot;cost&quot;, which is a linear function of the branches induced by a compressed stream (this function serves as a proxy for decompression time), and then do a DP to minimise this cost.
      • sroussey3 hours ago
        How much of the speed-up is attributed to not hardening the code?<p>And i do not mean this in a flippant way, as how to harden with speed in mind might alter how to design the format and the codec.
        • nonadhocproblem3 hours ago
          Almost none. Once again, simplicity comes to our rescue here. The decompressor is simple and a naive safe version I implemented but haven&#x27;t merged into main yet (see: <a href="https:&#x2F;&#x2F;encode.su&#x2F;threads&#x2F;4514-misa77-ridiculously-fast-decompression-at-good-ratios?p=88395&amp;viewfull=1#post88395" rel="nofollow">https:&#x2F;&#x2F;encode.su&#x2F;threads&#x2F;4514-misa77-ridiculously-fast-deco...</a>) is only ~5% slower than the current unsafe version (and can very likely be made faster).
      • edflsafoiewq2 hours ago
        What&#x27;s the advantage of the separate streams? That presumably prevents a streaming encoder&#x2F;decoder.
        • nonadhocproblem2 hours ago
          Yes, that prevents streaming for now.<p>What is the advantage of this? Out-of-order execution (see my decoder&#x27;s hot loop: <a href="https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;misa77&#x2F;blob&#x2F;3a91af162dfc4a45fbd6f811d4004de25be744c3&#x2F;src&#x2F;decompress_impl.h#L55" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;misa77&#x2F;blob&#x2F;3a9...</a>).<p>In particular, on even moderately compressible data most blocks take the following form:<p><pre><code> - 1 token byte + 2 distance bytes - a somewhat unpredictable number of literal bytes </code></pre> If these streams are interleaved, then it&#x27;s harder for the out-of-order core to process the token bytes of several blocks in advance (as the position of the next token byte depends on the unpredictable number of literal bytes in the current block). However, if you separate them (all token bytes in a prefix, and literal bytes in a suffix), the CPU can speculatively parse token bytes of a lot of blocks in advance (as most of the time, it just has to step forward by three bytes to go to the next block&#x27;s token byte).
          • derf_12 minutes ago
            I used the same &quot;separate stream&quot; design (one of them coded backwards from the end, to eliminate the need to send a separate offset) when working on video compression, to separate out arithmetic-coded bits from literal bits. It&#x27;s a good idea. The only reason it isn&#x27;t in AV1 is because hardware wanted to do DRM decryption in order.
  • scottchiefbaker4 hours ago
    Almost double the decompression speed, *and* a higher compression ratio than LZ4? That&#x27;s very promising.<p>I don&#x27;t see much in your README that talks about how a developer would integrate misa into their code. I might suggest some basic code samples to help a developer integrate misa decode into their project.<p>Congrats, looks like a cool project.
  • logdahl4 hours ago
    Nice results, I will keep a watch on this! Would be interesting to see benchmarks vs Oodle compression, I think the most similar one is Selkie?
  • kazinator4 hours ago
    &gt; <i>It offers particularly high decompression throughput on highly compressible files.</i><p>You know, you would expect that this is commonly observed. You&#x27;d expect, say, simple RLE (run length encoding) to be like this. It&#x27;s more expensive to produce output requiring the processing of a large number of RLE opcodes that produce short sequences than one opcode that produces one long sequence.
  • bootlegbilly5 hours ago
    this is super interesting! im excited to give this a look this afternoon, since I specifically have wanted faster throughout for decompressing maps in a game engine.
    • nonadhocproblem4 hours ago
      Hey, glad to hear that you found it interesting.<p>misa77 primarily targets textual data (ie. byte-aligned data formats where each byte corresponds to a symbol), so I hadn&#x27;t tested it on game assets much until now.<p>After seeing your comment, I pulled some random assets from Pathfinder WoTR (in fact, Unity compresses them with lz4hc) and DOS2. The gains are much more modest here due to asset data being mostly floats, but level 0 performs decently nevertheless.<p>Results on a map asset (WoTR):<p><pre><code> codec decode ratio encode misa77 -0 4061 MB&#x2F;s 61.52% 40.4 MB&#x2F;s misa77 -1 2851 MB&#x2F;s 59.04% 36.2 MB&#x2F;s lz4 2561 MB&#x2F;s 62.66% 488 MB&#x2F;s lz4hc -12 2428 MB&#x2F;s 55.53% 6.23 MB&#x2F;s </code></pre> Results on equipment asset (WoTR):<p><pre><code> codec decode ratio encode misa77 -0 4675 MB&#x2F;s 54.33% 48.6 MB&#x2F;s misa77 -1 3752 MB&#x2F;s 51.96% 40.9 MB&#x2F;s lz4 3101 MB&#x2F;s 55.21% 497 MB&#x2F;s lz4hc -12 3036 MB&#x2F;s 47.62% 6.25 MB&#x2F;s </code></pre> Results on texture asset (DOS2):<p><pre><code> codec decode ratio encode misa77 -0 5546 MB&#x2F;s 67.99% 47.0 MB&#x2F;s misa77 -1 2991 MB&#x2F;s 63.79% 31.5 MB&#x2F;s lz4 3602 MB&#x2F;s 68.53% 623 MB&#x2F;s lz4hc -12 2689 MB&#x2F;s 59.30% 9.01 MB&#x2F;s </code></pre> Note: the benchmarking setup is identical to the intel x86-64 one described in the readme.
    • zX41ZdbW3 hours ago
      You can look at the LZ4 decompression implementation in ClickHouse: <a href="https:&#x2F;&#x2F;presentations.clickhouse.com&#x2F;2018-highload-siberia&#x2F;" rel="nofollow">https:&#x2F;&#x2F;presentations.clickhouse.com&#x2F;2018-highload-siberia&#x2F;</a> (the presentation is quite old, but the implementation was updated recently). It uses the same LZ4 format, just decompresses faster.
  • Sesse__4 hours ago
    Interesting, but if you are not robust to corrupted&#x2F;malicious data, it is really in a different class of algorithm and it is hard to compare speeds directly.<p>From memory, 2505 MB&#x2F;sec also sounds on the low side for LZ4 on a modern CPU?
    • nonadhocproblem4 hours ago
      Someone asked this on encode.su too (see my reply here: <a href="https:&#x2F;&#x2F;encode.su&#x2F;threads&#x2F;4514-misa77-ridiculously-fast-decompression-at-good-ratios?p=88395&amp;viewfull=1#post88395" rel="nofollow">https:&#x2F;&#x2F;encode.su&#x2F;threads&#x2F;4514-misa77-ridiculously-fast-deco...</a>).<p>In short, my decompressor is very simple, and a naive safe version of the decompressor is only about 5% slower than the current unsafe one (and I will add this safe version in v0.3.0).<p>As for the raw throughput numbers being low here, it&#x27;s because Intel Turbo (frequency boost) was disabled for stability, and the CPU was running at a fixed frequency of 2.1 GHz (I&#x27;ve confirmed that the relative performance scales similarly even with Turbo enabled).
    • actionfromafar4 hours ago
      You mean some kind of error detection? LZ4 doesn&#x27;t have that.
      • kzrdude4 hours ago
        Have defined behaviour on any input, i.e not causing security issues, memory safety issues on untrusted inputs. Lz4 has this.
  • avph3 hours ago
    This looks awesome for boot firmware. How large is the decompressor code?
  • zX41ZdbW3 hours ago
    It is slower than LZ4 on AArch64.
    • nonadhocproblem3 hours ago
      Could you tell me what your test setup and corpus was?<p>For reference, to test ARM64, I tested v0.1.0 on an M3 mac with this fork of lzbench: <a href="https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;lzbench&#x2F;tree&#x2F;add-misa77" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;lzbench&#x2F;tree&#x2F;ad...</a><p>Here, lz4&#x27;s decompression speed was far slower than misa77 and zxc. Results are here: <a href="https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;misa77&#x2F;blob&#x2F;main&#x2F;misc&#x2F;lzbench-results-archive&#x2F;0.1.0&#x2F;apple-m3.txt" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;welcome-to-the-sunny-side&#x2F;misa77&#x2F;blob&#x2F;mai...</a>
    • noname1203 hours ago
      Source?
      • zX41ZdbW3 hours ago
        Just tested a few minutes ago on the ClickBench dataset. Overall quite good, but, depending on particular columns, most of the time slower - e.g., ~2.0 vs ~2.8 GB&#x2F;sec on Graviton 4 machine in AWS.
        • zX41ZdbW3 hours ago
          <a href="https:&#x2F;&#x2F;pastila.nl&#x2F;?cafebabe&#x2F;5763fb6ec6db85bf0f20fbd710a8c834.md" rel="nofollow">https:&#x2F;&#x2F;pastila.nl&#x2F;?cafebabe&#x2F;5763fb6ec6db85bf0f20fbd710a8c83...</a>
        • croemer3 hours ago
          You probably meant MB&#x2F;sec not GB.
          • wmf2 hours ago
            No? Decompression is rated in GB&#x2F;s per core now.
  • mervz2 hours ago
    how does it compare to macklin71?
  • pmarreck35 minutes ago
    cool, now do zstd!
  • zuzululu3 hours ago
    so whats the actual use case for this ? streaming ? games?
  • throwaway747474 hours ago
    What&#x27;s the Weissman score?