Skip to content

strcase: inline the raw case conversions - #22672

Closed
ron-kuper wants to merge 1 commit into
curl:masterfrom
ron-kuper:strcase-inline
Closed

ron-kuper wants to merge 1 commit into
curl:masterfrom
ron-kuper:strcase-inline

Conversation

@ron-kuper

@ron-kuper ron-kuper commented Aug 25, 2026

Copy link
Copy Markdown

Curl_raw_toupper() and Curl_raw_tolower() are out-of-line functions whose entire body is one 256-byte table lookup, and casecompare() invokes one of them twice per byte compared. Every case-insensitive comparison in the library (header matching, scheme and host compares, cookie domains) pays two function calls per byte to do work that could be reduced to a single load.

This PR changes them static CURL_INLINE functions in strcase.h and gives the two mapping tables external linkage so the lookup inlines in every translation unit. The tables keep the same bytes and the conversion performs the same mapping, so there is no behavior change: only the linkage of the tables and the placement of the lookup change.

Benchmarking

Benchmarking was done using a harness located in https://github.com/ron-kuper/curlbench. Note that his harness covers more of the library than this patch touches (e.g. printf, URL parsing, transfer lifecycle). I am measuring several other candidate changes with it and expect to propose some of them separately. Only the cases in the table above are relevant to this one.

I ran this benchmark on 2 embedded targets that are of interest to me. The results are as follows.

case Cortex-A55 250MHz e300c3
curl_strequal, identical header names −49.1% −51.7%
curl_strequal, case-folded match −49.1% −51.6%
curl_strequal, late mismatch −49.0% −51.5%
curl_strnequal prefix match −42.9% −54.6%
one response's worth of header dispatch −43.5% −39.8%

There is a margin of error in these results caused by 2 kinds of "noise". Repeat noise is when running the same binary run twice yields a different answer. In our benchmarking it is 0.12% median on the A55 and 0.18% on the e300c3. Recompile noise is when recompiling the same binary but with non-functioning code changes that merely cause addresses to move around. On the e300c3 it moves unrelated cases by up to 8%.

The performance gains on an x86-64 desktop clock in at about −79% to −81% on the compare cases. However on this machine I've observed that recompile noise can vary the outcome by 24-34% it's hard to make an apples-to-apples comparison.

Testing

make -C tests nonflaky-test on this patch alone, built --enable-debug --enable-warnings --with-openssl --with-nghttp2 --with-zlib:
1734 of 1734 OK, no new compiler warnings.
Includes 1397 (Curl_cert_hostcheck, which exercises the case compares), 1395, 1396, 1398, 1399, 1502 and 1506.
scripts/checksrc.pl clean.

AI disclosure

I used an AI assistant on this work: for auditing the call sites, for the codegen and object-size checks quoted above, and for parts of the benchmark harness. The change, the reasoning and the measurements are mine, and I have
verified every claim above myself rather than taking them on trust.

Curl_raw_toupper() and Curl_raw_tolower() were out-of-line functions
doing a single table lookup, and casecompare() invokes one of them twice
per byte compared, so every case-insensitive comparison in the library
paid two calls per byte: header matching, scheme and host compares,
cookie domains.

Make them static CURL_INLINE functions in strcase.h and give the two
mapping tables external linkage so the lookup inlines in every
translation unit without relying on LTO or unity mode. The tables and
the mapping they perform are unchanged, so this is not a behavior
change.

curl_strequal() on identical header names: -49% on a Cortex-A55, -51%
on a 250MHz e300c3.
@ron-kuper
ron-kuper marked this pull request as ready for review August 25, 2026 19:16

@bagder bagder left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice!

Increased performance at a very small cost. A small and non-intrusive change. I like it!

@bagder bagder closed this in bb8ec5e Aug 25, 2026
@bagder

bagder commented Aug 25, 2026

Copy link
Copy Markdown
Member

Thanks!

@ron-kuper
ron-kuper deleted the strcase-inline branch August 27, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants