Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 1 | /* |
| 2 | Copyright (c) 2013 Cisco and/or its affiliates. |
| 3 | |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at: |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef included_clib_pfhash_h |
| 18 | #define included_clib_pfhash_h |
| 19 | |
| 20 | |
| 21 | #include <vppinfra/clib.h> |
| 22 | #include <vppinfra/hash.h> |
| 23 | #include <vppinfra/pool.h> |
| 24 | |
| 25 | #if defined(CLIB_HAVE_VEC128) && ! defined (__ALTIVEC__) |
| 26 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 27 | typedef struct |
| 28 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 29 | /* 3 x 16 = 48 key bytes */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 30 | union |
| 31 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 32 | u32x4 k_u32x4[3]; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 33 | u64 k_u64[6]; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 34 | } kb; |
| 35 | /* 3 x 4 = 12 value bytes */ |
| 36 | u32 values[3]; |
| 37 | u32 pad; |
| 38 | } pfhash_kv_16_t; |
| 39 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 40 | typedef struct |
| 41 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 42 | /* 5 x 8 = 40 key bytes */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 43 | union |
| 44 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 45 | u64 k_u64[5]; |
| 46 | } kb; |
| 47 | |
| 48 | /* 5 x 4 = 20 value bytes */ |
| 49 | u32 values[5]; |
| 50 | u32 pad; |
| 51 | } pfhash_kv_8_t; |
| 52 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 53 | typedef struct |
| 54 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 55 | /* 4 x 8 = 32 key bytes */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 56 | union |
| 57 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 58 | u64 k_u64[4]; |
| 59 | } kb; |
| 60 | |
| 61 | /* 4 x 8 = 32 value bytes */ |
| 62 | u64 values[4]; |
| 63 | } pfhash_kv_8v8_t; |
| 64 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 65 | typedef struct |
| 66 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 67 | /* 8 x 4 = 32 key bytes */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 68 | union |
| 69 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 70 | u32x4 k_u32x4[2]; |
| 71 | u32 kb[8]; |
| 72 | } kb; |
| 73 | |
| 74 | /* 8 x 4 = 32 value bytes */ |
| 75 | u32 values[8]; |
| 76 | } pfhash_kv_4_t; |
| 77 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 78 | typedef union |
| 79 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 80 | pfhash_kv_16_t kv16; |
| 81 | pfhash_kv_8_t kv8; |
| 82 | pfhash_kv_8v8_t kv8v8; |
| 83 | pfhash_kv_4_t kv4; |
| 84 | } pfhash_kv_t; |
| 85 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 86 | typedef struct |
| 87 | { |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 88 | /* Bucket vector */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 89 | u32 *buckets; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 90 | #define PFHASH_BUCKET_OVERFLOW (u32)~0 |
| 91 | |
| 92 | /* Pool of key/value pairs */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 93 | pfhash_kv_t *kvp; |
| 94 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 95 | /* overflow plain-o-hash */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 96 | uword *overflow_hash; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 97 | |
| 98 | /* Pretty-print name */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 99 | u8 *name; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 100 | |
| 101 | u32 key_size; |
| 102 | u32 value_size; |
| 103 | |
| 104 | u32 overflow_count; |
| 105 | u32 nitems; |
| 106 | u32 nitems_in_overflow; |
| 107 | } pfhash_t; |
| 108 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 109 | void pfhash_init (pfhash_t * p, char *name, u32 key_size, u32 value_size, |
| 110 | u32 nbuckets); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 111 | void pfhash_free (pfhash_t * p); |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 112 | u64 pfhash_get (pfhash_t * p, u32 bucket, void *key); |
| 113 | void pfhash_set (pfhash_t * p, u32 bucket, void *key, void *value); |
| 114 | void pfhash_unset (pfhash_t * p, u32 bucket, void *key); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 115 | |
| 116 | format_function_t format_pfhash; |
| 117 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 118 | static inline void |
| 119 | pfhash_prefetch_bucket (pfhash_t * p, u32 bucket) |
| 120 | { |
| 121 | CLIB_PREFETCH (&p->buckets[bucket], CLIB_CACHE_LINE_BYTES, LOAD); |
| 122 | } |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 123 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 124 | static inline u32 |
| 125 | pfhash_read_bucket_prefetch_kv (pfhash_t * p, u32 bucket) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 126 | { |
| 127 | u32 bucket_contents = p->buckets[bucket]; |
| 128 | if (PREDICT_TRUE ((bucket_contents & PFHASH_BUCKET_OVERFLOW) == 0)) |
| 129 | CLIB_PREFETCH (&p->kvp[bucket_contents], CLIB_CACHE_LINE_BYTES, LOAD); |
| 130 | return bucket_contents; |
| 131 | } |
| 132 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 133 | /* |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 134 | * pfhash_search_kv_16 |
| 135 | * See if the supplied 16-byte key matches one of three 16-byte (key,value) pairs. |
| 136 | * Return the indicated value, or ~0 if no match |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 137 | * |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 138 | * Note: including the overflow test, the fast path is 35 instrs |
| 139 | * on x86_64. Elves will steal your keyboard in the middle of the night if |
| 140 | * you "improve" it without checking the generated code! |
| 141 | */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 142 | static inline u32 |
| 143 | pfhash_search_kv_16 (pfhash_t * p, u32 bucket_contents, u32x4 * key) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 144 | { |
| 145 | u32x4 diff0, diff1, diff2; |
| 146 | u32 is_equal0, is_equal1, is_equal2; |
| 147 | u32 no_match; |
| 148 | pfhash_kv_16_t *kv; |
| 149 | u32 rv; |
| 150 | |
| 151 | if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW)) |
| 152 | { |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 153 | uword *hp; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 154 | hp = hash_get_mem (p->overflow_hash, key); |
| 155 | if (hp) |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 156 | return hp[0]; |
| 157 | return (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | kv = &p->kvp[bucket_contents].kv16; |
| 161 | |
| 162 | diff0 = u32x4_sub (kv->kb.k_u32x4[0], key[0]); |
| 163 | diff1 = u32x4_sub (kv->kb.k_u32x4[1], key[0]); |
| 164 | diff2 = u32x4_sub (kv->kb.k_u32x4[2], key[0]); |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 165 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 166 | no_match = is_equal0 = (i16) u32x4_zero_byte_mask (diff0); |
| 167 | is_equal1 = (i16) u32x4_zero_byte_mask (diff1); |
| 168 | no_match |= is_equal1; |
| 169 | is_equal2 = (i16) u32x4_zero_byte_mask (diff2); |
| 170 | no_match |= is_equal2; |
| 171 | /* If any of the three items matched, no_match will be zero after this line */ |
| 172 | no_match = ~no_match; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 173 | |
| 174 | rv = (is_equal0 & kv->values[0]) |
| 175 | | (is_equal1 & kv->values[1]) | (is_equal2 & kv->values[2]) | no_match; |
| 176 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 177 | return rv; |
| 178 | } |
| 179 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 180 | static inline u32 |
| 181 | pfhash_search_kv_8 (pfhash_t * p, u32 bucket_contents, u64 * key) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 182 | { |
| 183 | pfhash_kv_8_t *kv; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 184 | u32 rv = (u32) ~ 0; |
| 185 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 186 | if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW)) |
| 187 | { |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 188 | uword *hp; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 189 | hp = hash_get_mem (p->overflow_hash, key); |
| 190 | if (hp) |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 191 | return hp[0]; |
| 192 | return (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 193 | } |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 194 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 195 | kv = &p->kvp[bucket_contents].kv8; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 196 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 197 | rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv; |
| 198 | rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv; |
| 199 | rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv; |
| 200 | rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv; |
| 201 | rv = (kv->kb.k_u64[4] == key[0]) ? kv->values[4] : rv; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 202 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 203 | return rv; |
| 204 | } |
| 205 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 206 | static inline u64 |
| 207 | pfhash_search_kv_8v8 (pfhash_t * p, u32 bucket_contents, u64 * key) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 208 | { |
| 209 | pfhash_kv_8v8_t *kv; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 210 | u64 rv = (u64) ~ 0; |
| 211 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 212 | if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW)) |
| 213 | { |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 214 | uword *hp; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 215 | hp = hash_get_mem (p->overflow_hash, key); |
| 216 | if (hp) |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 217 | return hp[0]; |
| 218 | return (u64) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 219 | } |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 220 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 221 | kv = &p->kvp[bucket_contents].kv8v8; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 222 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 223 | rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv; |
| 224 | rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv; |
| 225 | rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv; |
| 226 | rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 227 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 228 | return rv; |
| 229 | } |
| 230 | |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 231 | static inline u32 |
| 232 | pfhash_search_kv_4 (pfhash_t * p, u32 bucket_contents, u32 * key) |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 233 | { |
| 234 | u32x4 vector_key; |
| 235 | u32x4 is_equal[2]; |
| 236 | u32 zbm[2], winner_index; |
| 237 | pfhash_kv_4_t *kv; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 238 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 239 | if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW)) |
| 240 | { |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 241 | uword *hp; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 242 | hp = hash_get_mem (p->overflow_hash, key); |
| 243 | if (hp) |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 244 | return hp[0]; |
| 245 | return (u32) ~ 0; |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 246 | } |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 247 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 248 | kv = &p->kvp[bucket_contents].kv4; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 249 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 250 | vector_key = u32x4_splat (key[0]); |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 251 | |
Damjan Marion | a52e166 | 2018-05-19 00:04:23 +0200 | [diff] [blame] | 252 | is_equal[0] = (kv->kb.k_u32x4[0] == vector_key); |
| 253 | is_equal[1] = (kv->kb.k_u32x4[1] == vector_key); |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 254 | zbm[0] = ~u32x4_zero_byte_mask (is_equal[0]) & 0xFFFF; |
| 255 | zbm[1] = ~u32x4_zero_byte_mask (is_equal[1]) & 0xFFFF; |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 256 | |
| 257 | if (PREDICT_FALSE ((zbm[0] == 0) && (zbm[1] == 0))) |
| 258 | return (u32) ~ 0; |
| 259 | |
| 260 | winner_index = min_log2 (zbm[0]) >> 2; |
| 261 | winner_index = zbm[1] ? (4 + (min_log2 (zbm[1]) >> 2)) : winner_index; |
| 262 | |
Ed Warnicke | cb9cada | 2015-12-08 15:45:58 -0700 | [diff] [blame] | 263 | return kv->values[winner_index]; |
| 264 | } |
| 265 | |
| 266 | #endif /* CLIB_HAVE_VEC128 */ |
| 267 | |
| 268 | #endif /* included_clib_pfhash_h */ |
Dave Barach | c379999 | 2016-08-15 11:12:27 -0400 | [diff] [blame] | 269 | |
| 270 | /* |
| 271 | * fd.io coding-style-patch-verification: ON |
| 272 | * |
| 273 | * Local Variables: |
| 274 | * eval: (c-set-style "gnu") |
| 275 | * End: |
| 276 | */ |