bryancall commented on PR #13376:
URL: https://github.com/apache/trafficserver/pull/13376#issuecomment-5770522820

   ## Benchmark: base vs head, measured
   
   Separate from my review, here are A/B numbers for this PR. Posting them 
because the change is 70 days old and a measured result is more useful than 
another opinion.
   
   ### How the arms were built
   
   The benchmark source only exists on this branch, so comparing head's 
benchmark against anything else risks measuring the harness rather than the 
parser. Both arms therefore carry **byte-identical benchmark source** and 
differ only in `src/proxy/hdrs`:
   
   - **BASE** = merge-base `9c69fe1bcc` plus one commit that is `git checkout 
pr13376 -- tools/benchmark/benchmark_HdrParse.cc 
tools/benchmark/CMakeLists.txt`. The **head** version of those files was taken 
deliberately, not the version from `b00bdec54`, because `ccc437f95` later 
rewrote the `--iters` argv parsing.
   - **HEAD** = `7e9255ff4` as-is.
   
   ```
   $ git diff --stat 9c69fe1bcc..base-with-bench
    tools/benchmark/CMakeLists.txt        |   6 +
    tools/benchmark/benchmark_HdrParse.cc | 813 +++++++++++++++++++++
    2 files changed, 819 insertions(+)
   
   $ git diff --stat 9c69fe1bcc..base-with-bench -- src/proxy/hdrs/ 
include/proxy/hdrs/
   (empty)
   
   $ git diff --stat base-with-bench pr13376 -- tools/benchmark/
   (empty)
   ```
   
   Build and invocation, so this is repeatable:
   
   ```
   cmake --preset release -DENABLE_BENCHMARKS=ON 
-DBUILD_EXPERIMENTAL_PLUGINS=OFF
   cmake --build build-release --target benchmark_HdrParse -j 28
   
   taskset -c 4 ./build-release/tools/benchmark/benchmark_HdrParse "[bench]" \
       --benchmark-samples 200 --order decl --rng-seed 1 --reporter xml
   ```
   
   GCC 16.2.1, `CMAKE_CXX_FLAGS_RELEASE=-O3 -DNDEBUG`, no sanitizers, both arms 
clean with zero warnings. Pinned to one core, fixed order and RNG seed, **7 
rounds strictly interleaved base/head/base/head**. Load average during the runs 
was 1.0 to 1.1, which is essentially just the pinned process.
   
   ### Results, ns/op, median of 7 interleaved runs
   
   | case | base | head | delta | worst-arm spread |
   |---|---:|---:|---:|---:|
   | url: realistic | 217.38 | 51.66 | **-76.2%** | 13.6% |
   | response: 50 dup fields | 2546.03 | 1558.11 | **-38.8%** | 3.0% |
   | request: realistic (zero-copy) | 367.62 | 322.17 | **-12.4%** | 3.1% |
   | request: realistic (copy) | 449.94 | 403.36 | **-10.3%** | 2.9% |
   | request: modern browser (zero-copy) | 643.86 | 593.93 | **-7.8%** | 5.9% |
   | mime: 50 wks-miss fields | 4142.33 | 3907.70 | -5.7% | 15.7% |
   | request: 100 fields | 12344.90 | 12071.50 | -2.2% | 9.0% |
   | response: realistic | 320.85 | 316.54 | -1.3% | 5.5% |
   | mime: realistic fields | 295.04 | 291.39 | -1.2% | 3.9% |
   | wks: tokenize all field names | 2124.73 | 2146.28 | **+1.0%** | 0.7% |
   | wks: tokenize, lowercased (H2) | 2124.30 | 2147.43 | **+1.1%** | 0.8% |
   
   Per-run figures for the cases that carry the result, so you can judge the 
spread yourself:
   
   - **url: realistic** base `191.2 192.9 194.6 217.4 218.9 220.5 220.7`, head 
`50.6 51.2 51.5 51.7 52.0 53.0 53.1`. Base is visibly bimodal, two clusters 
about 14% apart, which I did not chase down. Even against base's *fastest* 
cluster the head is about 73% faster.
   - **response: 50 dup fields** base `2509 2519 2530 2546 2549 2549 2585`, 
head `1551 1554 1556 1558 1561 1561 1578`. No overlap at all.
   - **request: realistic (zero-copy)** base `362.3 to 373.8`, head `317.4 to 
325.7`. No overlap.
   - **request: modern browser** base min 625.2 is above head max 603.6, so 
despite base's 5.9% spread the distributions do not overlap.
   - **mime: 50 wks-miss fields** base had one outlier run at 4654.9 inflating 
the spread. Excluding it: base 4006 to 4252, head 3848 to 4028. The win is 
likely real but I would not quote a precise figure.
   
   The three cases the PR does not touch move 1 to 2%, which is inside noise. 
That is the control you want to see.
   
   ### One measured regression
   
   The standalone WKS tokenize entry point is consistently **slower**. Since 1% 
is close to noise, those two cases were re-run alone, 10 interleaved rounds 
each, 300 samples, on a different core:
   
   ```
   taskset -c 6 ./benchmark_HdrParse "[wks]" --benchmark-samples 300 --order 
decl --rng-seed 1 --reporter xml
   ```
   
   - `wks: tokenize all field names` base median 2129.24 (2127.1 to 2137.8), 
head median 2153.07 (2143.1 to 2157.6), **+1.12%, zero distribution overlap**
   - `wks: tokenize, lowercased (H2 form)` base median 2129.38 (2125.2 to 
2137.0), head median 2153.78 (2152.1 to 2179.7), **+1.15%, zero distribution 
overlap**
   
   So: a reproducible ~1.1% slowdown on standalone `hdrtoken_tokenize`, across 
20 interleaved rounds on two different cores with no overlap between arms. 
**Inferred rather than measured:** this is most likely the fused scan-and-hash 
trading standalone tokenize cost for the fused parse path, which would be 
consistent with the large wins on exactly the cases that go through that path. 
I did not profile to confirm the attribution, so treat the cause as a 
hypothesis and the effect as measured.
   
   It is dwarfed by the wins and I am not asking for anything about it. It is 
worth knowing it exists.
   
   ### Unit tests, Release build, head arm
   
   `test_proxy_hdrs` passes: **457,223 assertions in 62 test cases**. Base for 
reference: 456,999 assertions in 57 cases, so this PR adds 5 cases.
   
   ### What these numbers do not support
   
   - **Real-world impact.** This is a microbenchmark of `src/proxy/hdrs` in 
isolation. It says nothing about what fraction of a real transaction is header 
parsing. No h2load or end-to-end proxy run was done.
   - **Per-commit attribution.** Base against head only, not bisected. The URL 
and dup-field attributions above are inferred from reading the diffs.
   - **Other compilers.** GCC 16.2.1 only. The URL win depends on the compiler 
auto-vectorizing the new branchless loop, so clang or an older GCC could differ 
in magnitude. Your comment claims both clang and GCC vectorize at `-O3`; I 
verified the GCC half by measurement rather than by reading the generated 
assembly, and separately confirmed the clang half by compiling the loop 
standalone at `-O3` for arm64 and x86-64, where `-Rpass=loop-vectorize` reports 
vectorization width 16 in both.
   - **Loaded behavior.** Single pinned core, single threaded, no cache or 
memory-bandwidth pressure.
   


-- 
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]

Reply via email to