[wp-trac] [WordPress Trac] #64538: memoize wp_normalize_path
WordPress Trac
noreply at wordpress.org
Wed Jan 28 06:14:35 UTC 2026
#64538: memoize wp_normalize_path
--------------------------------------+--------------------------
Reporter: josephscott | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: 7.0
Component: General | Version:
Severity: normal | Resolution:
Keywords: has-patch has-unit-tests | Focuses: performance
--------------------------------------+--------------------------
Comment (by dmsnell):
@josephscott this is wonderful — thank you for sharing your benchmark.
with it, I was able to investigate a few more things.
- as noted in the comment above, the `while ()` loop replacing `//`
seemed to be the heaviest bottleneck.
- it seems like all the string processing is indeed the main source of
delay. skipping that, via the cache, is exactly what’s lifting the overall
performance here.
- with a warm JIT, the cacheless optimization with my two changes above
brought it within a little over 2x the runtime of the cached version. the
overall performance of the non-cache version was between 25% and 45%
faster than the original.
I even wondered about the odd `generate_paths()` functions and if we could
have been skewing the results due to pre-computing the string hashes in
`generate_paths()` outside of the timing function. That is, array lookup
is much cheaper if that hash has already been computed. The cached version
was still faster, though the gap was reduced when I moved this into the
benchmark. In order to facilitate this I also precomputed a large list of
paths as a newline-delimited string and had `generate_paths()` randomly
point into that string to grab a line.
you have exhausted all of the cases I can think of, and I wonder how
generally this approach could apply to other Core functions which see the
same strings frequently. there are probably many out there that do, where
a limited cache would serve us better than uncapped or large caches.
----
the one thing I think is worth reflecting on are the cases where a given
path loads before a stream wrapper is registered. there seemed to mostly
be a couple stream wrappers in the plugin directory,
[https://docs.guzzlephp.org/en/5.3/streams.html Guzzle] being one of them.
I foresee the failure scenario being the case that we normalize a path
before the plugin code is activated, and then that path stays in memory.
it does seem low-risk, as one might expect plugin code to run before
processing the rest of the request, so as long as those `require` or
`require_once` statements don’t appear dynamically and on-demand, this
should not misreport the paths. regardless, this is what I believe to be a
bug anyway, so that point will be moot if we fix the bug, as the actual
cached value will then //only// rely on the normalized path and not on
`stream_get_wrappers()`
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64538#comment:18>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list