LCOV - differential code coverage report
Current view: top level - src/include/port - pg_lfind.h (source / functions) Coverage Total Hit UNC UBC GNC CBC DCB
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 100.0 % 55 55 29 26 26
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 5 5 3 2 1
Baseline: 16@8cea358b128 Branches: 93.3 % 30 28 1 1 11 17
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 29 29 29
(240..) days: 100.0 % 26 26 26
Function coverage date bins:
[..60] days: 100.0 % 3 3 3
(240..) days: 100.0 % 2 2 2
Branch coverage date bins:
[..60] days: 91.7 % 12 11 1 11
(240..) days: 94.4 % 18 17 1 17

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pg_lfind.h
                                  4                 :                :  *    Optimized linear search routines using SIMD intrinsics where
                                  5                 :                :  *    available.
                                  6                 :                :  *
                                  7                 :                :  * Copyright (c) 2022-2024, PostgreSQL Global Development Group
                                  8                 :                :  *
                                  9                 :                :  * IDENTIFICATION
                                 10                 :                :  *    src/include/port/pg_lfind.h
                                 11                 :                :  *
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : #ifndef PG_LFIND_H
                                 15                 :                : #define PG_LFIND_H
                                 16                 :                : 
                                 17                 :                : #include "port/simd.h"
                                 18                 :                : 
                                 19                 :                : /*
                                 20                 :                :  * pg_lfind8
                                 21                 :                :  *
                                 22                 :                :  * Return true if there is an element in 'base' that equals 'key', otherwise
                                 23                 :                :  * return false.
                                 24                 :                :  */
                                 25                 :                : static inline bool
  603 john.naylor@postgres       26                 :CBC     2506799 : pg_lfind8(uint8 key, uint8 *base, uint32 nelem)
                                 27                 :                : {
                                 28                 :                :     uint32      i;
                                 29                 :                : 
                                 30                 :                :     /* round down to multiple of vector length */
                                 31                 :        2506799 :     uint32      tail_idx = nelem & ~(sizeof(Vector8) - 1);
                                 32                 :                :     Vector8     chunk;
                                 33                 :                : 
                                 34         [ +  + ]:        4020306 :     for (i = 0; i < tail_idx; i += sizeof(Vector8))
                                 35                 :                :     {
                                 36                 :        2506839 :         vector8_load(&chunk, &base[i]);
                                 37         [ +  + ]:        2506839 :         if (vector8_has(chunk, key))
                                 38                 :         993332 :             return true;
                                 39                 :                :     }
                                 40                 :                : 
                                 41                 :                :     /* Process the remaining elements one at a time. */
                                 42         [ +  + ]:        1513520 :     for (; i < nelem; i++)
                                 43                 :                :     {
                                 44         [ +  + ]:             60 :         if (key == base[i])
                                 45                 :              7 :             return true;
                                 46                 :                :     }
                                 47                 :                : 
                                 48                 :        1513460 :     return false;
                                 49                 :                : }
                                 50                 :                : 
                                 51                 :                : /*
                                 52                 :                :  * pg_lfind8_le
                                 53                 :                :  *
                                 54                 :                :  * Return true if there is an element in 'base' that is less than or equal to
                                 55                 :                :  * 'key', otherwise return false.
                                 56                 :                :  */
                                 57                 :                : static inline bool
                                 58                 :         260387 : pg_lfind8_le(uint8 key, uint8 *base, uint32 nelem)
                                 59                 :                : {
                                 60                 :                :     uint32      i;
                                 61                 :                : 
                                 62                 :                :     /* round down to multiple of vector length */
                                 63                 :         260387 :     uint32      tail_idx = nelem & ~(sizeof(Vector8) - 1);
                                 64                 :                :     Vector8     chunk;
                                 65                 :                : 
                                 66         [ +  + ]:         520801 :     for (i = 0; i < tail_idx; i += sizeof(Vector8))
                                 67                 :                :     {
                                 68                 :         260427 :         vector8_load(&chunk, &base[i]);
                                 69         [ +  + ]:         260427 :         if (vector8_has_le(chunk, key))
                                 70                 :             13 :             return true;
                                 71                 :                :     }
                                 72                 :                : 
                                 73                 :                :     /* Process the remaining elements one at a time. */
                                 74         [ +  + ]:         260421 :     for (; i < nelem; i++)
                                 75                 :                :     {
                                 76         [ +  + ]:             60 :         if (base[i] <= key)
                                 77                 :             13 :             return true;
                                 78                 :                :     }
                                 79                 :                : 
                                 80                 :         260361 :     return false;
                                 81                 :                : }
                                 82                 :                : 
                                 83                 :                : /*
                                 84                 :                :  * pg_lfind32_one_by_one_helper
                                 85                 :                :  *
                                 86                 :                :  * Searches the array of integers one-by-one.  The caller is responsible for
                                 87                 :                :  * ensuring that there are at least "nelem" integers in the array.
                                 88                 :                :  */
                                 89                 :                : static inline bool
   18 nathan@postgresql.or       90                 :GNC    14937175 : pg_lfind32_one_by_one_helper(uint32 key, const uint32 *base, uint32 nelem)
                                 91                 :                : {
                                 92         [ +  + ]:       33448362 :     for (uint32 i = 0; i < nelem; i++)
                                 93                 :                :     {
                                 94         [ +  + ]:       18529908 :         if (key == base[i])
                                 95                 :          18721 :             return true;
                                 96                 :                :     }
                                 97                 :                : 
                                 98                 :       14918454 :     return false;
                                 99                 :                : }
                                100                 :                : 
                                101                 :                : #ifndef USE_NO_SIMD
                                102                 :                : /*
                                103                 :                :  * pg_lfind32_simd_helper
                                104                 :                :  *
                                105                 :                :  * Searches one 4-register-block of integers.  The caller is responsible for
                                106                 :                :  * ensuring that there are at least 4-registers-worth of integers remaining.
                                107                 :                :  */
                                108                 :                : static inline bool
                                109                 :             53 : pg_lfind32_simd_helper(const Vector32 keys, const uint32 *base)
                                110                 :                : {
   19                           111                 :             53 :     const uint32 nelem_per_vector = sizeof(Vector32) / sizeof(uint32);
                                112                 :                :     Vector32    vals1,
                                113                 :                :                 vals2,
                                114                 :                :                 vals3,
                                115                 :                :                 vals4,
                                116                 :                :                 result1,
                                117                 :                :                 result2,
                                118                 :                :                 result3,
                                119                 :                :                 result4,
                                120                 :                :                 tmp1,
                                121                 :                :                 tmp2,
                                122                 :                :                 result;
                                123                 :                : 
                                124                 :                :     /* load the next block into 4 registers */
                                125                 :             53 :     vector32_load(&vals1, base);
                                126                 :             53 :     vector32_load(&vals2, &base[nelem_per_vector]);
                                127                 :             53 :     vector32_load(&vals3, &base[nelem_per_vector * 2]);
                                128                 :             53 :     vector32_load(&vals4, &base[nelem_per_vector * 3]);
                                129                 :                : 
                                130                 :                :     /* compare each value to the key */
                                131                 :             53 :     result1 = vector32_eq(keys, vals1);
                                132                 :             53 :     result2 = vector32_eq(keys, vals2);
                                133                 :             53 :     result3 = vector32_eq(keys, vals3);
                                134                 :             53 :     result4 = vector32_eq(keys, vals4);
                                135                 :                : 
                                136                 :                :     /* combine the results into a single variable */
                                137                 :             53 :     tmp1 = vector32_or(result1, result2);
                                138                 :             53 :     tmp2 = vector32_or(result3, result4);
                                139                 :             53 :     result = vector32_or(tmp1, tmp2);
                                140                 :                : 
                                141                 :                :     /* return whether there was a match */
                                142                 :             53 :     return vector32_is_highbit_set(result);
                                143                 :                : }
                                144                 :                : #endif                          /* ! USE_NO_SIMD */
                                145                 :                : 
                                146                 :                : /*
                                147                 :                :  * pg_lfind32
                                148                 :                :  *
                                149                 :                :  * Return true if there is an element in 'base' that equals 'key', otherwise
                                150                 :                :  * return false.
                                151                 :                :  */
                                152                 :                : static inline bool
   18                           153                 :        7468593 : pg_lfind32(uint32 key, const uint32 *base, uint32 nelem)
                                154                 :                : {
                                155                 :                : #ifndef USE_NO_SIMD
                                156                 :        7468593 :     uint32      i = 0;
                                157                 :                : 
                                158                 :                :     /*
                                159                 :                :      * For better instruction-level parallelism, each loop iteration operates
                                160                 :                :      * on a block of four registers.
                                161                 :                :      */
  594 john.naylor@postgres      162                 :CBC     7468593 :     const Vector32 keys = vector32_broadcast(key);  /* load copies of key */
                                163                 :        7468593 :     const uint32 nelem_per_vector = sizeof(Vector32) / sizeof(uint32);
                                164                 :        7468593 :     const uint32 nelem_per_iteration = 4 * nelem_per_vector;
                                165                 :                : 
                                166                 :                :     /* round down to multiple of elements per iteration */
                                167                 :        7468593 :     const uint32 tail_idx = nelem & ~(nelem_per_iteration - 1);
                                168                 :                : 
                                169                 :                : #if defined(USE_ASSERT_CHECKING)
   18 nathan@postgresql.or      170                 :GNC     7468593 :     bool        assert_result = pg_lfind32_one_by_one_helper(key, base, nelem);
                                171                 :                : #endif
                                172                 :                : 
                                173                 :                :     /*
                                174                 :                :      * If there aren't enough elements for the SIMD code, use the standard
                                175                 :                :      * one-by-one linear search code.
                                176                 :                :      */
   19                           177         [ +  + ]:        7468593 :     if (nelem < nelem_per_iteration)
   18                           178                 :        7468582 :         return pg_lfind32_one_by_one_helper(key, base, nelem);
                                179                 :                : 
                                180                 :                :     /*
                                181                 :                :      * Process as many elements as possible with a block of 4 registers.
                                182                 :                :      */
                                183                 :                :     do
                                184                 :                :     {
   19                           185         [ +  + ]:             35 :         if (pg_lfind32_simd_helper(keys, &base[i]))
                                186                 :                :         {
  620 john.naylor@postgres      187         [ -  + ]:CBC           2 :             Assert(assert_result == true);
                                188                 :              2 :             return true;
                                189                 :                :         }
                                190                 :                : 
   19 nathan@postgresql.or      191                 :GNC          33 :         i += nelem_per_iteration;
                                192                 :                : 
                                193         [ +  + ]:             33 :     } while (i < tail_idx);
                                194                 :                : 
                                195                 :                :     /*
                                196                 :                :      * Process the last 'nelem_per_iteration' elements in the array with a
                                197                 :                :      * 4-register block.  This will cause us to check a subset of the elements
                                198                 :                :      * more than once, but that won't affect correctness, and testing has
                                199                 :                :      * demonstrated that this helps more cases than it harms.
                                200                 :                :      */
                                201         [ -  + ]:              9 :     Assert(assert_result == pg_lfind32_simd_helper(keys, &base[nelem - nelem_per_iteration]));
                                202                 :              9 :     return pg_lfind32_simd_helper(keys, &base[nelem - nelem_per_iteration]);
                                203                 :                : #else
                                204                 :                :     /* Process the elements one at a time. */
                                205                 :                :     return pg_lfind32_one_by_one_helper(key, base, nelem);
                                206                 :                : #endif
                                207                 :                : }
                                208                 :                : 
                                209                 :                : #endif                          /* PG_LFIND_H */
        

Generated by: LCOV version 2.1-beta2-3-g6141622