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

op-batcher: Embed Zlib Compressor into Span Channel Out ; Compression Avoidance Strategy #10002

Merged
merged 7 commits into from Apr 8, 2024

Conversation

axelKingsley
Copy link
Contributor

@axelKingsley axelKingsley commented Mar 29, 2024

What

Moves compressor handling directly to the Span Channel Out, and implements a compression avoidance strategy.

Why

Because Span Batches are not streaming structures, there is not much value in using the existing Compressor Interfaces for Span Channel Out. And actually, handling this difference in behavior costs us complexity and performance.

By moving Compression directly to the Span Channel Out, we achieve fewer buffer writes, more careful control of the compression buffer, and also achieve a simple optimization to avoid compression in the majority of cases

How

Embedded Compression

  • I moved the zlib.Writer directly into the Span Channel Out and rewrote the AppendSingularBatch function
  • Span Channel Out now has a double-buffer for RLP bytes. This is so that if the compressor becomes full, the Channel Out can choose to flip back to the previous RLP bytes and use that instead
  • The Channel Builder now fully separates calls to NewSingularChannelOut vs NewSpanChannelOut. When building span channels, the TargetOutput that would normally build a compressor is instead passed directly to the Channel Out

Compression Avoidance

The size of the RLP structure is taken into account before compressing. Now, if the RLP size is smaller than the compression target (aka, the uncompressed data is already small enough), no compression is done. And whenever compression is done, the uncompressed RLP size is recorded. The logic is as follows:

  • IF uncompressed_bytes < Target, Return Early
  • IF compressed_bytes + uncompressed_growth < Target, Return Early

This causes the compression to only happen at required times. The first time the uncompressed data surpasses the target, it becomes compressed, and the threshold is no longer exceeded. It then won't compress again until the uncompressed data takes up all the remaining space.

In production with a compression ratio of ~40%, we achieve a ~log(n) number of total compressions for a span batch during its construction.

Testing

  • Unit Tests
  • E2E Tests
  • Took some existing Singular Channel Out tests, and added sub-cases to test Span Batches in the same way
  • Added unit tests around the Span Channel Out's fullness and closing behaviors, which also test compression avoidance.

Performance Testing

Our random blocks do not see a great compression ratio. I confirmed this on commits prior to the changes here in this PR. This means that once the compression threshold is met the first time, it is already nearly full and will compress on most subsequent AppendSingularBatch calls.

However, even with the lower quality compression, the benefits of compression avoidance is still visible. I wrote a benchmark which incrementally adds to a Batch. It's a bit of a hack on the Go Benchmark Sub-Benchmark system, but it will take an empty Batch/SpanBatch and will create a new benchmark test case for every batch of X (default 100) batches. The time it takes to add those 100 batches is considered the test time, and then the next test case is the next 100 batches.
New test cases are added until the channel is full. I used a Compressor with a "Real" configuration in order to test real compression limits.

Old Performance:

BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_0-100-12         	       1	  53355083 ns/op	 5989560 B/op	   17575 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_100-200-12       	       1	 133496166 ns/op	12106224 B/op	   41712 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_200-300-12       	       1	 220721375 ns/op	20593624 B/op	   67156 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_300-400-12       	       1	 315674084 ns/op	28215928 B/op	   92049 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_400-500-12       	       1	 409993042 ns/op	34390488 B/op	  116572 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_500-600-12       	       1	 496338416 ns/op	41259296 B/op	  141237 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_600-700-12       	       1	 581250000 ns/op	50580560 B/op	  166595 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_700-800-12       	       1	 694019083 ns/op	56663544 B/op	  191730 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_800-900-12       	       1	 777665125 ns/op	62368624 B/op	  216826 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_900-1000-12      	       1	1029998333 ns/op	71497368 B/op	  241540 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1000-1100-12     	       1	1092751667 ns/op	82707776 B/op	  266003 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1100-1200-12     	       1	1118788417 ns/op	95322016 B/op	  290950 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1200-1300-12     	       1	1030652625 ns/op	91570816 B/op	  292472 allocs/op

New Performance:

BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_0-100-12         	       1	   1356792 ns/op	 1483880 B/op	   17320 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_100-200-12       	       1	   2617458 ns/op	 2412216 B/op	   41479 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_200-300-12       	       1	   3389083 ns/op	 3052560 B/op	   66872 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_300-400-12       	       1	   4243833 ns/op	 4577824 B/op	   91741 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_400-500-12       	       1	   4942459 ns/op	 5422520 B/op	  116339 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_500-600-12       	       1	   5507875 ns/op	 5819888 B/op	  140994 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_600-700-12       	       1	   7399458 ns/op	10013768 B/op	  166348 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_700-800-12       	       1	   7444583 ns/op	 8027464 B/op	  191468 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_800-900-12       	       1	   9019875 ns/op	 9070624 B/op	  216584 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_900-1000-12      	       1	   9420417 ns/op	 9062696 B/op	  241273 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1000-1100-12     	       1	  10945875 ns/op	14998976 B/op	  265722 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1100-1200-12     	       1	  11058084 ns/op	 9024888 B/op	  290563 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=100,_Compressor=RealBlindCompressor:_1200-1300-12     	       1	  45556917 ns/op	18058112 B/op	  292206 allocs/op

Reading these results

Notably, adding the first 100 batches is now 40x faster. And adding the 500-600th batches is 90x faster.

Once compression is required, the speed is still ~5x faster, which is likely due to there being fewer layers of buffers to manage in the new Span Channel Out.

We can also turn the batch-count down on the test to see the behavior in a more granular way:

The last 25 batches added develop

BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1270-1275-12   	       1	  51847291 ns/op	 8265208 B/op	   16067 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1275-1280-12   	       1	  52220833 ns/op	 6528112 B/op	   16130 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1280-1285-12   	       1	  52613542 ns/op	 4507440 B/op	   16179 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1285-1290-12   	       1	  52739583 ns/op	 4444296 B/op	   16232 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1290-1295-12   	       1	  31722333 ns/op	 2688704 B/op	    9777 allocs/op

The last 25 batches added this code

BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1270-1275-12   	       1	    634041 ns/op	 4347456 B/op	   16053 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1275-1280-12   	       1	  10728832 ns/op	 3409728 B/op	   16134 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1280-1285-12   	       1	    706166 ns/op	 3458144 B/op	   16188 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1285-1290-12   	       1	    542667 ns/op	 1494936 B/op	   16223 allocs/op
BenchmarkIncremental/Incremental_BatchType=Span,_txPerBatch=1,_BatchCount=5,_Compressor=RealBlindCompressor:_1290-1295-12   	       1	  20678958 ns/op	 1877552 B/op	    9772 allocs/op

You can see that the new compression avoidance keeps runtime low even near the end of the execution, where the old code was consistently doing all the work of compression.

@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch 4 times, most recently from cb3df28 to 58dfa9d Compare April 3, 2024 16:24
@axelKingsley axelKingsley changed the title op-batcher: embedded compressor in Span Channel Out op-batcher: Embed Zlib Compressor into Span Channel Out ; Compression Avoidance Strategy Apr 3, 2024
@axelKingsley axelKingsley marked this pull request as ready for review April 3, 2024 16:25
Copy link
Contributor

coderabbitai bot commented Apr 3, 2024

Walkthrough

Walkthrough

The recent updates focus on enhancing channel and compressor functionalities in a batch processing system. Changes include implementing a factory pattern for dynamic channel creation based on batch types, removing the BlindKind compressor, and introducing new compressors with specific sizes. Testing now covers panic scenarios and integrates real compressors in benchmarks, aiming to improve flexibility, efficiency, and test coverage in managing batches and channels.

Changes

Files Change Summary
.../batcher/channel_builder.go Updated NewChannelBuilder to create channels dynamically based on batch type.
.../batcher/channel_builder_test.go Added ChannelBuilder_OutputWrongFramePanic test with batchType handling.
.../compressor/compressors.go Removed BlindKind compressor and updated compressor kinds map.
.../e2e/actions/l2_batcher.go, .../e2e/actions/sync_test.go Updated compressor usage to NewShadowCompressor and simplified channel output creation.
.../node/benchmarks/batchbuilding_test.go Introduced real compressors for benchmarking and added BenchmarkIncremental.
.../rollup/derive/channel_out.go, .../rollup/derive/channel_out_test.go Revised ChannelOut interface and testing approach, with direct instance handling.
.../rollup/derive/span_channel_out.go Enhanced SpanChannelOut with compression features and methods for batch size constraints.

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share

Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

op-batcher/compressor/blind_compressor.go Outdated Show resolved Hide resolved
op-batcher/compressor/non_compressor.go Outdated Show resolved Hide resolved
op-batcher/compressor/ratio_compressor.go Outdated Show resolved Hide resolved
op-batcher/compressor/shadow_compressor.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/benchmarks/batchbuilding_test.go Outdated Show resolved Hide resolved
op-node/benchmarks/batchbuilding_test.go Outdated Show resolved Hide resolved
op-node/rollup/derive/channel_out.go Outdated Show resolved Hide resolved
@sebastianst sebastianst self-requested a review April 3, 2024 20:00
Copy link
Member

@sebastianst sebastianst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if an additional unit test of the SpanChannelOut would be good that covers both cases:

  • adding block n-1 exits early in the threshold check, so no compression, then adding block n makes it full
  • adding block n-1 doesn't exits early in the threshold check, so compression does happen, which then stays under the threshold, then adding block n makes it full

not sure which case is currently covered.

op-node/rollup/derive/channel_out_test.go Outdated Show resolved Hide resolved
op-node/rollup/derive/channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-batcher/compressor/blind_compressor.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
@ethereum-optimism ethereum-optimism deleted a comment from coderabbitai bot Apr 4, 2024
@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch from 39b7702 to 824510e Compare April 4, 2024 22:19
@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch from 824510e to b251dec Compare April 4, 2024 22:46
@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch from b251dec to fc1e4ce Compare April 4, 2024 23:58
@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch from fc1e4ce to a513927 Compare April 5, 2024 00:25
op-node/rollup/derive/span_channel_out.go Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-node/rollup/derive/span_channel_out.go Outdated Show resolved Hide resolved
op-batcher/batcher/channel_builder.go Outdated Show resolved Hide resolved
op-node/rollup/derive/channel_out_test.go Outdated Show resolved Hide resolved
op-node/rollup/derive/channel_out_test.go Outdated Show resolved Hide resolved
op-node/rollup/derive/channel_out_test.go Show resolved Hide resolved
op-node/rollup/derive/channel_out_test.go Show resolved Hide resolved
op-node/rollup/derive/channel_out_test.go Outdated Show resolved Hide resolved
Copy link
Member

@sebastianst sebastianst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work, thanks ✨🔴

@axelKingsley axelKingsley force-pushed the axel/SpanChannelOutEmbeddedCompressor branch from a24dfe1 to 3fdc30a Compare April 5, 2024 22:44
@axelKingsley axelKingsley added this pull request to the merge queue Apr 8, 2024
Merged via the queue into develop with commit a3cc8f2 Apr 8, 2024
69 checks passed
@axelKingsley axelKingsley deleted the axel/SpanChannelOutEmbeddedCompressor branch April 8, 2024 17:04
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.

None yet

3 participants