LCOV - code coverage report
Current view: top level - lib/member - rte_member_ht.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 169 214 79.0 %
Date: 2025-01-02 22:41:34 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 80 174 46.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2017 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <rte_errno.h>
       6                 :            : #include <rte_malloc.h>
       7                 :            : #include <rte_prefetch.h>
       8                 :            : #include <rte_random.h>
       9                 :            : #include <rte_log.h>
      10                 :            : #include <rte_vect.h>
      11                 :            : 
      12                 :            : #include "member.h"
      13                 :            : #include "rte_member.h"
      14                 :            : #include "rte_member_ht.h"
      15                 :            : 
      16                 :            : #if defined(RTE_ARCH_X86)
      17                 :            : #include "rte_member_x86.h"
      18                 :            : #endif
      19                 :            : 
      20                 :            : /* Search bucket for entry with tmp_sig and update set_id */
      21                 :            : static inline int
      22                 :            : update_entry_search(uint32_t bucket_id, member_sig_t tmp_sig,
      23                 :            :                 struct member_ht_bucket *buckets,
      24                 :            :                 member_set_t set_id)
      25                 :            : {
      26                 :            :         uint32_t i;
      27                 :            : 
      28   [ #  #  #  # ]:          0 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
      29   [ #  #  #  # ]:          0 :                 if (buckets[bucket_id].sigs[i] == tmp_sig) {
      30                 :          0 :                         buckets[bucket_id].sets[i] = set_id;
      31                 :            :                         return 1;
      32                 :            :                 }
      33                 :            :         }
      34                 :            :         return 0;
      35                 :            : }
      36                 :            : 
      37                 :            : static inline int
      38                 :            : search_bucket_single(uint32_t bucket_id, member_sig_t tmp_sig,
      39                 :            :                 struct member_ht_bucket *buckets,
      40                 :            :                 member_set_t *set_id)
      41                 :            : {
      42                 :            :         uint32_t iter;
      43                 :            : 
      44   [ #  #  #  #  :          0 :         for (iter = 0; iter < RTE_MEMBER_BUCKET_ENTRIES; iter++) {
             #  #  #  # ]
      45   [ #  #  #  #  :          0 :                 if (tmp_sig == buckets[bucket_id].sigs[iter] &&
             #  #  #  # ]
      46   [ #  #  #  #  :          0 :                                 buckets[bucket_id].sets[iter] !=
             #  #  #  # ]
      47                 :            :                                 RTE_MEMBER_NO_MATCH) {
      48                 :          0 :                         *set_id = buckets[bucket_id].sets[iter];
      49                 :            :                         return 1;
      50                 :            :                 }
      51                 :            :         }
      52                 :            :         return 0;
      53                 :            : }
      54                 :            : 
      55                 :            : static inline void
      56                 :            : search_bucket_multi(uint32_t bucket_id, member_sig_t tmp_sig,
      57                 :            :                 struct member_ht_bucket *buckets,
      58                 :            :                 uint32_t *counter,
      59                 :            :                 uint32_t matches_per_key,
      60                 :            :                 member_set_t *set_id)
      61                 :            : {
      62                 :            :         uint32_t iter;
      63                 :            : 
      64   [ #  #  #  #  :          0 :         for (iter = 0; iter < RTE_MEMBER_BUCKET_ENTRIES; iter++) {
             #  #  #  # ]
      65   [ #  #  #  #  :          0 :                 if (tmp_sig == buckets[bucket_id].sigs[iter] &&
             #  #  #  # ]
      66   [ #  #  #  #  :          0 :                                 buckets[bucket_id].sets[iter] !=
             #  #  #  # ]
      67                 :            :                                 RTE_MEMBER_NO_MATCH) {
      68                 :          0 :                         set_id[*counter] = buckets[bucket_id].sets[iter];
      69                 :          0 :                         (*counter)++;
      70   [ #  #  #  #  :          0 :                         if (*counter >= matches_per_key)
             #  #  #  # ]
      71                 :            :                                 return;
      72                 :            :                 }
      73                 :            :         }
      74                 :            : }
      75                 :            : 
      76                 :            : int
      77                 :          8 : rte_member_create_ht(struct rte_member_setsum *ss,
      78                 :            :                 const struct rte_member_parameters *params)
      79                 :            : {
      80                 :            :         uint32_t i, j;
      81                 :            :         uint32_t size_bucket_t;
      82         [ +  + ]:          8 :         uint32_t num_entries = rte_align32pow2(params->num_keys);
      83                 :            : 
      84         [ +  + ]:          8 :         if ((num_entries > RTE_MEMBER_ENTRIES_MAX) ||
      85         [ +  + ]:          6 :                         !rte_is_power_of_2(RTE_MEMBER_BUCKET_ENTRIES) ||
      86                 :            :                         num_entries < RTE_MEMBER_BUCKET_ENTRIES) {
      87                 :          3 :                 rte_errno = EINVAL;
      88                 :          3 :                 MEMBER_LOG(ERR,
      89                 :            :                         "Membership HT create with invalid parameters");
      90                 :          3 :                 return -EINVAL;
      91                 :            :         }
      92                 :            : 
      93                 :          5 :         uint32_t num_buckets = num_entries / RTE_MEMBER_BUCKET_ENTRIES;
      94                 :            : 
      95                 :            :         size_bucket_t = sizeof(struct member_ht_bucket);
      96                 :            : 
      97                 :          5 :         struct member_ht_bucket *buckets = rte_zmalloc_socket(NULL,
      98                 :          5 :                         num_buckets * size_bucket_t,
      99                 :          5 :                         RTE_CACHE_LINE_SIZE, ss->socket_id);
     100                 :            : 
     101         [ -  + ]:          5 :         if (buckets == NULL) {
     102                 :          0 :                 MEMBER_LOG(ERR, "memory allocation failed for HT "
     103                 :            :                                                 "setsummary");
     104                 :          0 :                 return -ENOMEM;
     105                 :            :         }
     106                 :            : 
     107                 :          5 :         ss->table = buckets;
     108                 :          5 :         ss->bucket_cnt = num_buckets;
     109                 :          5 :         ss->bucket_mask = num_buckets - 1;
     110                 :          5 :         ss->cache = params->is_cache;
     111                 :            : 
     112         [ +  + ]:      20485 :         for (i = 0; i < num_buckets; i++) {
     113         [ +  + ]:     348160 :                 for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++)
     114                 :     327680 :                         buckets[i].sets[j] = RTE_MEMBER_NO_MATCH;
     115                 :            :         }
     116                 :            : #if defined(RTE_ARCH_X86)
     117         [ +  - ]:          5 :         if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX2) &&
     118         [ +  - ]:          5 :                         RTE_MEMBER_BUCKET_ENTRIES == 16 &&
     119                 :          5 :                         rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_256)
     120                 :          5 :                 ss->sig_cmp_fn = RTE_MEMBER_COMPARE_AVX2;
     121                 :            :         else
     122                 :            : #endif
     123                 :          0 :                 ss->sig_cmp_fn = RTE_MEMBER_COMPARE_SCALAR;
     124                 :            : 
     125                 :          5 :         MEMBER_LOG(DEBUG, "Hash table based filter created, "
     126                 :            :                         "the table has %u entries, %u buckets",
     127                 :            :                         num_entries, num_buckets);
     128                 :          5 :         return 0;
     129                 :            : }
     130                 :            : 
     131                 :            : static inline void
     132                 :     302968 : get_buckets_index(const struct rte_member_setsum *ss, const void *key,
     133                 :            :                 uint32_t *prim_bkt, uint32_t *sec_bkt, member_sig_t *sig)
     134                 :            : {
     135                 :     605936 :         uint32_t first_hash = MEMBER_HASH_FUNC(key, ss->key_len,
     136                 :     302968 :                                                 ss->prim_hash_seed);
     137                 :     302968 :         uint32_t sec_hash = MEMBER_HASH_FUNC(&first_hash, sizeof(uint32_t),
     138                 :     302968 :                                                 ss->sec_hash_seed);
     139                 :            :         /*
     140                 :            :          * We use the first hash value for the signature, and the second hash
     141                 :            :          * value to derive the primary and secondary bucket locations.
     142                 :            :          *
     143                 :            :          * For non-cache mode, we use the lower bits for the primary bucket
     144                 :            :          * location. Then we xor primary bucket location and the signature
     145                 :            :          * to get the secondary bucket location. This is called "partial-key
     146                 :            :          * cuckoo hashing" proposed by B. Fan, et al's paper
     147                 :            :          * "Cuckoo Filter: Practically Better Than Bloom". The benefit to use
     148                 :            :          * xor is that one could derive the alternative bucket location
     149                 :            :          * by only using the current bucket location and the signature. This is
     150                 :            :          * generally required by non-cache mode's eviction and deletion
     151                 :            :          * process without the need to store alternative hash value nor the full
     152                 :            :          * key.
     153                 :            :          *
     154                 :            :          * For cache mode, we use the lower bits for the primary bucket
     155                 :            :          * location and the higher bits for the secondary bucket location. In
     156                 :            :          * cache mode, keys are simply overwritten if bucket is full. We do not
     157                 :            :          * use xor since lower/higher bits are more independent hash values thus
     158                 :            :          * should provide slightly better table load.
     159                 :            :          */
     160                 :     302968 :         *sig = first_hash;
     161         [ +  + ]:     302968 :         if (ss->cache) {
     162                 :     107630 :                 *prim_bkt = sec_hash & ss->bucket_mask;
     163                 :     107630 :                 *sec_bkt =  (sec_hash >> 16) & ss->bucket_mask;
     164                 :            :         } else {
     165                 :     195338 :                 *prim_bkt = sec_hash & ss->bucket_mask;
     166                 :     195338 :                 *sec_bkt =  (*prim_bkt ^ *sig) & ss->bucket_mask;
     167                 :            :         }
     168                 :     302968 : }
     169                 :            : 
     170                 :            : int
     171                 :         20 : rte_member_lookup_ht(const struct rte_member_setsum *ss,
     172                 :            :                 const void *key, member_set_t *set_id)
     173                 :            : {
     174                 :            :         uint32_t prim_bucket, sec_bucket;
     175                 :            :         member_sig_t tmp_sig;
     176                 :         20 :         struct member_ht_bucket *buckets = ss->table;
     177                 :            : 
     178                 :         20 :         *set_id = RTE_MEMBER_NO_MATCH;
     179                 :         20 :         get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
     180                 :            : 
     181         [ +  - ]:         20 :         switch (ss->sig_cmp_fn) {
     182                 :            : #if defined(RTE_ARCH_X86) && defined(__AVX2__)
     183                 :         20 :         case RTE_MEMBER_COMPARE_AVX2:
     184                 :         20 :                 if (search_bucket_single_avx(prim_bucket, tmp_sig, buckets,
     185                 :            :                                 set_id) ||
     186                 :         10 :                                 search_bucket_single_avx(sec_bucket, tmp_sig,
     187                 :            :                                         buckets, set_id))
     188                 :         10 :                         return 1;
     189                 :            :                 break;
     190                 :            : #endif
     191                 :          0 :         default:
     192                 :          0 :                 if (search_bucket_single(prim_bucket, tmp_sig, buckets,
     193                 :            :                                 set_id) ||
     194                 :          0 :                                 search_bucket_single(sec_bucket, tmp_sig,
     195                 :            :                                         buckets, set_id))
     196                 :          0 :                         return 1;
     197                 :            :         }
     198                 :            : 
     199                 :            :         return 0;
     200                 :            : }
     201                 :            : 
     202                 :            : uint32_t
     203                 :          4 : rte_member_lookup_bulk_ht(const struct rte_member_setsum *ss,
     204                 :            :                 const void **keys, uint32_t num_keys, member_set_t *set_id)
     205                 :            : {
     206                 :            :         uint32_t i;
     207                 :            :         uint32_t num_matches = 0;
     208                 :          4 :         struct member_ht_bucket *buckets = ss->table;
     209                 :            :         member_sig_t tmp_sig[RTE_MEMBER_LOOKUP_BULK_MAX];
     210                 :            :         uint32_t prim_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
     211                 :            :         uint32_t sec_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
     212                 :            : 
     213         [ +  + ]:         24 :         for (i = 0; i < num_keys; i++) {
     214                 :         20 :                 get_buckets_index(ss, keys[i], &prim_buckets[i],
     215                 :            :                                 &sec_buckets[i], &tmp_sig[i]);
     216                 :         20 :                 rte_prefetch0(&buckets[prim_buckets[i]]);
     217                 :         20 :                 rte_prefetch0(&buckets[sec_buckets[i]]);
     218                 :            :         }
     219                 :            : 
     220         [ +  + ]:         24 :         for (i = 0; i < num_keys; i++) {
     221         [ +  - ]:         20 :                 switch (ss->sig_cmp_fn) {
     222                 :            : #if defined(RTE_ARCH_X86) && defined(__AVX2__)
     223                 :         20 :                 case RTE_MEMBER_COMPARE_AVX2:
     224                 :         20 :                         if (search_bucket_single_avx(prim_buckets[i],
     225                 :         20 :                                         tmp_sig[i], buckets, &set_id[i]) ||
     226                 :          4 :                                 search_bucket_single_avx(sec_buckets[i],
     227                 :            :                                         tmp_sig[i], buckets, &set_id[i]))
     228                 :         16 :                                 num_matches++;
     229                 :            :                         else
     230                 :          4 :                                 set_id[i] = RTE_MEMBER_NO_MATCH;
     231                 :            :                         break;
     232                 :            : #endif
     233                 :          0 :                 default:
     234                 :          0 :                         if (search_bucket_single(prim_buckets[i], tmp_sig[i],
     235                 :          0 :                                         buckets, &set_id[i]) ||
     236                 :          0 :                                         search_bucket_single(sec_buckets[i],
     237                 :            :                                         tmp_sig[i], buckets, &set_id[i]))
     238                 :          0 :                                 num_matches++;
     239                 :            :                         else
     240                 :          0 :                                 set_id[i] = RTE_MEMBER_NO_MATCH;
     241                 :            :                 }
     242                 :            :         }
     243                 :          4 :         return num_matches;
     244                 :            : }
     245                 :            : 
     246                 :            : uint32_t
     247                 :         10 : rte_member_lookup_multi_ht(const struct rte_member_setsum *ss,
     248                 :            :                 const void *key, uint32_t match_per_key,
     249                 :            :                 member_set_t *set_id)
     250                 :            : {
     251                 :         10 :         uint32_t num_matches = 0;
     252                 :            :         uint32_t prim_bucket, sec_bucket;
     253                 :            :         member_sig_t tmp_sig;
     254                 :         10 :         struct member_ht_bucket *buckets = ss->table;
     255                 :            : 
     256                 :         10 :         get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
     257                 :            : 
     258         [ +  - ]:         10 :         switch (ss->sig_cmp_fn) {
     259                 :            : #if defined(RTE_ARCH_X86) && defined(__AVX2__)
     260                 :         10 :         case RTE_MEMBER_COMPARE_AVX2:
     261                 :         10 :                 search_bucket_multi_avx(prim_bucket, tmp_sig, buckets,
     262                 :            :                         &num_matches, match_per_key, set_id);
     263         [ +  - ]:         10 :                 if (num_matches < match_per_key)
     264                 :         10 :                         search_bucket_multi_avx(sec_bucket, tmp_sig,
     265                 :            :                                 buckets, &num_matches, match_per_key, set_id);
     266                 :         10 :                 return num_matches;
     267                 :            : #endif
     268                 :          0 :         default:
     269                 :          0 :                 search_bucket_multi(prim_bucket, tmp_sig, buckets, &num_matches,
     270                 :            :                                  match_per_key, set_id);
     271         [ #  # ]:          0 :                 if (num_matches < match_per_key)
     272                 :          0 :                         search_bucket_multi(sec_bucket, tmp_sig,
     273                 :            :                                 buckets, &num_matches, match_per_key, set_id);
     274                 :          0 :                 return num_matches;
     275                 :            :         }
     276                 :            : }
     277                 :            : 
     278                 :            : uint32_t
     279                 :          2 : rte_member_lookup_multi_bulk_ht(const struct rte_member_setsum *ss,
     280                 :            :                 const void **keys, uint32_t num_keys, uint32_t match_per_key,
     281                 :            :                 uint32_t *match_count,
     282                 :            :                 member_set_t *set_ids)
     283                 :            : {
     284                 :            :         uint32_t i;
     285                 :            :         uint32_t num_matches = 0;
     286                 :          2 :         struct member_ht_bucket *buckets = ss->table;
     287                 :            :         uint32_t match_cnt_tmp;
     288                 :            :         member_sig_t tmp_sig[RTE_MEMBER_LOOKUP_BULK_MAX];
     289                 :            :         uint32_t prim_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
     290                 :            :         uint32_t sec_buckets[RTE_MEMBER_LOOKUP_BULK_MAX];
     291                 :            : 
     292         [ +  + ]:         12 :         for (i = 0; i < num_keys; i++) {
     293                 :         10 :                 get_buckets_index(ss, keys[i], &prim_buckets[i],
     294                 :            :                                 &sec_buckets[i], &tmp_sig[i]);
     295                 :         10 :                 rte_prefetch0(&buckets[prim_buckets[i]]);
     296                 :         10 :                 rte_prefetch0(&buckets[sec_buckets[i]]);
     297                 :            :         }
     298         [ +  + ]:         12 :         for (i = 0; i < num_keys; i++) {
     299                 :         10 :                 match_cnt_tmp = 0;
     300                 :            : 
     301         [ +  - ]:         10 :                 switch (ss->sig_cmp_fn) {
     302                 :            : #if defined(RTE_ARCH_X86) && defined(__AVX2__)
     303                 :         10 :                 case RTE_MEMBER_COMPARE_AVX2:
     304                 :         10 :                         search_bucket_multi_avx(prim_buckets[i], tmp_sig[i],
     305                 :            :                                 buckets, &match_cnt_tmp, match_per_key,
     306                 :         10 :                                 &set_ids[i*match_per_key]);
     307         [ +  - ]:         10 :                         if (match_cnt_tmp < match_per_key)
     308                 :         10 :                                 search_bucket_multi_avx(sec_buckets[i],
     309                 :         10 :                                         tmp_sig[i], buckets, &match_cnt_tmp,
     310                 :            :                                         match_per_key,
     311                 :            :                                         &set_ids[i*match_per_key]);
     312                 :         10 :                         match_count[i] = match_cnt_tmp;
     313         [ +  - ]:         10 :                         if (match_cnt_tmp != 0)
     314                 :         10 :                                 num_matches++;
     315                 :            :                         break;
     316                 :            : #endif
     317                 :          0 :                 default:
     318                 :          0 :                         search_bucket_multi(prim_buckets[i], tmp_sig[i],
     319                 :            :                                 buckets, &match_cnt_tmp, match_per_key,
     320                 :          0 :                                 &set_ids[i*match_per_key]);
     321         [ #  # ]:          0 :                         if (match_cnt_tmp < match_per_key)
     322                 :          0 :                                 search_bucket_multi(sec_buckets[i], tmp_sig[i],
     323                 :            :                                         buckets, &match_cnt_tmp, match_per_key,
     324                 :            :                                         &set_ids[i*match_per_key]);
     325                 :          0 :                         match_count[i] = match_cnt_tmp;
     326         [ #  # ]:          0 :                         if (match_cnt_tmp != 0)
     327                 :          0 :                                 num_matches++;
     328                 :            :                 }
     329                 :            :         }
     330                 :          2 :         return num_matches;
     331                 :            : }
     332                 :            : 
     333                 :            : static inline int
     334                 :     231157 : try_insert(struct member_ht_bucket *buckets, uint32_t prim, uint32_t sec,
     335                 :            :                 member_sig_t sig, member_set_t set_id)
     336                 :            : {
     337                 :            :         int i;
     338                 :            :         /* If not full then insert into one slot */
     339         [ +  + ]:    1942727 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
     340         [ +  + ]:    1916180 :                 if (buckets[prim].sets[i] == RTE_MEMBER_NO_MATCH) {
     341                 :     204610 :                         buckets[prim].sigs[i] = sig;
     342                 :     204610 :                         buckets[prim].sets[i] = set_id;
     343                 :     204610 :                         return 0;
     344                 :            :                 }
     345                 :            :         }
     346                 :            :         /* If prim failed, we need to access second bucket */
     347         [ +  + ]:     396417 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
     348         [ +  + ]:     382821 :                 if (buckets[sec].sets[i] == RTE_MEMBER_NO_MATCH) {
     349                 :      12951 :                         buckets[sec].sigs[i] = sig;
     350                 :      12951 :                         buckets[sec].sets[i] = set_id;
     351                 :      12951 :                         return 0;
     352                 :            :                 }
     353                 :            :         }
     354                 :            :         return -1;
     355                 :            : }
     356                 :            : 
     357                 :            : static inline int
     358                 :     107595 : try_update(struct member_ht_bucket *buckets, uint32_t prim, uint32_t sec,
     359                 :            :                 member_sig_t sig, member_set_t set_id,
     360                 :            :                 enum rte_member_sig_compare_function cmp_fn)
     361                 :            : {
     362         [ +  - ]:     107595 :         switch (cmp_fn) {
     363                 :            : #if defined(RTE_ARCH_X86) && defined(__AVX2__)
     364         [ +  + ]:     107595 :         case RTE_MEMBER_COMPARE_AVX2:
     365                 :            :                 if (update_entry_search_avx(prim, sig, buckets, set_id) ||
     366                 :            :                                 update_entry_search_avx(sec, sig, buckets,
     367                 :            :                                         set_id))
     368                 :      71741 :                         return 0;
     369                 :            :                 break;
     370                 :            : #endif
     371                 :            :         default:
     372                 :            :                 if (update_entry_search(prim, sig, buckets, set_id) ||
     373                 :            :                                 update_entry_search(sec, sig, buckets,
     374                 :            :                                         set_id))
     375                 :          0 :                         return 0;
     376                 :            :         }
     377                 :            :         return -1;
     378                 :            : }
     379                 :            : 
     380                 :            : static inline int
     381                 :            : evict_from_bucket(void)
     382                 :            : {
     383                 :            :         /* For now, we randomly pick one entry to evict */
     384                 :          3 :         return rte_rand() & (RTE_MEMBER_BUCKET_ENTRIES - 1);
     385                 :            : }
     386                 :            : 
     387                 :            : /*
     388                 :            :  * This function is similar to the cuckoo hash make_space function in hash
     389                 :            :  * library
     390                 :            :  */
     391                 :            : static inline int
     392                 :      17208 : make_space_bucket(const struct rte_member_setsum *ss, uint32_t bkt_idx,
     393                 :            :                         unsigned int *nr_pushes)
     394                 :            : {
     395                 :            :         unsigned int i, j;
     396                 :            :         int ret;
     397                 :      17208 :         struct member_ht_bucket *buckets = ss->table;
     398                 :            :         uint32_t next_bucket_idx;
     399                 :            :         struct member_ht_bucket *next_bkt[RTE_MEMBER_BUCKET_ENTRIES];
     400                 :      17208 :         struct member_ht_bucket *bkt = &buckets[bkt_idx];
     401                 :            :         /* MSB is set to indicate if an entry has been already pushed */
     402                 :            :         member_set_t flag_mask = 1U << (sizeof(member_set_t) * 8 - 1);
     403                 :            : 
     404                 :            :         /*
     405                 :            :          * Push existing item (search for bucket with space in
     406                 :            :          * alternative locations) to its alternative location
     407                 :            :          */
     408         [ +  + ]:     125199 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
     409                 :            :                 /* Search for space in alternative locations */
     410                 :     121581 :                 next_bucket_idx = (bkt->sigs[i] ^ bkt_idx) & ss->bucket_mask;
     411                 :     121581 :                 next_bkt[i] = &buckets[next_bucket_idx];
     412         [ +  + ]:    2023350 :                 for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++) {
     413         [ +  + ]:    1915359 :                         if (next_bkt[i]->sets[j] == RTE_MEMBER_NO_MATCH)
     414                 :            :                                 break;
     415                 :            :                 }
     416                 :            : 
     417         [ +  + ]:     121581 :                 if (j != RTE_MEMBER_BUCKET_ENTRIES)
     418                 :            :                         break;
     419                 :            :         }
     420                 :            : 
     421                 :            :         /* Alternative location has spare room (end of recursive function) */
     422         [ +  + ]:      17208 :         if (i != RTE_MEMBER_BUCKET_ENTRIES) {
     423                 :      13590 :                 next_bkt[i]->sigs[j] = bkt->sigs[i];
     424                 :      13590 :                 next_bkt[i]->sets[j] = bkt->sets[i];
     425                 :      13590 :                 return i;
     426                 :            :         }
     427                 :            : 
     428                 :            :         /* Pick entry that has not been pushed yet */
     429         [ +  - ]:       3621 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++)
     430         [ +  + ]:       3621 :                 if ((bkt->sets[i] & flag_mask) == 0)
     431                 :            :                         break;
     432                 :            : 
     433                 :            :         /* All entries have been pushed, so entry cannot be added */
     434         [ +  - ]:       3618 :         if (i == RTE_MEMBER_BUCKET_ENTRIES ||
     435         [ +  + ]:       3618 :                         ++(*nr_pushes) > RTE_MEMBER_MAX_PUSHES)
     436                 :          3 :                 return -ENOSPC;
     437                 :            : 
     438                 :       3615 :         next_bucket_idx = (bkt->sigs[i] ^ bkt_idx) & ss->bucket_mask;
     439                 :            :         /* Set flag to indicate that this entry is going to be pushed */
     440                 :       3615 :         bkt->sets[i] |= flag_mask;
     441                 :            : 
     442                 :            :         /* Need room in alternative bucket to insert the pushed entry */
     443                 :       3615 :         ret = make_space_bucket(ss, next_bucket_idx, nr_pushes);
     444                 :            :         /*
     445                 :            :          * After recursive function.
     446                 :            :          * Clear flags and insert the pushed entry
     447                 :            :          * in its alternative location if successful,
     448                 :            :          * or return error
     449                 :            :          */
     450                 :       3615 :         bkt->sets[i] &= ~flag_mask;
     451         [ +  + ]:       3615 :         if (ret >= 0) {
     452                 :       3465 :                 next_bkt[i]->sigs[ret] = bkt->sigs[i];
     453                 :       3465 :                 next_bkt[i]->sets[ret] = bkt->sets[i];
     454                 :       3465 :                 return i;
     455                 :            :         } else
     456                 :            :                 return ret;
     457                 :            : }
     458                 :            : 
     459                 :            : int
     460                 :     302898 : rte_member_add_ht(const struct rte_member_setsum *ss,
     461                 :            :                 const void *key, member_set_t set_id)
     462                 :            : {
     463                 :            :         int ret;
     464                 :     302898 :         unsigned int nr_pushes = 0;
     465                 :            :         uint32_t prim_bucket, sec_bucket;
     466                 :            :         member_sig_t tmp_sig;
     467                 :     302898 :         struct member_ht_bucket *buckets = ss->table;
     468                 :            :         member_set_t flag_mask = 1U << (sizeof(member_set_t) * 8 - 1);
     469                 :            : 
     470   [ +  -  +  - ]:     302898 :         if (set_id == RTE_MEMBER_NO_MATCH || (set_id & flag_mask) != 0)
     471                 :            :                 return -EINVAL;
     472                 :            : 
     473                 :     302898 :         get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
     474                 :            : 
     475                 :            :         /*
     476                 :            :          * If it is cache based setsummary, we try overwriting (updating)
     477                 :            :          * existing entry with the same signature first. In cache mode, we allow
     478                 :            :          * false negatives and only cache the most recent keys.
     479                 :            :          *
     480                 :            :          * For non-cache mode, we do not update existing entry with the same
     481                 :            :          * signature. This is because if two keys with same signature update
     482                 :            :          * each other, false negative may happen, which is not the expected
     483                 :            :          * behavior for non-cache setsummary.
     484                 :            :          */
     485         [ +  + ]:     302898 :         if (ss->cache) {
     486                 :     107595 :                 ret = try_update(buckets, prim_bucket, sec_bucket, tmp_sig,
     487                 :     107595 :                                         set_id, ss->sig_cmp_fn);
     488         [ +  + ]:     107595 :                 if (ret != -1)
     489                 :            :                         return ret;
     490                 :            :         }
     491                 :            :         /* If not full then insert into one slot */
     492                 :     231157 :         ret = try_insert(buckets, prim_bucket, sec_bucket, tmp_sig, set_id);
     493         [ +  + ]:     231157 :         if (ret != -1)
     494                 :            :                 return ret;
     495                 :            : 
     496                 :            :         /* Random pick prim or sec for recursive displacement */
     497         [ +  + ]:      13596 :         uint32_t select_bucket = (tmp_sig & 1U) ? prim_bucket : sec_bucket;
     498         [ +  + ]:      13596 :         if (ss->cache) {
     499                 :            :                 ret = evict_from_bucket();
     500                 :          3 :                 buckets[select_bucket].sigs[ret] = tmp_sig;
     501                 :          3 :                 buckets[select_bucket].sets[ret] = set_id;
     502                 :          3 :                 return 1;
     503                 :            :         }
     504                 :            : 
     505                 :      13593 :         ret = make_space_bucket(ss, select_bucket, &nr_pushes);
     506         [ +  + ]:      13593 :         if (ret >= 0) {
     507                 :      13590 :                 buckets[select_bucket].sigs[ret] = tmp_sig;
     508                 :      13590 :                 buckets[select_bucket].sets[ret] = set_id;
     509                 :            :                 ret = 1;
     510                 :            :         }
     511                 :            : 
     512                 :            :         return ret;
     513                 :            : }
     514                 :            : 
     515                 :            : void
     516                 :          5 : rte_member_free_ht(struct rte_member_setsum *ss)
     517                 :            : {
     518                 :          5 :         rte_free(ss->table);
     519                 :          5 : }
     520                 :            : 
     521                 :            : int
     522                 :         10 : rte_member_delete_ht(const struct rte_member_setsum *ss, const void *key,
     523                 :            :                 member_set_t set_id)
     524                 :            : {
     525                 :            :         int i;
     526                 :            :         uint32_t prim_bucket, sec_bucket;
     527                 :            :         member_sig_t tmp_sig;
     528                 :         10 :         struct member_ht_bucket *buckets = ss->table;
     529                 :            : 
     530                 :         10 :         get_buckets_index(ss, key, &prim_bucket, &sec_bucket, &tmp_sig);
     531                 :            : 
     532         [ +  - ]:         10 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
     533         [ +  - ]:         10 :                 if (tmp_sig == buckets[prim_bucket].sigs[i] &&
     534         [ +  - ]:         10 :                                 set_id == buckets[prim_bucket].sets[i]) {
     535                 :         10 :                         buckets[prim_bucket].sets[i] = RTE_MEMBER_NO_MATCH;
     536                 :         10 :                         return 0;
     537                 :            :                 }
     538                 :            :         }
     539                 :            : 
     540         [ #  # ]:          0 :         for (i = 0; i < RTE_MEMBER_BUCKET_ENTRIES; i++) {
     541         [ #  # ]:          0 :                 if (tmp_sig == buckets[sec_bucket].sigs[i] &&
     542         [ #  # ]:          0 :                                 set_id == buckets[sec_bucket].sets[i]) {
     543                 :          0 :                         buckets[sec_bucket].sets[i] = RTE_MEMBER_NO_MATCH;
     544                 :          0 :                         return 0;
     545                 :            :                 }
     546                 :            :         }
     547                 :            :         return -ENOENT;
     548                 :            : }
     549                 :            : 
     550                 :            : void
     551                 :          6 : rte_member_reset_ht(const struct rte_member_setsum *ss)
     552                 :            : {
     553                 :            :         uint32_t i, j;
     554                 :          6 :         struct member_ht_bucket *buckets = ss->table;
     555                 :            : 
     556         [ +  + ]:      24582 :         for (i = 0; i < ss->bucket_cnt; i++) {
     557         [ +  + ]:     417792 :                 for (j = 0; j < RTE_MEMBER_BUCKET_ENTRIES; j++)
     558                 :     393216 :                         buckets[i].sets[j] = RTE_MEMBER_NO_MATCH;
     559                 :            :         }
     560                 :          6 : }

Generated by: LCOV version 1.14