FD.io VPP  v16.06
Vector Packet Processing
pfhash.h
Go to the documentation of this file.
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 
27 typedef struct {
28  /* 3 x 16 = 48 key bytes */
29  union {
30  u32x4 k_u32x4[3];
31  u64 k_u64[6];
32  } kb;
33  /* 3 x 4 = 12 value bytes */
34  u32 values[3];
35  u32 pad;
36 } pfhash_kv_16_t;
37 
38 typedef struct {
39  /* 5 x 8 = 40 key bytes */
40  union {
41  u64 k_u64[5];
42  } kb;
43 
44  /* 5 x 4 = 20 value bytes */
45  u32 values[5];
46  u32 pad;
47 } pfhash_kv_8_t;
48 
49 typedef struct {
50  /* 4 x 8 = 32 key bytes */
51  union {
52  u64 k_u64[4];
53  } kb;
54 
55  /* 4 x 8 = 32 value bytes */
56  u64 values[4];
57 } pfhash_kv_8v8_t;
58 
59 typedef struct {
60  /* 8 x 4 = 32 key bytes */
61  union {
62  u32x4 k_u32x4[2];
63  u32 kb[8];
64  } kb;
65 
66  /* 8 x 4 = 32 value bytes */
67  u32 values[8];
68 } pfhash_kv_4_t;
69 
70 typedef union {
71  pfhash_kv_16_t kv16;
72  pfhash_kv_8_t kv8;
73  pfhash_kv_8v8_t kv8v8;
74  pfhash_kv_4_t kv4;
75 } pfhash_kv_t;
76 
77 typedef struct {
78  /* Bucket vector */
79  u32 * buckets;
80 #define PFHASH_BUCKET_OVERFLOW (u32)~0
81 
82  /* Pool of key/value pairs */
83  pfhash_kv_t * kvp;
84 
85  /* overflow plain-o-hash */
86  uword * overflow_hash;
87 
88  /* Pretty-print name */
89  u8 * name;
90 
91  u32 key_size;
92  u32 value_size;
93 
94  u32 overflow_count;
95  u32 nitems;
96  u32 nitems_in_overflow;
97 } pfhash_t;
98 
99 void pfhash_init (pfhash_t * p, char * name, u32 key_size, u32 value_size,
100  u32 nbuckets);
101 void pfhash_free (pfhash_t * p);
102 u64 pfhash_get (pfhash_t * p, u32 bucket, void * key);
103 void pfhash_set (pfhash_t * p, u32 bucket, void * key, void * value);
104 void pfhash_unset (pfhash_t * p, u32 bucket, void * key);
105 
106 format_function_t format_pfhash;
107 
108 static inline void pfhash_prefetch_bucket (pfhash_t * p, u32 bucket)
109 { CLIB_PREFETCH (&p->buckets[bucket], CLIB_CACHE_LINE_BYTES, LOAD); }
110 
111 static inline u32 pfhash_read_bucket_prefetch_kv (pfhash_t * p, u32 bucket)
112 {
113  u32 bucket_contents = p->buckets[bucket];
114  if (PREDICT_TRUE ((bucket_contents & PFHASH_BUCKET_OVERFLOW) == 0))
115  CLIB_PREFETCH (&p->kvp[bucket_contents], CLIB_CACHE_LINE_BYTES, LOAD);
116  return bucket_contents;
117 }
118 
119 /*
120  * pfhash_search_kv_16
121  * See if the supplied 16-byte key matches one of three 16-byte (key,value) pairs.
122  * Return the indicated value, or ~0 if no match
123  *
124  * Note: including the overflow test, the fast path is 35 instrs
125  * on x86_64. Elves will steal your keyboard in the middle of the night if
126  * you "improve" it without checking the generated code!
127  */
128 static inline u32 pfhash_search_kv_16 (pfhash_t * p, u32 bucket_contents,
129  u32x4 * key)
130 {
131  u32x4 diff0, diff1, diff2;
132  u32 is_equal0, is_equal1, is_equal2;
133  u32 no_match;
134  pfhash_kv_16_t *kv;
135  u32 rv;
136 
137  if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
138  {
139  uword * hp;
140  hp = hash_get_mem (p->overflow_hash, key);
141  if (hp)
142  return hp[0];
143  return (u32)~0;
144  }
145 
146  kv = &p->kvp[bucket_contents].kv16;
147 
148  diff0 = u32x4_sub (kv->kb.k_u32x4[0], key[0]);
149  diff1 = u32x4_sub (kv->kb.k_u32x4[1], key[0]);
150  diff2 = u32x4_sub (kv->kb.k_u32x4[2], key[0]);
151 
152  no_match = is_equal0 = (i16) u32x4_zero_byte_mask (diff0);
153  is_equal1 = (i16) u32x4_zero_byte_mask (diff1);
154  no_match |= is_equal1;
155  is_equal2 = (i16) u32x4_zero_byte_mask (diff2);
156  no_match |= is_equal2;
157  /* If any of the three items matched, no_match will be zero after this line */
158  no_match = ~no_match;
159 
160  rv = (is_equal0 & kv->values[0])
161  |(is_equal1 & kv->values[1])
162  | (is_equal2 & kv->values[2])
163  | no_match;
164 
165  return rv;
166 }
167 
168 static inline u32 pfhash_search_kv_8 (pfhash_t * p, u32 bucket_contents,
169  u64 * key)
170 {
171  pfhash_kv_8_t *kv;
172  u32 rv = (u32)~0;
173 
174  if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
175  {
176  uword * hp;
177  hp = hash_get_mem (p->overflow_hash, key);
178  if (hp)
179  return hp[0];
180  return (u32)~0;
181  }
182 
183  kv = &p->kvp[bucket_contents].kv8;
184 
185  rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv;
186  rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv;
187  rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv;
188  rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv;
189  rv = (kv->kb.k_u64[4] == key[0]) ? kv->values[4] : rv;
190 
191  return rv;
192 }
193 
194 static inline u64 pfhash_search_kv_8v8 (pfhash_t * p, u32 bucket_contents,
195  u64 * key)
196 {
197  pfhash_kv_8v8_t *kv;
198  u64 rv = (u64)~0;
199 
200  if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
201  {
202  uword * hp;
203  hp = hash_get_mem (p->overflow_hash, key);
204  if (hp)
205  return hp[0];
206  return (u64)~0;
207  }
208 
209  kv = &p->kvp[bucket_contents].kv8v8;
210 
211  rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv;
212  rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv;
213  rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv;
214  rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv;
215 
216  return rv;
217 }
218 
219 static inline u32 pfhash_search_kv_4 (pfhash_t * p, u32 bucket_contents,
220  u32 * key)
221 {
222  u32x4 vector_key;
223  u32x4 is_equal[2];
224  u32 zbm[2], winner_index;
225  pfhash_kv_4_t *kv;
226 
227  if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
228  {
229  uword * hp;
230  hp = hash_get_mem (p->overflow_hash, key);
231  if (hp)
232  return hp[0];
233  return (u32)~0;
234  }
235 
236  kv = &p->kvp[bucket_contents].kv4;
237 
238  vector_key = u32x4_splat (key[0]);
239 
240  is_equal[0] = u32x4_is_equal (kv->kb.k_u32x4[0], vector_key);
241  is_equal[1] = u32x4_is_equal (kv->kb.k_u32x4[1], vector_key);
242  zbm[0] = ~u32x4_zero_byte_mask (is_equal[0]) & 0xFFFF;
243  zbm[1] = ~u32x4_zero_byte_mask (is_equal[1]) & 0xFFFF;
244 
245  if (PREDICT_FALSE((zbm[0] == 0) && (zbm[1] == 0)))
246  return (u32)~0;
247 
248  winner_index = min_log2 (zbm[0])>>2;
249  winner_index = zbm[1] ? (4 + (min_log2 (zbm[1])>>2)) : winner_index;
250 
251  return kv->values[winner_index];
252 }
253 
254 #endif /* CLIB_HAVE_VEC128 */
255 
256 #endif /* included_clib_pfhash_h */
always_inline u32x4 u32x4_is_equal(u32x4 x, u32x4 y)
Definition: vector_sse2.h:392
#define PREDICT_TRUE(x)
Definition: clib.h:98
always_inline u32 u32x4_zero_byte_mask(u32x4 x)
always_inline u32x4 u32x4_splat(u32 a)
Definition: vector_sse2.h:119
unsigned long u64
Definition: types.h:89
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
is_equal
unsigned int u32
Definition: types.h:88
u8 *( format_function_t)(u8 *s, va_list *args)
Definition: format.h:48
u64 uword
Definition: types.h:112
unsigned char u8
Definition: types.h:56
#define hash_get_mem(h, key)
Definition: hash.h:251
short i16
Definition: types.h:46
always_inline uword min_log2(uword x)
Definition: clib.h:181
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67