-
Notifications
You must be signed in to change notification settings - Fork 461
Reworking Headers impl #5396
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
base: main
Are you sure you want to change the base?
Reworking Headers impl #5396
Conversation
7f431f6 to
b94d316
Compare
CodSpeed Performance ReportMerging #5396 will improve performances by 53.4%Comparing Summary
Benchmarks breakdown
Footnotes
|
8191e31 to
7f84859
Compare
|
Internal tests are failing because the refactor changes the ordering of the headers in places... will need to see if we can preserve the order but first want to see if this has a positive impact on performance overall... waiting for benchmark results to be updated. |
21b09a3 to
b59e107
Compare
|
Marking as ready for review but there are still some internal test updates I'll need to do on the internal repo. |
7ac27f1 to
7c52fb0
Compare
| 'headers/headers-errors.any.js': { | ||
| comment: 'Our validation of header names is too lax', | ||
| expectedFailures: [ | ||
| 'Create headers giving bad header name as init argument', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we did end up getting a couple of WPT improvements out of it, nice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, but we'll need to make sure this doesn't count as a breaking change that'll need a compat flag.
|
Whenever this is done I want as many reviewers as we can get on this, incl Harris, Kenton, Mike, Yagiz, etc. |
0a4c8f0 to
7c52fb0
Compare
| other.forEach([this, &js](auto name, auto value) { | ||
| // We have to copy the strings here but we can avoid normalizing and validating since | ||
| // they presumably already went through that process when they were added to the | ||
| // kj::HttpHeader instance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified that kj::HttpHeader is doing validation on these so this should be fine but if we're paranoid enough then we might want to just go ahead and validate here also. Just keep in mind, however, that this constructor is where most of the cost is when creating a Headers for a request.
| for (char c: name) { | ||
| JSG_REQUIRE(HTTP_TOKEN_CHAR_TABLE[static_cast<uint8_t>(c)], TypeError, "Invalid header name."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be speed up if we eliminated the branch inside this for loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a suggested alternative impl?
|
|
||
| inline void requireValidHeaderValue(kj::StringPtr value) { | ||
| for (char c: value) { | ||
| JSG_REQUIRE(isValidHeaderValueChar(c), TypeError, "Invalid header value."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Speed up is possible if we eliminate branches inside this for loop.
In preparation to re-apply Headers performance improvements
Modify the kj::HttpHeaders instead and then construct the api::Headers from that.
While the common header names and indices are defined in the capnp header, they are unlikely to change often (if at all). To avoid the overhead of building the hash map at runtime and performing the hash lookups, we can hardcode the common header names in an array and use direct indexing to retrieve them. Should at least save a handful of CPU cycles.
7c52fb0 to
2e794b4
Compare
Profile is dominated by the cost of constructing the object to serialize rather than the cost of the Response::json_ call itself.
2e794b4 to
fb81688
Compare
|
Note for reviewers: while it likely is possible to get more performance gain with additional tweaks on this, the emphasis for review should be on correctness and ensuring that the revised implementation does not introduce new bugs, etc. We can tweak additional performance knobs separately in follow up PRs. |
| fixture->runInIoContext([&](const TestFixture::Environment& env) { | ||
| auto& js = env.js; | ||
| // Prepare object to serialize. Do this outside the loop to avoid measuring its repeated | ||
| // construction cost. What we want to measure is just the cost of the api::Response::json_ call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you make these changes on a separate pull request? it will help us to generate incorrect outcomes for this pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A separate commit isn't enough?
Needs careful review. It does improve performance but the impl is a bit more complex. Fiddled around with a number of other perf tweaks but nothing that really moved the needle enough to justify the increased complexity. Not entirely sold on this impl so be brutal in reviews.