LCOV - differential code coverage report
Current view: top level - src/port - pg_cpu_x86.c (source / functions) Coverage Total Hit UNC GNC
Current: 380a8b2ea024c33a35e7abc8628e7c4f52f9f9f9 vs db5ed03217b9c238703df8b4b286115d6e940488 Lines: 67.2 % 64 43 21 43
Current Date: 2026-05-29 21:51:00 -0400 Functions: 100.0 % 6 6 6
Baseline: lcov-20260530-034037-baseline Branches: 17.5 % 40 7 33 7
Baseline Date: 2026-05-29 14:39:03 -0700 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 58.3 % 12 7 5 7
(30,360] days: 68.6 % 51 35 16 35
(360..) days: 100.0 % 1 1 1
Function coverage date bins:
(7,30] days: 100.0 % 1 1 1
(30,360] days: 100.0 % 5 5 5
Branch coverage date bins:
(7,30] days: 25.0 % 8 2 6 2
(30,360] days: 15.6 % 32 5 27 5

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pg_cpu_x86.c
                                  4                 :                :  *    Runtime CPU feature detection for x86
                                  5                 :                :  *
                                  6                 :                :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
                                  7                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                  8                 :                :  *
                                  9                 :                :  *
                                 10                 :                :  * IDENTIFICATION
                                 11                 :                :  *    src/port/pg_cpu_x86.c
                                 12                 :                :  *
                                 13                 :                :  *-------------------------------------------------------------------------
                                 14                 :                :  */
                                 15                 :                : 
                                 16                 :                : #ifndef FRONTEND
                                 17                 :                : #include "postgres.h"
                                 18                 :                : #else
                                 19                 :                : #include "postgres_fe.h"
                                 20                 :                : #endif
                                 21                 :                : 
                                 22                 :                : #if defined(USE_SSE2) || defined(__i386__)
                                 23                 :                : 
                                 24                 :                : #ifdef _MSC_VER
                                 25                 :                : #include <intrin.h>
                                 26                 :                : #else
                                 27                 :                : #include <cpuid.h>
                                 28                 :                : #endif
                                 29                 :                : 
                                 30                 :                : #ifdef HAVE_XSAVE_INTRINSICS
                                 31                 :                : #include <immintrin.h>
                                 32                 :                : #endif
                                 33                 :                : 
                                 34                 :                : #include "port/pg_cpu.h"
                                 35                 :                : 
                                 36                 :                : /*
                                 37                 :                :  * XSAVE state component bits that we need
                                 38                 :                :  *
                                 39                 :                :  * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-1-manual.pdf
                                 40                 :                :  * Chapter "MANAGING STATE USING THE XSAVE FEATURE SET"
                                 41                 :                :  */
                                 42                 :                : #define XMM         (1<<1)
                                 43                 :                : #define YMM         (1<<2)
                                 44                 :                : #define OPMASK      (1<<5)
                                 45                 :                : #define ZMM0_15     (1<<6)
                                 46                 :                : #define ZMM16_31    (1<<7)
                                 47                 :                : 
                                 48                 :                : 
                                 49                 :                : /* array indexed by enum X86FeatureId */
                                 50                 :                : bool        X86Features[X86FeaturesSize] = {0};
                                 51                 :                : 
                                 52                 :                : static bool
   91 john.naylor@postgres       53                 :GNC        3674 : mask_available(uint32 value, uint32 mask)
                                 54                 :                : {
                                 55                 :           3674 :     return (value & mask) == mask;
                                 56                 :                : }
                                 57                 :                : 
                                 58                 :                : /* Named indexes for CPUID register array */
                                 59                 :                : #define EAX 0
                                 60                 :                : #define EBX 1
                                 61                 :                : #define ECX 2
                                 62                 :                : #define EDX 3
                                 63                 :                : 
                                 64                 :                : /*
                                 65                 :                :  * Request CPUID information for the specified leaf.
                                 66                 :                :  */
                                 67                 :                : static inline void
   66                            68                 :           5511 : pg_cpuid(int leaf, unsigned int *reg)
                                 69                 :                : {
   22                            70                 :           5511 :     memset(reg, 0, 4 * sizeof(unsigned int));
                                 71                 :                : #if defined(HAVE__GET_CPUID)
   66                            72                 :           5511 :     __get_cpuid(leaf, &reg[EAX], &reg[EBX], &reg[ECX], &reg[EDX]);
                                 73                 :                : #elif defined(HAVE__CPUID)
                                 74                 :                :     __cpuid((int *) reg, leaf);
                                 75                 :                : #endif
                                 76                 :           5511 : }
                                 77                 :                : 
                                 78                 :                : /*
                                 79                 :                :  * Request CPUID information for the specified leaf and subleaf.
                                 80                 :                :  *
                                 81                 :                :  * Returns true if the CPUID leaf/subleaf is supported, false otherwise.
                                 82                 :                :  */
                                 83                 :                : static inline bool
                                 84                 :           1837 : pg_cpuid_subleaf(int leaf, int subleaf, unsigned int *reg)
                                 85                 :                : {
   53 andres@anarazel.de         86                 :           1837 :     memset(reg, 0, 4 * sizeof(unsigned int));
                                 87                 :                : #if defined(HAVE__GET_CPUID_COUNT)
   66 john.naylor@postgres       88                 :           1837 :     return __get_cpuid_count(leaf, subleaf, &reg[EAX], &reg[EBX], &reg[ECX], &reg[EDX]) == 1;
                                 89                 :                : #elif defined(HAVE__CPUIDEX)
                                 90                 :                :     __cpuidex((int *) reg, leaf, subleaf);
                                 91                 :                :     return true;
                                 92                 :                : #else
                                 93                 :                :     return false;
                                 94                 :                : #endif
                                 95                 :                : }
                                 96                 :                : 
                                 97                 :                : /*
                                 98                 :                :  * Parse the CPU ID info for runtime checks.
                                 99                 :                :  */
                                100                 :                : #ifdef HAVE_XSAVE_INTRINSICS
                                101                 :                : pg_attribute_target("xsave")
                                102                 :                : #endif
                                103                 :                : void
   92                           104                 :           1837 : set_x86_features(void)
                                105                 :                : {
   66                           106                 :           1837 :     unsigned int reg[4] = {0};
                                107                 :                :     bool        have_osxsave;
                                108                 :                : 
                                109                 :           1837 :     pg_cpuid(0x01, reg);
                                110                 :                : 
                                111                 :           1837 :     X86Features[PG_SSE4_2] = reg[ECX] >> 20 & 1;
                                112                 :           1837 :     X86Features[PG_POPCNT] = reg[ECX] >> 23 & 1;
   53 andres@anarazel.de        113                 :           1837 :     X86Features[PG_HYPERVISOR] = reg[ECX] >> 31 & 1;
                                114                 :           1837 :     have_osxsave = reg[ECX] >> 27 & 1;
                                115                 :                : 
                                116                 :           1837 :     pg_cpuid_subleaf(0x07, 0, reg);
                                117                 :                : 
                                118                 :           1837 :     X86Features[PG_TSC_ADJUST] = reg[EBX] >> 1 & 1;
                                119                 :                : 
                                120                 :                :     /* leaf 7 features that depend on OSXSAVE */
                                121         [ +  - ]:           1837 :     if (have_osxsave)
                                122                 :                :     {
   91 john.naylor@postgres      123                 :           1837 :         uint32      xcr0_val = 0;
                                124                 :                : 
                                125                 :                : #ifdef HAVE_XSAVE_INTRINSICS
                                126                 :                :         /* get value of Extended Control Register */
                                127                 :           1837 :         xcr0_val = _xgetbv(0);
                                128                 :                : #endif
                                129                 :                : 
                                130                 :                :         /* Are YMM registers enabled? */
   56                           131         [ +  - ]:           1837 :         if (mask_available(xcr0_val, XMM | YMM))
                                132                 :           1837 :             X86Features[PG_AVX2] = reg[EBX] >> 5 & 1;
                                133                 :                : 
                                134                 :                :         /* Are ZMM registers enabled? */
   91                           135         [ -  + ]:           1837 :         if (mask_available(xcr0_val, XMM | YMM |
                                136                 :                :                            OPMASK | ZMM0_15 | ZMM16_31))
                                137                 :                :         {
   66 john.naylor@postgres      138                 :UNC           0 :             X86Features[PG_AVX512_BW] = reg[EBX] >> 30 & 1;
                                139                 :              0 :             X86Features[PG_AVX512_VL] = reg[EBX] >> 31 & 1;
                                140                 :                : 
                                141                 :              0 :             X86Features[PG_AVX512_VPCLMULQDQ] = reg[ECX] >> 10 & 1;
                                142                 :              0 :             X86Features[PG_AVX512_VPOPCNTDQ] = reg[ECX] >> 14 & 1;
                                143                 :                :         }
                                144                 :                :     }
                                145                 :                : 
                                146                 :                :     /* Check for other TSC related flags */
   53 andres@anarazel.de        147                 :GNC        1837 :     pg_cpuid(0x80000001, reg);
                                148                 :           1837 :     X86Features[PG_RDTSCP] = reg[EDX] >> 27 & 1;
                                149                 :                : 
                                150                 :           1837 :     pg_cpuid(0x80000007, reg);
                                151                 :           1837 :     X86Features[PG_TSC_INVARIANT] = reg[EDX] >> 8 & 1;
                                152                 :                : 
   92 john.naylor@postgres      153                 :           1837 :     X86Features[INIT_PG_X86] = true;
 4064 heikki.linnakangas@i      154                 :           1837 : }
                                155                 :                : 
                                156                 :                : /* TSC (Time-stamp Counter) handling code */
                                157                 :                : 
                                158                 :                : static uint32 x86_hypervisor_tsc_frequency_khz(void);
                                159                 :                : 
                                160                 :                : /*
                                161                 :                :  * Determine the TSC frequency of the CPU through CPUID, where supported.
                                162                 :                :  *
                                163                 :                :  * Needed to interpret the tick value returned by RDTSC/RDTSCP. Return value of
                                164                 :                :  * 0 indicates the frequency information was not accessible via CPUID.
                                165                 :                :  *
                                166                 :                :  * The optional source argument may contain a pre-allocated string of capacity
                                167                 :                :  * source_size that will be concatenated with info on the TSC frequency source.
                                168                 :                :  */
                                169                 :                : uint32
   14 andres@anarazel.de        170                 :           1293 : x86_tsc_frequency_khz(char *source, size_t source_size)
                                171                 :                : {
   53                           172                 :           1293 :     unsigned int reg[4] = {0};
                                173                 :                : 
                                174                 :                :     /*
                                175                 :                :      * If we're inside a virtual machine, try to fetch the TSC frequency from
                                176                 :                :      * the hypervisor, using a hypervisor specific method.
                                177                 :                :      *
                                178                 :                :      * Note it is not safe to utilize the regular 0x15/0x16 CPUID registers
                                179                 :                :      * (i.e. the logic below) in virtual machines, as they have been observed
                                180                 :                :      * to be wildly incorrect when virtualized.
                                181                 :                :      */
                                182         [ +  - ]:           1293 :     if (x86_feature_available(PG_HYPERVISOR))
                                183                 :                :     {
   14                           184                 :           1293 :         uint32      freq = x86_hypervisor_tsc_frequency_khz();
                                185                 :                : 
                                186         [ +  - ]:           1293 :         if (source)
                                187                 :                :         {
                                188                 :           1293 :             strlcat(source, ", hypervisor", source_size);
                                189         [ -  + ]:           1293 :             if (freq > 0)
   14 andres@anarazel.de        190                 :UNC           0 :                 strlcat(source, ", cpuid 0x40000010", source_size);
                                191                 :                :         }
   14 andres@anarazel.de        192                 :GNC        1293 :         return freq;
                                193                 :                :     }
                                194                 :                : 
                                195                 :                :     /*
                                196                 :                :      * On modern Intel CPUs, the TSC is implemented by invariant timekeeping
                                197                 :                :      * hardware, also called "Always Running Timer", or ART. The ART stays
                                198                 :                :      * consistent even if the CPU changes frequency due to changing power
                                199                 :                :      * levels.
                                200                 :                :      *
                                201                 :                :      * As documented in "Determining the Processor Base Frequency" in the
                                202                 :                :      * "IntelĀ® 64 and IA-32 Architectures Software Developer's Manual",
                                203                 :                :      * February 2026 Edition, we can get the TSC frequency as follows:
                                204                 :                :      *
                                205                 :                :      * Nominal TSC frequency = ( CPUID.15H:ECX[31:0] * CPUID.15H:EBX[31:0] ) /
                                206                 :                :      * CPUID.15H:EAX[31:0]
                                207                 :                :      *
                                208                 :                :      * With CPUID.15H:ECX representing the nominal core crystal clock
                                209                 :                :      * frequency, and EAX/EBX representing values used to translate the TSC
                                210                 :                :      * value to that frequency, see "Chapter 20.17 "Time-Stamp Counter" of
                                211                 :                :      * that manual.
                                212                 :                :      *
                                213                 :                :      * Older Intel CPUs, and other vendors do not set CPUID.15H:ECX, and as
                                214                 :                :      * such we fall back to alternate approaches.
                                215                 :                :      */
   53 andres@anarazel.de        216                 :UNC           0 :     pg_cpuid(0x15, reg);
                                217         [ #  # ]:              0 :     if (reg[ECX] > 0)
                                218                 :                :     {
                                219                 :                :         /*
                                220                 :                :          * EBX not being set indicates invariant TSC is not available. Require
                                221                 :                :          * EAX being non-zero too, to avoid a theoretical divide by zero.
                                222                 :                :          */
                                223   [ #  #  #  # ]:              0 :         if (reg[EAX] == 0 || reg[EBX] == 0)
                                224                 :              0 :             return 0;
                                225                 :                : 
   14                           226         [ #  # ]:              0 :         if (source)
                                227                 :              0 :             strlcat(source, ", cpuid 0x15", source_size);
                                228                 :                : 
   53                           229                 :              0 :         return reg[ECX] / 1000 * reg[EBX] / reg[EAX];
                                230                 :                :     }
                                231                 :                : 
                                232                 :                :     /*
                                233                 :                :      * When CPUID.15H is not available/incomplete, we can instead try to get
                                234                 :                :      * the processor base frequency in MHz from CPUID.16H:EAX, the "Processor
                                235                 :                :      * Frequency Information Leaf".
                                236                 :                :      */
                                237                 :              0 :     pg_cpuid(0x16, reg);
                                238         [ #  # ]:              0 :     if (reg[EAX] > 0)
                                239                 :                :     {
   14                           240         [ #  # ]:              0 :         if (source)
                                241                 :              0 :             strlcat(source, ", cpuid 0x16", source_size);
                                242                 :                : 
   53                           243                 :              0 :         return reg[EAX] * 1000;
                                244                 :                :     }
                                245                 :                : 
                                246                 :              0 :     return 0;
                                247                 :                : }
                                248                 :                : 
                                249                 :                : /*
                                250                 :                :  * Support for reading TSC frequency for hypervisors passing it to a guest VM.
                                251                 :                :  *
                                252                 :                :  * Two Hypervisors (VMware and KVM) are known to make TSC frequency in KHz
                                253                 :                :  * available at the vendor-specific 0x40000010 leaf in the EAX register.
                                254                 :                :  *
                                255                 :                :  * For some other Hypervisors that have an invariant TSC, e.g. HyperV, we would
                                256                 :                :  * need to access a model-specific register (MSR) to get the frequency. MSRs are
                                257                 :                :  * separate from CPUID and typically not available for unprivileged processes,
                                258                 :                :  * so we can't get the frequency this way.
                                259                 :                :  */
                                260                 :                : #define CPUID_HYPERVISOR_VMWARE(r) (r[EBX] == 0x61774d56 && r[ECX] == 0x4d566572 && r[EDX] == 0x65726177)   /* VMwareVMware */
                                261                 :                : #define CPUID_HYPERVISOR_KVM(r) (r[EBX] == 0x4b4d564b && r[ECX] == 0x564b4d56 && r[EDX] == 0x0000004d)  /* KVMKVMKVM */
                                262                 :                : static uint32
   53 andres@anarazel.de        263                 :GNC        1293 : x86_hypervisor_tsc_frequency_khz(void)
                                264                 :                : {
                                265                 :                : #if defined(HAVE__CPUIDEX)
      tgl@sss.pgh.pa.us         266                 :           1293 :     unsigned int reg[4] = {0};
                                267                 :                : 
                                268                 :                :     /*
                                269                 :                :      * The hypervisor is determined using the 0x40000000 Hypervisor
                                270                 :                :      * information leaf, which requires use of __cpuidex to set ECX to 0 to
                                271                 :                :      * access it.
                                272                 :                :      *
                                273                 :                :      * The similar __get_cpuid_count function does not work as expected since
                                274                 :                :      * it contains a check for __get_cpuid_max, which has been observed to be
                                275                 :                :      * lower than the special Hypervisor leaf, despite it being available.
                                276                 :                :      */
      andres@anarazel.de        277                 :           1293 :     __cpuidex((int *) reg, 0x40000000, 0);
                                278                 :                : 
                                279                 :           1293 :     if (reg[EAX] >= 0x40000010 && (CPUID_HYPERVISOR_VMWARE(reg) || CPUID_HYPERVISOR_KVM(reg)))
                                      [ -  +  -  -  
                                     -  -  -  -  -  
                                        -  -  -  -  
                                                 - ]
                                280                 :                :     {
   53 andres@anarazel.de        281                 :UNC           0 :         __cpuidex((int *) reg, 0x40000010, 0);
                                282         [ #  # ]:              0 :         if (reg[EAX] > 0)
                                283                 :              0 :             return reg[EAX];
                                284                 :                :     }
                                285                 :                : #endif                          /* HAVE__CPUIDEX */
                                286                 :                : 
   53 andres@anarazel.de        287                 :GNC        1293 :     return 0;
                                288                 :                : }
                                289                 :                : 
                                290                 :                : #else                           /* defined(USE_SSE2) || defined(__i386__) */
                                291                 :                : 
                                292                 :                : /* prevent linker complaints about empty module */
                                293                 :                : extern int  pg_cpu_x86_dummy_variable;
                                294                 :                : int         pg_cpu_x86_dummy_variable = 0;
                                295                 :                : 
                                296                 :                : #endif                          /* ! (USE_SSE2 || __i386__) */
        

Generated by: LCOV version 2.5.0-beta