Skip to content

Add option to disable HPACK dynamic table - #12973

Open
petedmarsh wants to merge 2 commits into
grpc:masterfrom
petedmarsh:disable-dynamic-hpack
Open

Add option to disable HPACK dynamic table#12973
petedmarsh wants to merge 2 commits into
grpc:masterfrom
petedmarsh:disable-dynamic-hpack

Conversation

@petedmarsh

Copy link
Copy Markdown

Add disableHpackDynamicTable() to the Netty client and server builders.

When enabled, Netty uses a zero-sized HPACK dynamic table and advertises SETTINGS_HEADER_TABLE_SIZE = 0 to its peer. The default remains unchanged.

Also fix grpc-okhttp to apply a peer's header-table setting to its outbound encoder instead of its inbound decoder.

Compliant peers require no configuration changes. Older grpc-okhttp releases must be upgraded before enabling this option on their Netty peer.

OpenAI Codex (GPT-5) was used to implement all changes in this PR.

Add client and server builder controls that disable HPACK dynamic table use
in both directions. Advertise a zero header table size and keep the encoder
table pinned at zero when the peer changes its setting.

Add encoder, handler, builder, transport, and interoperability coverage.

AI assistance: OpenAI Codex (GPT-5) was used to review these HPACK changes
and strengthen the tests.
Apply SETTINGS_HEADER_TABLE_SIZE to the outbound HPACK writer before
acknowledging it, so the next header block emits the required dynamic table
size update. Stop applying the peer encoder setting to the inbound decoder.

Add framed unit coverage and bidirectional OkHttp-Netty regression tests.
The tests verify that repeated calls remain on one transport.

AI assistance: OpenAI Codex (GPT-5) was used to implement and test this
grpc-okhttp compatibility fix.
@linux-foundation-easycla

linux-foundation-easycla Bot commented Aug 6, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@petedmarsh petedmarsh changed the title Disable dynamic hpack Add option to disable HPACK dynamic table Aug 6, 2026
@ejona86

ejona86 commented Aug 6, 2026

Copy link
Copy Markdown
Member

Can you describe what your goal is? It seems like it is to reduce idle memory usage?

The okhttp bug has been on our radar, but needed some further investigation (#12819 . #12818 is similar but I saw it didn't remove hpackReader.headerTableSizeSetting(), so it was highly suspect; it was also AI-generated, and we really want a human to look at it). We will definitely want to keep any changes there as a separate commit.

@petedmarsh

petedmarsh commented Aug 6, 2026 via email

Copy link
Copy Markdown
Author

@ejona86

ejona86 commented Aug 6, 2026

Copy link
Copy Markdown
Member

Can you share what function(s) is hot? Is it the key/value hashing?

Receiving indexed values in HPACK seems reasonably cheap. I expect it is just the encoder costing you.

One thing for us to consider is this approach looks to be incompatible with Http2FrameCodecBuilder. We really need to migrate off the old Netty API that we are using, at which point we'll be limited to what Http2FrameCodecBuilder offers. (So then we have to either drop this feature or upstream it to Netty.)

@petedmarsh

Copy link
Copy Markdown
Author

We have quite a significant amount of headers (a lot of individual headers, some with high cardinality, and some with high cardinality and size of value), we've observed via production profiling that this is actually casuing signficiant CPU usage.

Here's a benchmark:

https://github.com/petedmarsh/grpc-java/tree/disable-dynamic-hpack-benchmark

## Direct change when disabling the table

Positive throughput is better; negative bytes and CPU are better.

| Value profile | Throughput | Modeled bytes | Process CPU |
| --- | ---: | ---: | ---: |
| Low length | +98.275% | +102.576% | -49.069% |
| High length | +18.114% | +19.040% | -15.381% |

The direct encoder results show statistically resolved CPU and throughput improvements, accompanied
by statistically resolved increases in encoded bytes.

## End-to-end unary gRPC

| Value profile | Dynamic table | Throughput (RPC/s) | Client bytes/RPC | Process CPU (us/RPC) |
| --- | --- | ---: | ---: | ---: |
| Low length | 4 KiB | 24,807.936 +/- 4,357.322 | 350.793 +/- 0.004 | 36.032 +/- 7.189 |
| Low length | Disabled | 25,666.263 +/- 983.054 | 717.585 +/- 0.002 | 34.700 +/- 1.669 |
| High length | 4 KiB | 24,187.775 +/- 1,832.197 | 1,524.586 +/- 0.004 | 36.926 +/- 2.476 |
| High length | Disabled | 25,873.456 +/- 3,399.571 | 1,803.585 +/- 0.002 | 34.459 +/- 4.809 |

### End-to-end change when disabling the table

| Value profile | Throughput | Client bytes | Process CPU |
| --- | ---: | ---: | ---: |
| Low length | +3.460% | +104.561% | -3.697% |
| High length | +6.969% | +18.300% | -6.681% |

The end-to-end CPU and throughput confidence intervals overlap, so those observed changes are not
statistically resolved by this run. The client-byte increases are resolved.

(Benchmark also generated with Open AI / Codex / Sol 5)

@petedmarsh

Copy link
Copy Markdown
Author

I'm also happy to change this to make the HPACK dynamic table size configurable, rather than just disable-able, in some cases bigger tables might be better.

I also know that AI generated contributions are slightly suspect, but I am confident in the analysis from our production profiling and that the benchmark is at least somewhat representative. This PR itself I am not too concernred about but I would like this functionality in grpc-java (as well as the never index changes in my other pr #12976) if someone has to re-do by hand.

If AI generated code is not an issue then I am happy to adjut - cheers!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants