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

Sunil Pandey skpgkp2@gmail.com
Wed Jun 3 06:38:09 GMT 2026


Hi Fabian,

Can you please provide some comments about implementation marked "===>".

Thanks,
Sunil

 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
@@ -108,6 +108,11 @@ static const struct intel_02_cache_info

 #define nintel_02_known (sizeof (intel_02_known) / sizeof (intel_02_known
[0]))

+struct intel_cpuid_cache {
+  char leaf2_valid, leaf4_valid;
+  unsigned int leaf2[4], leaf4[0x10][4];
+};
+
 static int
 intel_02_known_compare (const void *p1, const void *p2)
 {
@@ -128,7 +133,8 @@ static long int
 __attribute__ ((noinline))
 intel_check_word (int name, unsigned int value, bool *has_level_2,
                  bool *no_level_2_or_3,
-                 const struct cpu_features *cpu_features)
+                 const struct cpu_features *cpu_features,
+                 struct intel_cpuid_cache *cache)
 {
   if ((value & 0x80000000) != 0)
     /* The register value is reserved.  */
@@ -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.

              enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax &
0x1f;
              if (type == null)
@@ -258,7 +276,8 @@ intel_check_word (int name, unsigned int value, bool
*has_level_2,


 static long int __attribute__ ((noinline))
-handle_intel (int name, const struct cpu_features *cpu_features)
+handle_intel (int name, const struct cpu_features *cpu_features,
+             struct intel_cpuid_cache *cache)
 {
   unsigned int maxidx = cpu_features->basic.max_cpuid;

@@ -271,41 +290,33 @@ handle_intel (int name, const struct cpu_features
*cpu_features)
   long int result = 0;
   bool no_level_2_or_3 = false;
   bool has_level_2 = false;
-  unsigned int eax;
-  unsigned int ebx;
-  unsigned int ecx;
-  unsigned int edx;
-  __cpuid (2, eax, ebx, ecx, edx);
+  int i;
+
+  if (!cache->leaf2_valid)
+    {
+      __cpuid (2, cache->leaf2[0], cache->leaf2[1],
+                 cache->leaf2[2], cache->leaf2[3]);
+      cache->leaf2_valid = 1;
+    }

   /* The low byte of EAX of CPUID leaf 2 should always return 1 and it
      should be ignored.  If it isn't 1, use CPUID leaf 4 instead.  */
-  if ((eax & 0xff) != 1)
+  if ((cache->leaf2[0] & 0xff) != 1)
     return intel_check_word (name, 0xff, &has_level_2, &no_level_2_or_3,
-                            cpu_features);
-  else
-    {
-      eax &= 0xffffff00;
+                            cpu_features, cache);

-      /* Process the individual registers' value.  */
-      result = intel_check_word (name, eax, &has_level_2,
-                                &no_level_2_or_3, cpu_features);
-      if (result != 0)
-       return result;
-
-      result = intel_check_word (name, ebx, &has_level_2,
-                                &no_level_2_or_3, cpu_features);
-      if (result != 0)
-       return result;
+  /* Process all descriptors in leaf 2. */
+  result = intel_check_word (name, cache->leaf2[0]>>8, &has_level_2,
+                           &no_level_2_or_3, cpu_features, cache);
+  if (result != 0)
+    return result;

-      result = intel_check_word (name, ecx, &has_level_2,
-                                &no_level_2_or_3, cpu_features);
-      if (result != 0)
-       return result;
-
-      result = intel_check_word (name, edx, &has_level_2,
-                                &no_level_2_or_3, cpu_features);
+  for (i = 1; i < 4; i++)
+    {
+      result = intel_check_word (name, cache->leaf2[i], &has_level_2,
+                               &no_level_2_or_3, cpu_features, cache);
       if (result != 0)
-       return result;
+        return result;
     }

   if (name >= _SC_LEVEL2_CACHE_SIZE && name <= _SC_LEVEL3_CACHE_LINESIZE
@@ -779,7 +790,7 @@ handle_hygon (int name)

 static void
 get_common_cache_info (long int *shared_ptr, long int *
shared_per_thread_ptr, unsigned int *threads_ptr,
-                long int core)
+                long int core, struct intel_cpuid_cache *cache)
 {
   unsigned int eax;
   unsigned int ebx;
@@ -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.

+              else
+                __cpuid_count (4, i++, eax, ebx, ecx, edx);

               /* There seems to be a bug in at least some Pentium Ds
                  which sometimes fail to iterate all cache parameters.
@@ -1017,35 +1032,38 @@ dl_init_cacheinfo (struct cpu_features
*cpu_features)

   if (cpu_features->basic.kind == arch_kind_intel)
     {
-      data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features);
-      shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features);
+      struct intel_cpuid_cache cache;
+      cache.leaf2_valid = cache.leaf4_valid = 0;
+
+      data = handle_intel (_SC_LEVEL1_DCACHE_SIZE, cpu_features, &cache);
+      shared = handle_intel (_SC_LEVEL3_CACHE_SIZE, cpu_features, &cache);
       shared_per_thread = shared;

       level1_icache_size
-       = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features);
+       = handle_intel (_SC_LEVEL1_ICACHE_SIZE, cpu_features, &cache);
       level1_icache_linesize
-       = handle_intel (_SC_LEVEL1_ICACHE_LINESIZE, cpu_features);
+       = handle_intel (_SC_LEVEL1_ICACHE_LINESIZE, cpu_features, &cache);
       level1_dcache_size = data;
       level1_dcache_assoc
-       = handle_intel (_SC_LEVEL1_DCACHE_ASSOC, cpu_features);
+       = handle_intel (_SC_LEVEL1_DCACHE_ASSOC, cpu_features, &cache);
       level1_dcache_linesize
-       = handle_intel (_SC_LEVEL1_DCACHE_LINESIZE, cpu_features);
+       = handle_intel (_SC_LEVEL1_DCACHE_LINESIZE, cpu_features, &cache);
       level2_cache_size
-       = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features);
+       = handle_intel (_SC_LEVEL2_CACHE_SIZE, cpu_features, &cache);
       level2_cache_assoc
-       = handle_intel (_SC_LEVEL2_CACHE_ASSOC, cpu_features);
+       = handle_intel (_SC_LEVEL2_CACHE_ASSOC, cpu_features, &cache);
       level2_cache_linesize
-       = handle_intel (_SC_LEVEL2_CACHE_LINESIZE, cpu_features);
+       = handle_intel (_SC_LEVEL2_CACHE_LINESIZE, cpu_features, &cache);
       level3_cache_size = shared;
       level3_cache_assoc
-       = handle_intel (_SC_LEVEL3_CACHE_ASSOC, cpu_features);
+       = handle_intel (_SC_LEVEL3_CACHE_ASSOC, cpu_features, &cache);
       level3_cache_linesize
-       = handle_intel (_SC_LEVEL3_CACHE_LINESIZE, cpu_features);
+       = handle_intel (_SC_LEVEL3_CACHE_LINESIZE, cpu_features, &cache);
       level4_cache_size
-       = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features);
+       = handle_intel (_SC_LEVEL4_CACHE_SIZE, cpu_features, &cache);

       get_common_cache_info (&shared, &shared_per_thread, &threads,
-                            level2_cache_size);
+                            level2_cache_size, &cache);
     }
   else if (cpu_features->basic.kind == arch_kind_zhaoxin)
     {
@@ -1066,7 +1084,7 @@ dl_init_cacheinfo (struct cpu_features *cpu_features)
       level3_cache_linesize = handle_zhaoxin (_SC_LEVEL3_CACHE_LINESIZE);

       get_common_cache_info (&shared, &shared_per_thread, &threads,
-                            level2_cache_size);
+                            level2_cache_size, NULL);
     }
   else if (cpu_features->basic.kind == arch_kind_amd)
     {

On Tue, May 19, 2026 at 1:02 AM Fabian Rast <fabian.rast@tum.de> wrote:

> On Mon May 18, 2026 at 9:00 PM CEST, Sunil Pandey wrote:
> > Can you please rebase and send you patch as attachment.
>
> Patch is attached. I also fixed a typo in `intel_check_word`
> that was in the previous patch (edx -> ecx).
>
> Best Regards,
> Fabian
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260602/b9f16f96/attachment-0001.htm>


More information about the Libc-alpha mailing list