[PATCH] rtld: cache cpuid results on the stack for intel

Sunil Pandey skpgkp2@gmail.com
Fri Jun 5 03:16:09 GMT 2026


On Thu, Jun 4, 2026 at 3:58 AM Fabian Rast <fabian.rast@tum.de> wrote:

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

Ok.


> Instead, this patch caches the cpuid queries from previous calls
> to intel_check_word to avoid executing the instruction again.
>
>
Ok, put this info as comment in revised patch.


> 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.
>
>
Same as above.


> 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.
>
>
Same as above.


> > @@ -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.
>

Ok.


>
>
> 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?
>
>
Microcode team is looking into this issue. Regardless, this patch is good
as it reduces cpuid calls. Thank you so much for finding and fixing it.


> Thanks,
> Fabian
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260604/e428510c/attachment-0001.htm>


More information about the Libc-alpha mailing list