[PATCH] rtld: cache cpuid results on the stack for intel
Fabian Rast
fabian.rast@tum.de
Thu Jun 4 10:58:02 GMT 2026
On Wed Jun 3, 2026 at 8:38 AM CEST, Sunil Pandey wrote:
> Can you please provide some comments about implementation marked "===>".
>
> diff --git a/sysdeps/x86/dl-cacheinfo.h b/sysdeps/x86/dl-cacheinfo.h
> index d45565b973..05c1faa32e 100644
> --- a/sysdeps/x86/dl-cacheinfo.h
> +++ b/sysdeps/x86/dl-cacheinfo.h
> @@ -162,7 +168,19 @@ intel_check_word (int name, unsigned int value, bool
> *has_level_2,
> unsigned int round = 0;
> while (1)
> {
> - __cpuid_count (4, round, eax, ebx, ecx, edx);
> + if (round < cache->leaf4_valid)
> + eax = cache->leaf4[round][0], ebx = cache->leaf4[round][1],
> + ecx = cache->leaf4[round][2], edx = cache->leaf4[round][3];
> + else if (round == cache->leaf4_valid
> + && round <
> sizeof(cache->leaf4)/sizeof(*cache->leaf4))
> + {
> + __cpuid_count (4, round, eax, ebx, ecx, edx);
> + cache->leaf4[round][0] = eax, cache->leaf4[round][1] =
> ebx;
> + cache->leaf4[round][2] = ecx, cache->leaf4[round][3] =
> edx;
> + cache->leaf4_valid++;
> + }
> + else
> + __cpuid_count (4, round, eax, ebx, ecx, edx);
>
> ===> Please provide comment about each block of logic above.
Ok, I will attempt to explain how this works in detail:
Some background info first:
The `value` passed to intel_check_word is basically an array
of 1 byte "cpuid descriptors".
These are documented in the intel manual
"Table 21-12. Encoding of CPUID Leaf 2 Descriptors" (This table is also present
in the code as `intel_02_known`.)
`intel_check_word` searches through all of the descriptors in `value`
for the specfic property we are interested in, by performing binary search
on the intel_02_known table for each descriptor in the word.
However, cpuid leaf 2 has been superseeded for cache and TLB enumeration
by cpuid leaves 4 and 0x18. This is indicated by the presence of descriptors
0xfe (TLB) and 0xff (cache). The `else if (byte == 0xff)` branch handles this
case and retrieves the cache information from leaf 4 instead.
Maybe it would be clearer if the cpuid leaf 4 enumeration logic
was split into its own function? But that is besides the point.
Now, leaf 4 is documented in the intel manual in
"Table 21-14. Leaf 04H Deterministic Cache Parameters".
Basically, sub leaves should be queried in a loop until
the lowest 5 bits of eax, the "cache type" is zero.
The main problem is that this enumeration of leaf 4 is done
for every `name` that dl_init_cacheinfo is interested in,
instead of extracting all information in one pass.
Changing the enumeration to a single-pass would require bigger
changes to the code.
Instead, this patch caches the cpuid queries from previous calls
to intel_check_word to avoid executing the instruction again.
Now, to explain the blocks of logic above:
`leaf4_valid` is used to track the number of subleaves that
have already been cached, so everything below
leaf4[leaf4_valid] is valid cached data of a previous cpuid call.
This happy case is the first block above: `round < cache->leaf4_valid`
-> the subleaf is cached and we can get the result without executing cpuid
Otherwise we must execute the cpuid instruction.
The `round == cache->leaf4_valid && round < sizeof(cache->leaf4)/sizeof(*cache->leaf4)`
case handles storing the value of the just queried subleaf in the cache.
This can only be done if the subleaf index is smaller than the countof(leaf4)
and all the smaller leaves are already cached.
> @@ -837,7 +848,11 @@ get_common_cache_info (long int *shared_ptr, long int
> * shared_per_thread_ptr, u
> int check = 0x1 | (threads_l3 == 0) << 1;
> do
> {
> - __cpuid_count (4, i++, eax, ebx, ecx, edx);
> + if (cache && i < cache->leaf4_valid)
> + eax = cache->leaf4[i][0], ebx = cache->leaf4[i][1],
> + ecx = cache->leaf4[i][2], edx = cache->leaf4[i++][3];
>
> ===> You may want to increment i in separate statement.
Sure, that might be more readable.
Thanks for looking into this issue!
Is there any new information you could share about why the cpuid instruction
is so slow on the Intel(R) Xeon(R) Gold 6430 specifically?
Demonstrating the problem with that specific processor was the why I sent
this patch in the first place -- for all other processors I tested, the cpu feature
detection code is not problematic, although it still performs redundant cpuid
queries.
Maybe this is naive, but could this issue maybe be fixed through something like
a microcode update for the xeon gold 6430?
Or do you intend to add something similar to this patch to glibc; or
even refactor the feature detection logic on a more fundamental level?
Thanks,
Fabian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 293 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260604/afa9302b/attachment-0001.sig>
More information about the Libc-alpha
mailing list