LCOV - code coverage report
Current view: top level - vppinfra - cpu.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 50 60 83.3 %
Date: 2023-07-05 22:20:52 Functions: 28 41 68.3 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #ifndef included_clib_cpu_h
      17             : #define included_clib_cpu_h
      18             : 
      19             : #include <sys/syscall.h>
      20             : #include <vppinfra/format.h>
      21             : 
      22             : #if defined(__x86_64__)
      23             : #define foreach_march_variant                                                 \
      24             :   _ (scalar, "Generic (SIMD disabled)")                                       \
      25             :   _ (hsw, "Intel Haswell")                                                    \
      26             :   _ (trm, "Intel Tremont")                                                    \
      27             :   _ (skx, "Intel Skylake (server) / Cascade Lake")                            \
      28             :   _ (icl, "Intel Ice Lake")                                                   \
      29             :   _ (adl, "Intel Alder Lake")                                                 \
      30             :   _ (spr, "Intel Sapphire Rapids")                                            \
      31             :   _ (znver3, "AMD Milan")                                                     \
      32             :   _ (znver4, "AMD Genoa")
      33             : #elif defined(__aarch64__)
      34             : #define foreach_march_variant                                                 \
      35             :   _ (octeontx2, "Marvell Octeon TX2")                                         \
      36             :   _ (thunderx2t99, "Marvell ThunderX2 T99")                                   \
      37             :   _ (qdf24xx, "Qualcomm CentriqTM 2400")                                      \
      38             :   _ (cortexa72, "ARM Cortex-A72")                                             \
      39             :   _ (neoversen1, "ARM Neoverse N1")
      40             : #else
      41             : #define foreach_march_variant
      42             : #endif
      43             : 
      44             : #define amd_vendor(t1, t2, t3)                                                \
      45             :   ((t1 == 0x68747541) && /* htuA */                                           \
      46             :    (t2 == 0x444d4163) && /* DMAc */                                           \
      47             :    (t3 == 0x69746e65))   /* itne */
      48             : typedef enum
      49             : {
      50             :   CLIB_MARCH_VARIANT_TYPE = 0,
      51             : #define _(s, n) CLIB_MARCH_VARIANT_TYPE_##s,
      52             :   foreach_march_variant
      53             : #undef _
      54             :     CLIB_MARCH_TYPE_N_VARIANTS
      55             : } clib_march_variant_type_t;
      56             : 
      57             : #ifdef CLIB_MARCH_VARIANT
      58             : #define __CLIB_MULTIARCH_FN(a,b) a##_##b
      59             : #define _CLIB_MULTIARCH_FN(a,b) __CLIB_MULTIARCH_FN(a,b)
      60             : #define CLIB_MULTIARCH_FN(fn) _CLIB_MULTIARCH_FN(fn,CLIB_MARCH_VARIANT)
      61             : #else
      62             : #define CLIB_MULTIARCH_FN(fn) fn
      63             : #endif
      64             : 
      65             : #define CLIB_MARCH_SFX CLIB_MULTIARCH_FN
      66             : 
      67             : typedef struct _clib_march_fn_registration
      68             : {
      69             :   void *function;
      70             :   int priority;
      71             :   struct _clib_march_fn_registration *next;
      72             :   char *name;
      73             : } clib_march_fn_registration;
      74             : 
      75             : static_always_inline void *
      76       24602 : clib_march_select_fn_ptr (clib_march_fn_registration * r)
      77             : {
      78       24602 :   void *rv = 0;
      79       24602 :   int last_prio = -1;
      80             : 
      81      123010 :   while (r)
      82             :     {
      83       98408 :       if (last_prio < r->priority)
      84             :         {
      85       24602 :           last_prio = r->priority;
      86       24602 :           rv = r->function;
      87             :         }
      88       98408 :       r = r->next;
      89             :     }
      90       24602 :   return rv;
      91             : }
      92             : 
      93             : #define CLIB_MARCH_FN_POINTER(fn)                                             \
      94             :   (__typeof__ (fn) *) clib_march_select_fn_ptr (fn##_march_fn_registrations);
      95             : 
      96             : #define CLIB_MARCH_FN_VOID_POINTER(fn)                                        \
      97             :   clib_march_select_fn_ptr (fn##_march_fn_registrations);
      98             : 
      99             : #define _CLIB_MARCH_FN_REGISTRATION(fn) \
     100             : static clib_march_fn_registration \
     101             : CLIB_MARCH_SFX(fn##_march_fn_registration) = \
     102             : { \
     103             :   .name = CLIB_MARCH_VARIANT_STR \
     104             : }; \
     105             : \
     106             : static void __clib_constructor \
     107             : fn##_march_register () \
     108             : { \
     109             :   clib_march_fn_registration *r; \
     110             :   r = & CLIB_MARCH_SFX (fn##_march_fn_registration); \
     111             :   r->priority = CLIB_MARCH_FN_PRIORITY(); \
     112             :   r->next = fn##_march_fn_registrations; \
     113             :   r->function = CLIB_MARCH_SFX (fn); \
     114             :   fn##_march_fn_registrations = r; \
     115             : }
     116             : 
     117             : #ifdef CLIB_MARCH_VARIANT
     118             : #define CLIB_MARCH_FN_REGISTRATION(fn) \
     119             : extern clib_march_fn_registration *fn##_march_fn_registrations; \
     120             : _CLIB_MARCH_FN_REGISTRATION(fn)
     121             : #else
     122             : #define CLIB_MARCH_FN_REGISTRATION(fn) \
     123             : clib_march_fn_registration *fn##_march_fn_registrations = 0; \
     124             : _CLIB_MARCH_FN_REGISTRATION(fn)
     125             : #endif
     126             : #define foreach_x86_64_flags                                                  \
     127             :   _ (sse3, 1, ecx, 0)                                                         \
     128             :   _ (pclmulqdq, 1, ecx, 1)                                                    \
     129             :   _ (ssse3, 1, ecx, 9)                                                        \
     130             :   _ (sse41, 1, ecx, 19)                                                       \
     131             :   _ (sse42, 1, ecx, 20)                                                       \
     132             :   _ (avx, 1, ecx, 28)                                                         \
     133             :   _ (rdrand, 1, ecx, 30)                                                      \
     134             :   _ (avx2, 7, ebx, 5)                                                         \
     135             :   _ (bmi2, 7, ebx, 8)                                                         \
     136             :   _ (rtm, 7, ebx, 11)                                                         \
     137             :   _ (pqm, 7, ebx, 12)                                                         \
     138             :   _ (pqe, 7, ebx, 15)                                                         \
     139             :   _ (avx512f, 7, ebx, 16)                                                     \
     140             :   _ (rdseed, 7, ebx, 18)                                                      \
     141             :   _ (x86_aes, 1, ecx, 25)                                                     \
     142             :   _ (sha, 7, ebx, 29)                                                         \
     143             :   _ (vaes, 7, ecx, 9)                                                         \
     144             :   _ (vpclmulqdq, 7, ecx, 10)                                                  \
     145             :   _ (avx512_vnni, 7, ecx, 11)                                                 \
     146             :   _ (avx512_bitalg, 7, ecx, 12)                                               \
     147             :   _ (avx512_vpopcntdq, 7, ecx, 14)                                            \
     148             :   _ (movdiri, 7, ecx, 27)                                                     \
     149             :   _ (movdir64b, 7, ecx, 28)                                                   \
     150             :   _ (enqcmd, 7, ecx, 29)                                                      \
     151             :   _ (avx512_fp16, 7, edx, 23)                                                 \
     152             :   _ (invariant_tsc, 0x80000007, edx, 8)                                       \
     153             :   _ (monitorx, 0x80000001, ecx, 29)
     154             : 
     155             : #define foreach_aarch64_flags \
     156             : _ (fp,          0) \
     157             : _ (asimd,       1) \
     158             : _ (evtstrm,     2) \
     159             : _ (aarch64_aes, 3) \
     160             : _ (pmull,       4) \
     161             : _ (sha1,        5) \
     162             : _ (sha2,        6) \
     163             : _ (crc32,       7) \
     164             : _ (atomics,     8) \
     165             : _ (fphp,        9) \
     166             : _ (asimdhp,    10) \
     167             : _ (cpuid,      11) \
     168             : _ (asimdrdm,   12) \
     169             : _ (jscvt,      13) \
     170             : _ (fcma,       14) \
     171             : _ (lrcpc,      15) \
     172             : _ (dcpop,      16) \
     173             : _ (sha3,       17) \
     174             : _ (sm3,        18) \
     175             : _ (sm4,        19) \
     176             : _ (asimddp,    20) \
     177             : _ (sha512,     21) \
     178             : _ (sve,        22)
     179             : 
     180             : u32 clib_get_current_cpu_id (void);
     181             : u32 clib_get_current_numa_node (void);
     182             : 
     183             : typedef int (*clib_cpu_supports_func_t) (void);
     184             : 
     185             : #if defined(__x86_64__)
     186             : #include "cpuid.h"
     187             : 
     188             : static inline int
     189       60024 : clib_get_cpuid (const u32 lev, u32 * eax, u32 * ebx, u32 * ecx, u32 * edx)
     190             : {
     191       60024 :   if ((u32) __get_cpuid_max (0x80000000 & lev, 0) < lev)
     192           0 :     return 0;
     193       60030 :   if (lev == 7)
     194       40972 :     __cpuid_count (lev, 0, *eax, *ebx, *ecx, *edx);
     195             :   else
     196       19058 :     __cpuid (lev, *eax, *ebx, *ecx, *edx);
     197       60032 :   return 1;
     198             : }
     199             : 
     200             : #define _(flag, func, reg, bit) \
     201             : static inline int                                                       \
     202             : clib_cpu_supports_ ## flag()                                            \
     203             : {                                                                       \
     204             :   u32 __attribute__((unused)) eax, ebx = 0, ecx = 0, edx  = 0;          \
     205             :   clib_get_cpuid (func, &eax, &ebx, &ecx, &edx);                        \
     206             :                                                                         \
     207             :   return ((reg & (1 << bit)) != 0);                                   \
     208             : }
     209       45444 : foreach_x86_64_flags
     210             : #undef _
     211             : #else /* __x86_64__ */
     212             : 
     213             : #define _(flag, func, reg, bit) \
     214             : static inline int clib_cpu_supports_ ## flag() { return 0; }
     215             : foreach_x86_64_flags
     216             : #undef _
     217             : #endif /* __x86_64__ */
     218             : #if defined(__aarch64__)
     219             : #include <sys/auxv.h>
     220             : #define _(flag, bit) \
     221             : static inline int                                                       \
     222             : clib_cpu_supports_ ## flag()                                            \
     223             : {                                                                       \
     224             :   unsigned long hwcap = getauxval(AT_HWCAP);                            \
     225             :   return (hwcap & (1 << bit));                                                \
     226             : }
     227             :   foreach_aarch64_flags
     228             : #undef _
     229             : #else /* ! __x86_64__ && !__aarch64__ */
     230             : #define _(flag, bit) \
     231             : static inline int clib_cpu_supports_ ## flag() { return 0; }
     232           0 :   foreach_aarch64_flags
     233             : #undef _
     234             : #endif /* __x86_64__, __aarch64__ */
     235             : /*
     236             :  * aes is the only feature with the same name in both flag lists
     237             :  * handle this by prefixing it with the arch name, and handling it
     238             :  * with the custom function below
     239             :  */
     240             :   static inline int
     241         559 : clib_cpu_supports_aes ()
     242             : {
     243             : #if defined(__x86_64__)
     244         559 :   return clib_cpu_supports_x86_aes ();
     245             : #elif defined (__aarch64__)
     246             :   return clib_cpu_supports_aarch64_aes ();
     247             : #else
     248             :   return 0;
     249             : #endif
     250             : }
     251             : 
     252             : static inline int
     253         559 : clib_cpu_march_priority_scalar ()
     254             : {
     255         559 :   return 1;
     256             : }
     257             : 
     258             : static inline int
     259         559 : clib_cpu_march_priority_spr ()
     260             : {
     261         559 :   if (clib_cpu_supports_enqcmd ())
     262           0 :     return 300;
     263         559 :   return -1;
     264             : }
     265             : 
     266             : static inline int
     267        7401 : clib_cpu_march_priority_icl ()
     268             : {
     269        7401 :   if (clib_cpu_supports_avx512_bitalg ())
     270           0 :     return 200;
     271        7401 :   return -1;
     272             : }
     273             : 
     274             : static inline int
     275         559 : clib_cpu_march_priority_adl ()
     276             : {
     277         559 :   if (clib_cpu_supports_movdiri () && clib_cpu_supports_avx2 ())
     278           0 :     return 150;
     279         559 :   return -1;
     280             : }
     281             : 
     282             : static inline int
     283        9771 : clib_cpu_march_priority_skx ()
     284             : {
     285        9771 :   if (clib_cpu_supports_avx512f ())
     286        9771 :     return 100;
     287           0 :   return -1;
     288             : }
     289             : 
     290             : static inline int
     291         559 : clib_cpu_march_priority_trm ()
     292             : {
     293         559 :   if (clib_cpu_supports_movdiri ())
     294           0 :     return 40;
     295         559 :   return -1;
     296             : }
     297             : 
     298             : static inline int
     299        9771 : clib_cpu_march_priority_hsw ()
     300             : {
     301        9771 :   if (clib_cpu_supports_avx2 ())
     302        9771 :     return 50;
     303           0 :   return -1;
     304             : }
     305             : 
     306             : static inline int
     307         559 : clib_cpu_march_priority_znver4 ()
     308             : {
     309         559 :   if (clib_cpu_supports_avx512_bitalg () && clib_cpu_supports_monitorx ())
     310           0 :     return 250;
     311         559 :   return -1;
     312             : }
     313             : 
     314             : static inline int
     315         559 : clib_cpu_march_priority_znver3 ()
     316             : {
     317         559 :   if (clib_cpu_supports_avx2 () && clib_cpu_supports_monitorx ())
     318           0 :     return 70;
     319         559 :   return -1;
     320             : }
     321             : 
     322             : #define X86_CPU_ARCH_PERF_FUNC 0xA
     323             : 
     324             : static inline int
     325        8944 : clib_get_pmu_counter_count (u8 *fixed, u8 *general)
     326             : {
     327             : #if defined(__x86_64__)
     328        8944 :   u32 __clib_unused eax = 0, ebx = 0, ecx = 0, edx = 0;
     329        8944 :   clib_get_cpuid (X86_CPU_ARCH_PERF_FUNC, &eax, &ebx, &ecx, &edx);
     330             : 
     331        8944 :   *general = (eax & 0xFF00) >> 8;
     332        8944 :   *fixed = (edx & 0xF);
     333             : 
     334        8944 :   return 1;
     335             : #else
     336             :   return 0;
     337             : #endif
     338             : }
     339             : 
     340             : static inline u32
     341             : clib_cpu_implementer ()
     342             : {
     343             :   char buf[128];
     344             :   static u32 implementer = -1;
     345             : 
     346             :   if (-1 != implementer)
     347             :     return implementer;
     348             : 
     349             :   FILE *fp = fopen ("/proc/cpuinfo", "r");
     350             :   if (!fp)
     351             :     return implementer;
     352             : 
     353             :   while (!feof (fp))
     354             :     {
     355             :       if (!fgets (buf, sizeof (buf), fp))
     356             :         break;
     357             :       buf[127] = '\0';
     358             :       if (strstr (buf, "CPU implementer"))
     359             :         implementer = (u32) strtol (memchr (buf, ':', 128) + 2, NULL, 0);
     360             :       if (-1 != implementer)
     361             :         break;
     362             :     }
     363             :   fclose (fp);
     364             : 
     365             :   return implementer;
     366             : }
     367             : 
     368             : static inline u32
     369             : clib_cpu_part ()
     370             : {
     371             :   char buf[128];
     372             :   static u32 part = -1;
     373             : 
     374             :   if (-1 != part)
     375             :     return part;
     376             : 
     377             :   FILE *fp = fopen ("/proc/cpuinfo", "r");
     378             :   if (!fp)
     379             :     return part;
     380             : 
     381             :   while (!feof (fp))
     382             :     {
     383             :       if (!fgets (buf, sizeof (buf), fp))
     384             :         break;
     385             :       buf[127] = '\0';
     386             :       if (strstr (buf, "CPU part"))
     387             :         part = (u32) strtol (memchr (buf, ':', 128) + 2, NULL, 0);
     388             :       if (-1 != part)
     389             :         break;
     390             :     }
     391             :   fclose (fp);
     392             : 
     393             :   return part;
     394             : }
     395             : 
     396             : #define AARCH64_CPU_IMPLEMENTER_CAVIUM      0x43
     397             : #define AARCH64_CPU_PART_THUNDERX2          0x0af
     398             : #define AARCH64_CPU_PART_OCTEONTX2T96       0x0b2
     399             : #define AARCH64_CPU_PART_OCTEONTX2T98       0x0b1
     400             : #define AARCH64_CPU_IMPLEMENTER_QDF24XX     0x51
     401             : #define AARCH64_CPU_PART_QDF24XX            0xc00
     402             : #define AARCH64_CPU_IMPLEMENTER_CORTEXA72   0x41
     403             : #define AARCH64_CPU_PART_CORTEXA72          0xd08
     404             : #define AARCH64_CPU_IMPLEMENTER_NEOVERSEN1  0x41
     405             : #define AARCH64_CPU_PART_NEOVERSEN1         0xd0c
     406             : 
     407             : static inline int
     408             : clib_cpu_march_priority_octeontx2 ()
     409             : {
     410             :   if ((AARCH64_CPU_IMPLEMENTER_CAVIUM == clib_cpu_implementer ()) &&
     411             :       ((AARCH64_CPU_PART_OCTEONTX2T96 == clib_cpu_part ())
     412             :        || AARCH64_CPU_PART_OCTEONTX2T98 == clib_cpu_part ()))
     413             :     return 20;
     414             :   return -1;
     415             : }
     416             : 
     417             : static inline int
     418             : clib_cpu_march_priority_thunderx2t99 ()
     419             : {
     420             :   if ((AARCH64_CPU_IMPLEMENTER_CAVIUM == clib_cpu_implementer ()) &&
     421             :       (AARCH64_CPU_PART_THUNDERX2 == clib_cpu_part ()))
     422             :     return 20;
     423             :   return -1;
     424             : }
     425             : 
     426             : static inline int
     427             : clib_cpu_march_priority_qdf24xx ()
     428             : {
     429             :   if ((AARCH64_CPU_IMPLEMENTER_QDF24XX == clib_cpu_implementer ()) &&
     430             :       (AARCH64_CPU_PART_QDF24XX == clib_cpu_part ()))
     431             :     return 20;
     432             :   return -1;
     433             : }
     434             : 
     435             : static inline int
     436             : clib_cpu_march_priority_cortexa72 ()
     437             : {
     438             :   if ((AARCH64_CPU_IMPLEMENTER_CORTEXA72 == clib_cpu_implementer ()) &&
     439             :       (AARCH64_CPU_PART_CORTEXA72 == clib_cpu_part ()))
     440             :     return 10;
     441             :   return -1;
     442             : }
     443             : 
     444             : static inline int
     445             : clib_cpu_march_priority_neoversen1 ()
     446             : {
     447             :   if ((AARCH64_CPU_IMPLEMENTER_NEOVERSEN1 == clib_cpu_implementer ()) &&
     448             :       (AARCH64_CPU_PART_NEOVERSEN1 == clib_cpu_part ()))
     449             :     return 10;
     450             :   return -1;
     451             : }
     452             : 
     453             : #ifdef CLIB_MARCH_VARIANT
     454             : #define CLIB_MARCH_FN_PRIORITY() CLIB_MARCH_SFX(clib_cpu_march_priority)()
     455             : #else
     456             : #define CLIB_MARCH_FN_PRIORITY() 0
     457             : #endif
     458             : #endif /* included_clib_cpu_h */
     459             : 
     460             : #define CLIB_MARCH_FN_CONSTRUCTOR(fn)                                   \
     461             : static void __clib_constructor                                          \
     462             : CLIB_MARCH_SFX(fn ## _march_constructor) (void)                         \
     463             : {                                                                       \
     464             :   if (CLIB_MARCH_FN_PRIORITY() > fn ## _selected_priority)           \
     465             :     {                                                                   \
     466             :       fn ## _selected = & CLIB_MARCH_SFX (fn ## _ma);                       \
     467             :       fn ## _selected_priority = CLIB_MARCH_FN_PRIORITY();              \
     468             :     }                                                                   \
     469             : }                                                                       \
     470             : 
     471             : #ifndef CLIB_MARCH_VARIANT
     472             : #define CLIB_MARCH_FN(fn, rtype, _args...)                                    \
     473             :   static rtype CLIB_MARCH_SFX (fn##_ma) (_args);                              \
     474             :   rtype (*fn##_selected) (_args) = &CLIB_MARCH_SFX (fn##_ma);                 \
     475             :   int fn##_selected_priority = 0;                                             \
     476             :   static inline rtype CLIB_MARCH_SFX (fn##_ma) (_args)
     477             : #else
     478             : #define CLIB_MARCH_FN(fn, rtype, _args...)                                    \
     479             :   static rtype CLIB_MARCH_SFX (fn##_ma) (_args);                              \
     480             :   extern rtype (*fn##_selected) (_args);                                      \
     481             :   extern int fn##_selected_priority;                                          \
     482             :   CLIB_MARCH_FN_CONSTRUCTOR (fn)                                              \
     483             :   static rtype CLIB_MARCH_SFX (fn##_ma) (_args)
     484             : #endif
     485             : 
     486             : #define CLIB_MARCH_FN_SELECT(fn) (* fn ## _selected)
     487             : 
     488             : format_function_t format_cpu_uarch;
     489             : format_function_t format_cpu_model_name;
     490             : format_function_t format_cpu_flags;
     491             : format_function_t format_march_variant;
     492             : 
     493             : /*
     494             :  * fd.io coding-style-patch-verification: ON
     495             :  *
     496             :  * Local Variables:
     497             :  * eval: (c-set-style "gnu")
     498             :  * End:
     499             :  */

Generated by: LCOV version 1.14