pjfanning opened a new pull request, #1226:
URL: https://github.com/apache/pekko-http/pull/1226

   ### Motivation
   `LineParser` scanned its buffer one byte at a time:
   
   ```scala
   bs(at) match {
     case CR_BYTE if at < bs.length - 1 && bs(at + 1) == LF_BYTE => ...
   ```
   
   The buffer is built as `buffer ++ grab(in)`, so it is a multi-fragment 
`ByteString` whenever a line spans more than one chunk. 
`ByteString$ByteStrings.apply` has no offset index or position cache - it walks 
the fragment vector from the first fragment on every access - so scanning an 
SSE line that arrives in N chunks costs O(bytes × N).
   
   `ByteString.indexOf(byte, from)` is the opposite: it walks fragments once 
and, inside a fragment, uses `SWARUtil` to test 8 bytes per step.
   
   ### Modification
   Jump to the next CR or LF with `indexOf` instead of testing every byte. The 
three identical line-emitting blocks are factored into a local `lineAt` helper.
   
   Line termination semantics are unchanged - CR, LF, CRLF, a lone CR followed 
by a non-LF byte, and a CRLF split across two chunks (the `lastCharWasCr` flag) 
all behave exactly as before. The oversized-line handling (`maxLineSize` and 
every `OversizedSseStrategy`) is untouched, just moved into the helper.
   
   ### Result
   `LineParserBenchmark`, JDK 21, `-f 1 -wi 3 -i 3`:
   
   | lineSize | chunkSize | before | after | |
   |---|---|---|---|---|
   | 1 KB | 512 | 0.265 ms/op | 0.189 ms/op | within noise |
   | 1 KB | 8192 | 0.295 ms/op | 0.183 ms/op | within noise |
   | 128 KB | 512 | 71.210 ms/op | 1.013 ms/op | ~70x |
   | 128 KB | 8192 | 3.269 ms/op | 0.342 ms/op | ~10x |
   | 1 MB | 512 | 9821.281 ms/op | 54.361 ms/op | ~180x |
   
   Small lines are unaffected; the gain scales with how many chunks a line is 
split across, which is exactly the shape of a real SSE stream over a network.
   
   Note this is independent of the pending pekko-core change that gives 
`ByteStrings.apply` a fragment hint. That hint helps monotonic forward scans, 
but `indexOf` still avoids one virtual call per byte and tests 8 bytes at a 
time, and this change also benefits the 1.x line, which is pinned to pekko 
1.1.5.
   
   ### Tests
   - `sbt "http-tests / Test / testOnly 
org.apache.pekko.http.scaladsl.unmarshalling.sse.*"` - 48 passed (46 existing, 
plus 2 new in `LineParserSpec`: a CRLF split across two chunks, and lines 
parsed out of an explicitly multi-fragment `ByteString`, asserted non-compact 
so the test really covers the rope path).
   - `sbt "http-bench-jmh/Jmh/run …"` - numbers above, measured before and 
after on the same machine.
   - `scalafmt --mode diff-ref=upstream/main` - clean.
   
   ### References
   None - found while auditing ByteString usage across the code base


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to