blob: 2884fa81cf91ddf180693074a5070bb828a80e23 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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 Barachc3799992016-08-15 11:12:27 -040027typedef struct
28{
Ed Warnickecb9cada2015-12-08 15:45:58 -070029 /* 3 x 16 = 48 key bytes */
Dave Barachc3799992016-08-15 11:12:27 -040030 union
31 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070032 u32x4 k_u32x4[3];
Dave Barachc3799992016-08-15 11:12:27 -040033 u64 k_u64[6];
Ed Warnickecb9cada2015-12-08 15:45:58 -070034 } kb;
35 /* 3 x 4 = 12 value bytes */
36 u32 values[3];
37 u32 pad;
38} pfhash_kv_16_t;
39
Dave Barachc3799992016-08-15 11:12:27 -040040typedef struct
41{
Ed Warnickecb9cada2015-12-08 15:45:58 -070042 /* 5 x 8 = 40 key bytes */
Dave Barachc3799992016-08-15 11:12:27 -040043 union
44 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070045 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 Barachc3799992016-08-15 11:12:27 -040053typedef struct
54{
Ed Warnickecb9cada2015-12-08 15:45:58 -070055 /* 4 x 8 = 32 key bytes */
Dave Barachc3799992016-08-15 11:12:27 -040056 union
57 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070058 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 Barachc3799992016-08-15 11:12:27 -040065typedef struct
66{
Ed Warnickecb9cada2015-12-08 15:45:58 -070067 /* 8 x 4 = 32 key bytes */
Dave Barachc3799992016-08-15 11:12:27 -040068 union
69 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070070 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 Barachc3799992016-08-15 11:12:27 -040078typedef union
79{
Ed Warnickecb9cada2015-12-08 15:45:58 -070080 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 Barachc3799992016-08-15 11:12:27 -040086typedef struct
87{
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 /* Bucket vector */
Dave Barachc3799992016-08-15 11:12:27 -040089 u32 *buckets;
Ed Warnickecb9cada2015-12-08 15:45:58 -070090#define PFHASH_BUCKET_OVERFLOW (u32)~0
91
92 /* Pool of key/value pairs */
Dave Barachc3799992016-08-15 11:12:27 -040093 pfhash_kv_t *kvp;
94
Ed Warnickecb9cada2015-12-08 15:45:58 -070095 /* overflow plain-o-hash */
Dave Barachc3799992016-08-15 11:12:27 -040096 uword *overflow_hash;
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
98 /* Pretty-print name */
Dave Barachc3799992016-08-15 11:12:27 -040099 u8 *name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
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 Barachc3799992016-08-15 11:12:27 -0400109void pfhash_init (pfhash_t * p, char *name, u32 key_size, u32 value_size,
110 u32 nbuckets);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111void pfhash_free (pfhash_t * p);
Dave Barachc3799992016-08-15 11:12:27 -0400112u64 pfhash_get (pfhash_t * p, u32 bucket, void *key);
113void pfhash_set (pfhash_t * p, u32 bucket, void *key, void *value);
114void pfhash_unset (pfhash_t * p, u32 bucket, void *key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
116format_function_t format_pfhash;
117
Dave Barachc3799992016-08-15 11:12:27 -0400118static inline void
119pfhash_prefetch_bucket (pfhash_t * p, u32 bucket)
120{
121 CLIB_PREFETCH (&p->buckets[bucket], CLIB_CACHE_LINE_BYTES, LOAD);
122}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Dave Barachc3799992016-08-15 11:12:27 -0400124static inline u32
125pfhash_read_bucket_prefetch_kv (pfhash_t * p, u32 bucket)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126{
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 Barachc3799992016-08-15 11:12:27 -0400133/*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 * 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 Barachc3799992016-08-15 11:12:27 -0400137 *
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 * 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 Barachc3799992016-08-15 11:12:27 -0400142static inline u32
143pfhash_search_kv_16 (pfhash_t * p, u32 bucket_contents, u32x4 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144{
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 Barachc3799992016-08-15 11:12:27 -0400153 uword *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 hp = hash_get_mem (p->overflow_hash, key);
155 if (hp)
Dave Barachc3799992016-08-15 11:12:27 -0400156 return hp[0];
157 return (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 }
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 Barachc3799992016-08-15 11:12:27 -0400165
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 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 Barachc3799992016-08-15 11:12:27 -0400173
174 rv = (is_equal0 & kv->values[0])
175 | (is_equal1 & kv->values[1]) | (is_equal2 & kv->values[2]) | no_match;
176
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 return rv;
178}
179
Dave Barachc3799992016-08-15 11:12:27 -0400180static inline u32
181pfhash_search_kv_8 (pfhash_t * p, u32 bucket_contents, u64 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182{
183 pfhash_kv_8_t *kv;
Dave Barachc3799992016-08-15 11:12:27 -0400184 u32 rv = (u32) ~ 0;
185
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
187 {
Dave Barachc3799992016-08-15 11:12:27 -0400188 uword *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 hp = hash_get_mem (p->overflow_hash, key);
190 if (hp)
Dave Barachc3799992016-08-15 11:12:27 -0400191 return hp[0];
192 return (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 }
Dave Barachc3799992016-08-15 11:12:27 -0400194
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 kv = &p->kvp[bucket_contents].kv8;
Dave Barachc3799992016-08-15 11:12:27 -0400196
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 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 Barachc3799992016-08-15 11:12:27 -0400202
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 return rv;
204}
205
Dave Barachc3799992016-08-15 11:12:27 -0400206static inline u64
207pfhash_search_kv_8v8 (pfhash_t * p, u32 bucket_contents, u64 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208{
209 pfhash_kv_8v8_t *kv;
Dave Barachc3799992016-08-15 11:12:27 -0400210 u64 rv = (u64) ~ 0;
211
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
213 {
Dave Barachc3799992016-08-15 11:12:27 -0400214 uword *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 hp = hash_get_mem (p->overflow_hash, key);
216 if (hp)
Dave Barachc3799992016-08-15 11:12:27 -0400217 return hp[0];
218 return (u64) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 }
Dave Barachc3799992016-08-15 11:12:27 -0400220
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221 kv = &p->kvp[bucket_contents].kv8v8;
Dave Barachc3799992016-08-15 11:12:27 -0400222
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 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 Barachc3799992016-08-15 11:12:27 -0400227
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 return rv;
229}
230
Dave Barachc3799992016-08-15 11:12:27 -0400231static inline u32
232pfhash_search_kv_4 (pfhash_t * p, u32 bucket_contents, u32 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233{
234 u32x4 vector_key;
235 u32x4 is_equal[2];
236 u32 zbm[2], winner_index;
237 pfhash_kv_4_t *kv;
Dave Barachc3799992016-08-15 11:12:27 -0400238
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
240 {
Dave Barachc3799992016-08-15 11:12:27 -0400241 uword *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 hp = hash_get_mem (p->overflow_hash, key);
243 if (hp)
Dave Barachc3799992016-08-15 11:12:27 -0400244 return hp[0];
245 return (u32) ~ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 }
Dave Barachc3799992016-08-15 11:12:27 -0400247
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 kv = &p->kvp[bucket_contents].kv4;
Dave Barachc3799992016-08-15 11:12:27 -0400249
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 vector_key = u32x4_splat (key[0]);
Dave Barachc3799992016-08-15 11:12:27 -0400251
Damjan Mariona52e1662018-05-19 00:04:23 +0200252 is_equal[0] = (kv->kb.k_u32x4[0] == vector_key);
253 is_equal[1] = (kv->kb.k_u32x4[1] == vector_key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 zbm[0] = ~u32x4_zero_byte_mask (is_equal[0]) & 0xFFFF;
255 zbm[1] = ~u32x4_zero_byte_mask (is_equal[1]) & 0xFFFF;
Dave Barachc3799992016-08-15 11:12:27 -0400256
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 Warnickecb9cada2015-12-08 15:45:58 -0700263 return kv->values[winner_index];
264}
265
266#endif /* CLIB_HAVE_VEC128 */
267
268#endif /* included_clib_pfhash_h */
Dave Barachc3799992016-08-15 11:12:27 -0400269
270/*
271 * fd.io coding-style-patch-verification: ON
272 *
273 * Local Variables:
274 * eval: (c-set-style "gnu")
275 * End:
276 */