053d093524
Type: improvement Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: Id28299a188feefa1899d835fd499f018af95d81b
277 lines
6.3 KiB
C
277 lines
6.3 KiB
C
/*
|
|
Copyright (c) 2013 Cisco and/or its affiliates.
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef included_clib_pfhash_h
|
|
#define included_clib_pfhash_h
|
|
|
|
|
|
#include <vppinfra/clib.h>
|
|
#include <vppinfra/hash.h>
|
|
#include <vppinfra/pool.h>
|
|
|
|
#if defined(CLIB_HAVE_VEC128) && ! defined (__ALTIVEC__)
|
|
|
|
typedef struct
|
|
{
|
|
/* 3 x 16 = 48 key bytes */
|
|
union
|
|
{
|
|
u32x4 k_u32x4[3];
|
|
u64 k_u64[6];
|
|
} kb;
|
|
/* 3 x 4 = 12 value bytes */
|
|
u32 values[3];
|
|
u32 pad;
|
|
} pfhash_kv_16_t;
|
|
|
|
typedef struct
|
|
{
|
|
/* 5 x 8 = 40 key bytes */
|
|
union
|
|
{
|
|
u64 k_u64[5];
|
|
} kb;
|
|
|
|
/* 5 x 4 = 20 value bytes */
|
|
u32 values[5];
|
|
u32 pad;
|
|
} pfhash_kv_8_t;
|
|
|
|
typedef struct
|
|
{
|
|
/* 4 x 8 = 32 key bytes */
|
|
union
|
|
{
|
|
u64 k_u64[4];
|
|
} kb;
|
|
|
|
/* 4 x 8 = 32 value bytes */
|
|
u64 values[4];
|
|
} pfhash_kv_8v8_t;
|
|
|
|
typedef struct
|
|
{
|
|
/* 8 x 4 = 32 key bytes */
|
|
union
|
|
{
|
|
u32x4 k_u32x4[2];
|
|
u32 kb[8];
|
|
} kb;
|
|
|
|
/* 8 x 4 = 32 value bytes */
|
|
u32 values[8];
|
|
} pfhash_kv_4_t;
|
|
|
|
typedef union
|
|
{
|
|
pfhash_kv_16_t kv16;
|
|
pfhash_kv_8_t kv8;
|
|
pfhash_kv_8v8_t kv8v8;
|
|
pfhash_kv_4_t kv4;
|
|
} pfhash_kv_t;
|
|
|
|
typedef struct
|
|
{
|
|
/* Bucket vector */
|
|
u32 *buckets;
|
|
#define PFHASH_BUCKET_OVERFLOW (u32)~0
|
|
|
|
/* Pool of key/value pairs */
|
|
pfhash_kv_t *kvp;
|
|
|
|
/* overflow plain-o-hash */
|
|
uword *overflow_hash;
|
|
|
|
/* Pretty-print name */
|
|
u8 *name;
|
|
|
|
u32 key_size;
|
|
u32 value_size;
|
|
|
|
u32 overflow_count;
|
|
u32 nitems;
|
|
u32 nitems_in_overflow;
|
|
} pfhash_t;
|
|
|
|
void pfhash_init (pfhash_t * p, char *name, u32 key_size, u32 value_size,
|
|
u32 nbuckets);
|
|
void pfhash_free (pfhash_t * p);
|
|
u64 pfhash_get (pfhash_t * p, u32 bucket, void *key);
|
|
void pfhash_set (pfhash_t * p, u32 bucket, void *key, void *value);
|
|
void pfhash_unset (pfhash_t * p, u32 bucket, void *key);
|
|
|
|
format_function_t format_pfhash;
|
|
|
|
static inline void
|
|
pfhash_prefetch_bucket (pfhash_t * p, u32 bucket)
|
|
{
|
|
CLIB_PREFETCH (&p->buckets[bucket], CLIB_CACHE_LINE_BYTES, LOAD);
|
|
}
|
|
|
|
static inline u32
|
|
pfhash_read_bucket_prefetch_kv (pfhash_t * p, u32 bucket)
|
|
{
|
|
u32 bucket_contents = p->buckets[bucket];
|
|
if (PREDICT_TRUE ((bucket_contents & PFHASH_BUCKET_OVERFLOW) == 0))
|
|
CLIB_PREFETCH (&p->kvp[bucket_contents], CLIB_CACHE_LINE_BYTES, LOAD);
|
|
return bucket_contents;
|
|
}
|
|
|
|
/*
|
|
* pfhash_search_kv_16
|
|
* See if the supplied 16-byte key matches one of three 16-byte (key,value) pairs.
|
|
* Return the indicated value, or ~0 if no match
|
|
*
|
|
* Note: including the overflow test, the fast path is 35 instrs
|
|
* on x86_64. Elves will steal your keyboard in the middle of the night if
|
|
* you "improve" it without checking the generated code!
|
|
*/
|
|
static inline u32
|
|
pfhash_search_kv_16 (pfhash_t * p, u32 bucket_contents, u32x4 * key)
|
|
{
|
|
u32x4 diff0, diff1, diff2;
|
|
u32 is_equal0, is_equal1, is_equal2;
|
|
u32 no_match;
|
|
pfhash_kv_16_t *kv;
|
|
u32 rv;
|
|
|
|
if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
|
|
{
|
|
uword *hp;
|
|
hp = hash_get_mem (p->overflow_hash, key);
|
|
if (hp)
|
|
return hp[0];
|
|
return (u32) ~ 0;
|
|
}
|
|
|
|
kv = &p->kvp[bucket_contents].kv16;
|
|
|
|
diff0 = u32x4_sub (kv->kb.k_u32x4[0], key[0]);
|
|
diff1 = u32x4_sub (kv->kb.k_u32x4[1], key[0]);
|
|
diff2 = u32x4_sub (kv->kb.k_u32x4[2], key[0]);
|
|
|
|
no_match = is_equal0 = (i16) u32x4_zero_byte_mask (diff0);
|
|
is_equal1 = (i16) u32x4_zero_byte_mask (diff1);
|
|
no_match |= is_equal1;
|
|
is_equal2 = (i16) u32x4_zero_byte_mask (diff2);
|
|
no_match |= is_equal2;
|
|
/* If any of the three items matched, no_match will be zero after this line */
|
|
no_match = ~no_match;
|
|
|
|
rv = (is_equal0 & kv->values[0])
|
|
| (is_equal1 & kv->values[1]) | (is_equal2 & kv->values[2]) | no_match;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static inline u32
|
|
pfhash_search_kv_8 (pfhash_t * p, u32 bucket_contents, u64 * key)
|
|
{
|
|
pfhash_kv_8_t *kv;
|
|
u32 rv = (u32) ~ 0;
|
|
|
|
if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
|
|
{
|
|
uword *hp;
|
|
hp = hash_get_mem (p->overflow_hash, key);
|
|
if (hp)
|
|
return hp[0];
|
|
return (u32) ~ 0;
|
|
}
|
|
|
|
kv = &p->kvp[bucket_contents].kv8;
|
|
|
|
rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv;
|
|
rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv;
|
|
rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv;
|
|
rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv;
|
|
rv = (kv->kb.k_u64[4] == key[0]) ? kv->values[4] : rv;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static inline u64
|
|
pfhash_search_kv_8v8 (pfhash_t * p, u32 bucket_contents, u64 * key)
|
|
{
|
|
pfhash_kv_8v8_t *kv;
|
|
u64 rv = (u64) ~ 0;
|
|
|
|
if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
|
|
{
|
|
uword *hp;
|
|
hp = hash_get_mem (p->overflow_hash, key);
|
|
if (hp)
|
|
return hp[0];
|
|
return (u64) ~ 0;
|
|
}
|
|
|
|
kv = &p->kvp[bucket_contents].kv8v8;
|
|
|
|
rv = (kv->kb.k_u64[0] == key[0]) ? kv->values[0] : rv;
|
|
rv = (kv->kb.k_u64[1] == key[0]) ? kv->values[1] : rv;
|
|
rv = (kv->kb.k_u64[2] == key[0]) ? kv->values[2] : rv;
|
|
rv = (kv->kb.k_u64[3] == key[0]) ? kv->values[3] : rv;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static inline u32
|
|
pfhash_search_kv_4 (pfhash_t * p, u32 bucket_contents, u32 * key)
|
|
{
|
|
u32x4 vector_key;
|
|
u32x4 is_equal[2];
|
|
u32 zbm[2], winner_index;
|
|
pfhash_kv_4_t *kv;
|
|
|
|
if (PREDICT_FALSE (bucket_contents == PFHASH_BUCKET_OVERFLOW))
|
|
{
|
|
uword *hp;
|
|
hp = hash_get_mem (p->overflow_hash, key);
|
|
if (hp)
|
|
return hp[0];
|
|
return (u32) ~ 0;
|
|
}
|
|
|
|
kv = &p->kvp[bucket_contents].kv4;
|
|
|
|
vector_key = u32x4_splat (key[0]);
|
|
|
|
is_equal[0] = (kv->kb.k_u32x4[0] == vector_key);
|
|
is_equal[1] = (kv->kb.k_u32x4[1] == vector_key);
|
|
zbm[0] = ~u32x4_zero_byte_mask (is_equal[0]) & 0xFFFF;
|
|
zbm[1] = ~u32x4_zero_byte_mask (is_equal[1]) & 0xFFFF;
|
|
|
|
if (PREDICT_FALSE ((zbm[0] == 0) && (zbm[1] == 0)))
|
|
return (u32) ~ 0;
|
|
|
|
winner_index = min_log2 (zbm[0]) >> 2;
|
|
winner_index = zbm[1] ? (4 + (min_log2 (zbm[1]) >> 2)) : winner_index;
|
|
|
|
return kv->values[winner_index];
|
|
}
|
|
|
|
#endif /* CLIB_HAVE_VEC128 */
|
|
|
|
#endif /* included_clib_pfhash_h */
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|