vppinfra: move unused code to extras/deprecated/vppinfra
Type: improvement Signed-off-by: Dave Barach <dave@barachs.net> Change-Id: Id28299a188feefa1899d835fd499f018af95d81b
This commit is contained in:
committed by
Florin Coras
parent
f932f97d7d
commit
053d093524
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright (c) 2011 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.
|
||||
*/
|
||||
|
||||
#include <vppinfra/anneal.h>
|
||||
|
||||
/*
|
||||
* Optimize an objective function by simulated annealing
|
||||
*
|
||||
* Here are a couple of short, easily-understood
|
||||
* descriptions of simulated annealing:
|
||||
*
|
||||
* http://www.cs.sandia.gov/opt/survey/sa.html
|
||||
* Numerical Recipes in C, 2nd ed., 444ff
|
||||
*
|
||||
* The description in the Wikipedia is not helpful.
|
||||
*
|
||||
* The algorithm tries to produce a decent answer to combinatorially
|
||||
* explosive optimization problems by analogy to slow cooling
|
||||
* of hot metal, aka annealing.
|
||||
*
|
||||
* There are (at least) three problem-dependent annealing parameters
|
||||
* to consider:
|
||||
*
|
||||
* t0, the initial "temperature. Should be set so that the probability
|
||||
* of accepting a transition to a higher cost configuration is
|
||||
* initially about 0.8.
|
||||
*
|
||||
* ntemps, the number of temperatures to use. Each successive temperature
|
||||
* is some fraction of the previous temperature.
|
||||
*
|
||||
* nmoves_per_temp, the number of configurations to try at each temperature
|
||||
*
|
||||
* It is a black art to set ntemps, nmoves_per_temp, and the rate
|
||||
* at which the temperature drops. Go too fast with too few iterations,
|
||||
* and the computation falls into a local minimum instead of the
|
||||
* (desired) global minimum.
|
||||
*/
|
||||
|
||||
void
|
||||
clib_anneal (clib_anneal_param_t * p)
|
||||
{
|
||||
f64 t;
|
||||
f64 cost, prev_cost, delta_cost, initial_cost, best_cost;
|
||||
f64 random_accept, delta_cost_over_t;
|
||||
f64 total_increase = 0.0, average_increase;
|
||||
u32 i, j;
|
||||
u32 number_of_increases = 0;
|
||||
u32 accepted_this_temperature;
|
||||
u32 best_saves_this_temperature;
|
||||
int accept;
|
||||
|
||||
t = p->initial_temperature;
|
||||
best_cost = initial_cost = prev_cost = p->anneal_metric (p->opaque);
|
||||
p->anneal_save_best_configuration (p->opaque);
|
||||
|
||||
if (p->flags & CLIB_ANNEAL_VERBOSE)
|
||||
fformat (stdout, "Initial cost %.2f\n", initial_cost);
|
||||
|
||||
for (i = 0; i < p->number_of_temperatures; i++)
|
||||
{
|
||||
accepted_this_temperature = 0;
|
||||
best_saves_this_temperature = 0;
|
||||
|
||||
p->anneal_restore_best_configuration (p->opaque);
|
||||
cost = best_cost;
|
||||
|
||||
for (j = 0; j < p->number_of_configurations_per_temperature; j++)
|
||||
{
|
||||
p->anneal_new_configuration (p->opaque);
|
||||
cost = p->anneal_metric (p->opaque);
|
||||
|
||||
delta_cost = cost - prev_cost;
|
||||
|
||||
/* cost function looks better, accept this move */
|
||||
if (p->flags & CLIB_ANNEAL_MINIMIZE)
|
||||
accept = delta_cost < 0.0;
|
||||
else
|
||||
accept = delta_cost > 0.0;
|
||||
|
||||
if (accept)
|
||||
{
|
||||
if (p->flags & CLIB_ANNEAL_MINIMIZE)
|
||||
if (cost < best_cost)
|
||||
{
|
||||
if (p->flags & CLIB_ANNEAL_VERBOSE)
|
||||
fformat (stdout, "New best cost %.2f\n", cost);
|
||||
best_cost = cost;
|
||||
p->anneal_save_best_configuration (p->opaque);
|
||||
best_saves_this_temperature++;
|
||||
}
|
||||
|
||||
accepted_this_temperature++;
|
||||
prev_cost = cost;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* cost function worse, keep stats to suggest t0 */
|
||||
total_increase += (p->flags & CLIB_ANNEAL_MINIMIZE) ?
|
||||
delta_cost : -delta_cost;
|
||||
|
||||
number_of_increases++;
|
||||
|
||||
/*
|
||||
* Accept a higher cost with Pr { e^(-(delta_cost / T)) },
|
||||
* equivalent to rnd[0,1] < e^(-(delta_cost / T))
|
||||
*
|
||||
* AKA, the Boltzmann factor.
|
||||
*/
|
||||
random_accept = random_f64 (&p->random_seed);
|
||||
|
||||
delta_cost_over_t = delta_cost / t;
|
||||
|
||||
if (random_accept < exp (-delta_cost_over_t))
|
||||
{
|
||||
accepted_this_temperature++;
|
||||
prev_cost = cost;
|
||||
continue;
|
||||
}
|
||||
p->anneal_restore_previous_configuration (p->opaque);
|
||||
}
|
||||
|
||||
if (p->flags & CLIB_ANNEAL_VERBOSE)
|
||||
{
|
||||
fformat (stdout, "Temp %.2f, cost %.2f, accepted %d, bests %d\n", t,
|
||||
prev_cost, accepted_this_temperature,
|
||||
best_saves_this_temperature);
|
||||
fformat (stdout, "Improvement %.2f\n", initial_cost - prev_cost);
|
||||
fformat (stdout, "-------------\n");
|
||||
}
|
||||
|
||||
t = t * p->temperature_step;
|
||||
}
|
||||
|
||||
/*
|
||||
* Empirically, one wants the probability of accepting a move
|
||||
* at the initial temperature to be about 0.8.
|
||||
*/
|
||||
average_increase = total_increase / (f64) number_of_increases;
|
||||
p->suggested_initial_temperature = average_increase / 0.22; /* 0.22 = -ln (0.8) */
|
||||
|
||||
p->final_temperature = t;
|
||||
p->final_metric = p->anneal_metric (p->opaque);
|
||||
|
||||
if (p->flags & CLIB_ANNEAL_VERBOSE)
|
||||
{
|
||||
fformat (stdout, "Average cost increase from a bad move: %.2f\n",
|
||||
average_increase);
|
||||
fformat (stdout, "Suggested t0 = %.2f\n",
|
||||
p->suggested_initial_temperature);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright (c) 2011 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_anneal_h__
|
||||
#define __included_anneal_h__
|
||||
|
||||
#include <vppinfra/clib.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/random.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Initial temperature */
|
||||
f64 initial_temperature;
|
||||
|
||||
/* Temperature fraction at each step, 0.95 is reasonable */
|
||||
f64 temperature_step;
|
||||
|
||||
/* Number of temperatures used */
|
||||
u32 number_of_temperatures;
|
||||
|
||||
/* Number of configurations tried at each temperature */
|
||||
u32 number_of_configurations_per_temperature;
|
||||
|
||||
u32 flags;
|
||||
#define CLIB_ANNEAL_VERBOSE (1<<0)
|
||||
#define CLIB_ANNEAL_MINIMIZE (1<<1) /* mutually exclusive */
|
||||
#define CLIB_ANNEAL_MAXIMIZE (1<<2) /* mutually exclusive */
|
||||
|
||||
/* Random number seed, set to ensure repeatable results */
|
||||
u32 random_seed;
|
||||
|
||||
/* Opaque data passed to callbacks */
|
||||
void *opaque;
|
||||
|
||||
/* Final temperature (output) */
|
||||
f64 final_temperature;
|
||||
|
||||
/* Final metric (output) */
|
||||
f64 final_metric;
|
||||
|
||||
/* Suggested initial temperature (output) */
|
||||
f64 suggested_initial_temperature;
|
||||
|
||||
|
||||
/*--- Callbacks ---*/
|
||||
|
||||
/* objective function to minimize */
|
||||
f64 (*anneal_metric) (void *opaque);
|
||||
|
||||
/* Generate a new configuration */
|
||||
void (*anneal_new_configuration) (void *opaque);
|
||||
|
||||
/* Restore the previous configuration */
|
||||
void (*anneal_restore_previous_configuration) (void *opaque);
|
||||
|
||||
/* Save best configuration found e.g at a certain temperature */
|
||||
void (*anneal_save_best_configuration) (void *opaque);
|
||||
|
||||
/* restore best configuration found e.g at a certain temperature */
|
||||
void (*anneal_restore_best_configuration) (void *opaque);
|
||||
|
||||
} clib_anneal_param_t;
|
||||
|
||||
void clib_anneal (clib_anneal_param_t * p);
|
||||
|
||||
#endif /* __included_anneal_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
#undef CLIB_CUCKOO_TYPE
|
||||
|
||||
#define CLIB_CUCKOO_TYPE _16_8
|
||||
#define CLIB_CUCKOO_KVP_PER_BUCKET (4)
|
||||
#define CLIB_CUCKOO_LOG2_KVP_PER_BUCKET (2)
|
||||
#define CLIB_CUCKOO_BFS_MAX_STEPS (2000)
|
||||
#define CLIB_CUCKOO_BFS_MAX_PATH_LENGTH (8)
|
||||
|
||||
#ifndef __included_cuckoo_16_8_h__
|
||||
#define __included_cuckoo_16_8_h__
|
||||
|
||||
#include <vppinfra/heap.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/pool.h>
|
||||
#include <vppinfra/xxhash.h>
|
||||
#include <vppinfra/cuckoo_debug.h>
|
||||
#include <vppinfra/cuckoo_common.h>
|
||||
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_PREFETCH
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_UNROLL
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_USE_COUNT_LIMITS_SEARCH
|
||||
#define CLIB_CUCKOO_OPTIMIZE_PREFETCH 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_UNROLL 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_USE_COUNT_LIMITS_SEARCH 1
|
||||
|
||||
#if __SSE4_2__ && !defined (__i386__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
/** 8 octet key, 8 octet key value pair */
|
||||
typedef struct
|
||||
{
|
||||
u64 key[2]; /**< the key */
|
||||
u64 value; /**< the value */
|
||||
} clib_cuckoo_kv_16_8_t;
|
||||
|
||||
/** Decide if a clib_cuckoo_kv_16_8_t instance is free
|
||||
@param v- pointer to the (key,value) pair
|
||||
*/
|
||||
always_inline int
|
||||
clib_cuckoo_kv_is_free_16_8 (const clib_cuckoo_kv_16_8_t * v)
|
||||
{
|
||||
if (v->key[0] == ~0ULL && v->value == ~0ULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline void
|
||||
clib_cuckoo_kv_set_free_16_8 (clib_cuckoo_kv_16_8_t * v)
|
||||
{
|
||||
clib_memset (v, 0xff, sizeof (*v));
|
||||
}
|
||||
|
||||
/** Format a clib_cuckoo_kv_16_8_t instance
|
||||
@param s - u8 * vector under construction
|
||||
@param args (vararg) - the (key,value) pair to format
|
||||
@return s - the u8 * vector under construction
|
||||
*/
|
||||
always_inline u8 *
|
||||
format_cuckoo_kvp_16_8 (u8 * s, va_list * args)
|
||||
{
|
||||
clib_cuckoo_kv_16_8_t *v = va_arg (*args, clib_cuckoo_kv_16_8_t *);
|
||||
|
||||
if (clib_cuckoo_kv_is_free_16_8 (v))
|
||||
{
|
||||
s = format (s, " -- empty -- ");
|
||||
}
|
||||
else
|
||||
{
|
||||
s =
|
||||
format (s, "key %llu%llu value %llu", v->key[0], v->key[1], v->value);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
always_inline u64
|
||||
clib_cuckoo_hash_16_8 (clib_cuckoo_kv_16_8_t * v)
|
||||
{
|
||||
#ifdef clib_crc32c_uses_intrinsics
|
||||
return clib_crc32c ((u8 *) v->key, 16);
|
||||
#else
|
||||
u64 tmp = v->key[0] ^ v->key[1];
|
||||
return clib_xxhash (tmp);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Compare two clib_cuckoo_kv_16_8_t instances
|
||||
@param a - first key
|
||||
@param b - second key
|
||||
*/
|
||||
always_inline int
|
||||
clib_cuckoo_key_compare_16_8 (u64 * a, u64 * b)
|
||||
{
|
||||
#if defined(CLIB_HAVE_VEC128) && defined(CLIB_HAVE_VEC128_UNALIGNED_LOAD_STORE)
|
||||
u64x2 v;
|
||||
v = u64x2_load_unaligned (a) ^ u64x2_load_unaligned (b);
|
||||
return u64x2_is_all_zero (v);
|
||||
#else
|
||||
return ((a[0] ^ b[0]) | (a[1] ^ b[1])) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __included_cuckoo_template_h__
|
||||
#include <vppinfra/cuckoo_template.h>
|
||||
|
||||
#endif /* __included_cuckoo_16_8_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
#undef CLIB_CUCKOO_TYPE
|
||||
|
||||
#define CLIB_CUCKOO_TYPE _8_8
|
||||
#define CLIB_CUCKOO_KVP_PER_BUCKET (4)
|
||||
#define CLIB_CUCKOO_LOG2_KVP_PER_BUCKET (2)
|
||||
#define CLIB_CUCKOO_BFS_MAX_STEPS (2000)
|
||||
#define CLIB_CUCKOO_BFS_MAX_PATH_LENGTH (8)
|
||||
|
||||
#ifndef __included_cuckoo_8_8_h__
|
||||
#define __included_cuckoo_8_8_h__
|
||||
|
||||
#include <vppinfra/heap.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/pool.h>
|
||||
#include <vppinfra/xxhash.h>
|
||||
#include <vppinfra/cuckoo_debug.h>
|
||||
#include <vppinfra/cuckoo_common.h>
|
||||
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_PREFETCH
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_UNROLL
|
||||
#undef CLIB_CUCKOO_OPTIMIZE_USE_COUNT_LIMITS_SEARCH
|
||||
#define CLIB_CUCKOO_OPTIMIZE_PREFETCH 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_UNROLL 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_USE_COUNT_LIMITS_SEARCH 1
|
||||
|
||||
#if __SSE4_2__ && !defined (__i386__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
/** 8 octet key, 8 octet key value pair */
|
||||
typedef struct
|
||||
{
|
||||
u64 key; /**< the key */
|
||||
u64 value; /**< the value */
|
||||
} clib_cuckoo_kv_8_8_t;
|
||||
|
||||
/** Decide if a clib_cuckoo_kv_8_8_t instance is free
|
||||
@param v- pointer to the (key,value) pair
|
||||
*/
|
||||
always_inline int
|
||||
clib_cuckoo_kv_is_free_8_8 (const clib_cuckoo_kv_8_8_t * v)
|
||||
{
|
||||
if (v->key == ~0ULL && v->value == ~0ULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
always_inline void
|
||||
clib_cuckoo_kv_set_free_8_8 (clib_cuckoo_kv_8_8_t * v)
|
||||
{
|
||||
clib_memset (v, 0xff, sizeof (*v));
|
||||
}
|
||||
|
||||
/** Format a clib_cuckoo_kv_8_8_t instance
|
||||
@param s - u8 * vector under construction
|
||||
@param args (vararg) - the (key,value) pair to format
|
||||
@return s - the u8 * vector under construction
|
||||
*/
|
||||
always_inline u8 *
|
||||
format_cuckoo_kvp_8_8 (u8 * s, va_list * args)
|
||||
{
|
||||
clib_cuckoo_kv_8_8_t *v = va_arg (*args, clib_cuckoo_kv_8_8_t *);
|
||||
|
||||
if (clib_cuckoo_kv_is_free_8_8 (v))
|
||||
{
|
||||
s = format (s, " -- empty -- ");
|
||||
}
|
||||
else
|
||||
{
|
||||
s = format (s, "key %llu value %llu", v->key, v->value);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
always_inline u64
|
||||
clib_cuckoo_hash_8_8 (clib_cuckoo_kv_8_8_t * v)
|
||||
{
|
||||
#if defined(clib_crc32c_uses_intrinsics) && !defined (__i386__)
|
||||
return crc32_u64 (0, v->key);
|
||||
#else
|
||||
return clib_xxhash (v->key);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Compare two clib_cuckoo_kv_8_8_t instances
|
||||
@param a - first key
|
||||
@param b - second key
|
||||
*/
|
||||
always_inline int
|
||||
clib_cuckoo_key_compare_8_8 (u64 a, u64 b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
#undef __included_cuckoo_template_h__
|
||||
#include <vppinfra/cuckoo_template.h>
|
||||
|
||||
#endif /* __included_cuckoo_8_8_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
Copyright (c) 2017 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: to instantiate the template multiple times in a single file,
|
||||
* #undef __included_cuckoo_template_h__...
|
||||
*/
|
||||
#ifndef __included_cuckoo_common_h__
|
||||
#define __included_cuckoo_common_h__
|
||||
|
||||
#include <vppinfra/types.h>
|
||||
|
||||
#define CLIB_CUCKOO_OPTIMIZE_PREFETCH 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_UNROLL 1
|
||||
#define CLIB_CUCKOO_OPTIMIZE_USE_COUNT_LIMITS_SEARCH 1
|
||||
|
||||
#define foreach_clib_cuckoo_error(F) \
|
||||
F (CLIB_CUCKOO_ERROR_SUCCESS, 0, "success") \
|
||||
F (CLIB_CUCKOO_ERROR_NOT_FOUND, -1, "object not found") \
|
||||
F (CLIB_CUCKOO_ERROR_AGAIN, -2, "object busy")
|
||||
|
||||
typedef enum
|
||||
{
|
||||
#define F(n, v, s) n = v,
|
||||
foreach_clib_cuckoo_error (F)
|
||||
#undef F
|
||||
} clib_cuckoo_error_e;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uword bucket1;
|
||||
uword bucket2;
|
||||
u8 reduced_hash;
|
||||
} clib_cuckoo_lookup_info_t;
|
||||
|
||||
#endif /* __included_cuckoo_common_h__ */
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2017 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.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief cuckoo debugs
|
||||
*/
|
||||
#ifndef __included_cuckoo_debug_h__
|
||||
#define __included_cuckoo_debug_h__
|
||||
|
||||
/* controls debug counters */
|
||||
#define CLIB_CUCKOO_DEBUG_COUNTERS (0)
|
||||
|
||||
/* controls debug prints */
|
||||
#define CLIB_CUCKOO_DEBUG (0)
|
||||
|
||||
/* controls garbage collection related debug prints */
|
||||
#define CLIB_CUCKOO_DEBUG_GC (0)
|
||||
|
||||
#if CLIB_CUCKOO_DEBUG
|
||||
#define CLIB_CUCKOO_DEBUG_FILE_DEF \
|
||||
static const char *__file = NULL; \
|
||||
{ \
|
||||
__file = strrchr (__FILE__, '/'); \
|
||||
if (__file) \
|
||||
{ \
|
||||
++__file; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
__file = __FILE__; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CLIB_CUCKOO_DBG(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
CLIB_CUCKOO_DEBUG_FILE_DEF \
|
||||
static u8 *_s = NULL; \
|
||||
_s = format (_s, "DBG:%s:%d:%s():" fmt, __file, __LINE__, __func__, \
|
||||
##__VA_ARGS__); \
|
||||
printf ("%.*s\n", vec_len (_s), _s); \
|
||||
vec_reset_length (_s); \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
#define CLIB_CUCKOO_ERR(fmt, ...) \
|
||||
do \
|
||||
{ \
|
||||
CLIB_CUCKOO_DEBUG_FILE_DEF \
|
||||
static u8 *_s = NULL; \
|
||||
_s = format (_s, "ERR:%s:%d:%s():" fmt, __file, __LINE__, __func__, \
|
||||
##__VA_ARGS__); \
|
||||
printf ("%.*s\n", vec_len (_s), _s); \
|
||||
vec_reset_length (_s); \
|
||||
} \
|
||||
while (0);
|
||||
|
||||
#else
|
||||
#define CLIB_CUCKOO_DBG(...)
|
||||
#define CLIB_CUCKOO_ERR(...)
|
||||
#endif
|
||||
|
||||
#endif /* __included_cuckoo_debug_h__ */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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_fheap_h
|
||||
#define included_clib_fheap_h
|
||||
|
||||
/* Fibonacci Heaps Fredman, M. L.; Tarjan (1987).
|
||||
"Fibonacci heaps and their uses in improved network optimization algorithms" */
|
||||
|
||||
#include <vppinfra/vec.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Node index of parent. */
|
||||
u32 parent;
|
||||
|
||||
/* Node index of first child. */
|
||||
u32 first_child;
|
||||
|
||||
/* Next and previous nodes in doubly linked list of siblings. */
|
||||
u32 next_sibling, prev_sibling;
|
||||
|
||||
/* Key (distance) for this node. Parent always has key
|
||||
<= than keys of children. */
|
||||
u32 key;
|
||||
|
||||
/* Number of children (as opposed to descendents). */
|
||||
u32 rank;
|
||||
|
||||
u32 is_marked;
|
||||
|
||||
/* Set to one when node is inserted; zero when deleted. */
|
||||
u32 is_valid;
|
||||
} fheap_node_t;
|
||||
|
||||
#define foreach_fheap_node_sibling(f,ni,first_ni,body) \
|
||||
do { \
|
||||
u32 __fheap_foreach_first_ni = (first_ni); \
|
||||
u32 __fheap_foreach_ni = __fheap_foreach_first_ni; \
|
||||
u32 __fheap_foreach_next_ni; \
|
||||
fheap_node_t * __fheap_foreach_n; \
|
||||
if (__fheap_foreach_ni != ~0) \
|
||||
while (1) \
|
||||
{ \
|
||||
__fheap_foreach_n = fheap_get_node ((f), __fheap_foreach_ni); \
|
||||
__fheap_foreach_next_ni = __fheap_foreach_n -> next_sibling; \
|
||||
(ni) = __fheap_foreach_ni; \
|
||||
\
|
||||
body; \
|
||||
\
|
||||
/* End of circular list? */ \
|
||||
if (__fheap_foreach_next_ni == __fheap_foreach_first_ni) \
|
||||
break; \
|
||||
\
|
||||
__fheap_foreach_ni = __fheap_foreach_next_ni; \
|
||||
\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 min_root;
|
||||
|
||||
/* Vector of nodes. */
|
||||
fheap_node_t *nodes;
|
||||
|
||||
u32 *root_list_by_rank;
|
||||
|
||||
u32 enable_validate;
|
||||
|
||||
u32 validate_serial;
|
||||
} fheap_t;
|
||||
|
||||
/* Initialize empty heap. */
|
||||
always_inline void
|
||||
fheap_init (fheap_t * f, u32 n_nodes)
|
||||
{
|
||||
fheap_node_t *save_nodes = f->nodes;
|
||||
u32 *save_root_list = f->root_list_by_rank;
|
||||
|
||||
clib_memset (f, 0, sizeof (f[0]));
|
||||
|
||||
f->nodes = save_nodes;
|
||||
f->root_list_by_rank = save_root_list;
|
||||
|
||||
vec_validate (f->nodes, n_nodes - 1);
|
||||
vec_reset_length (f->root_list_by_rank);
|
||||
|
||||
f->min_root = ~0;
|
||||
}
|
||||
|
||||
always_inline void
|
||||
fheap_free (fheap_t * f)
|
||||
{
|
||||
vec_free (f->nodes);
|
||||
vec_free (f->root_list_by_rank);
|
||||
}
|
||||
|
||||
always_inline u32
|
||||
fheap_find_min (fheap_t * f)
|
||||
{
|
||||
return f->min_root;
|
||||
}
|
||||
|
||||
always_inline u32
|
||||
fheap_is_empty (fheap_t * f)
|
||||
{
|
||||
return f->min_root == ~0;
|
||||
}
|
||||
|
||||
/* Add/delete nodes. */
|
||||
void fheap_add (fheap_t * f, u32 ni, u32 key);
|
||||
void fheap_del (fheap_t * f, u32 ni);
|
||||
|
||||
/* Delete and return minimum. */
|
||||
u32 fheap_del_min (fheap_t * f, u32 * min_key);
|
||||
|
||||
/* Change key value. */
|
||||
void fheap_decrease_key (fheap_t * f, u32 ni, u32 new_key);
|
||||
|
||||
#endif /* included_clib_fheap_h */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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 SRC_VPPINFRA_FLOWHASH_24_16_H_
|
||||
#define SRC_VPPINFRA_FLOWHASH_24_16_H_
|
||||
|
||||
#ifdef __included_flowhash_template_h__
|
||||
#undef __included_flowhash_template_h__
|
||||
#endif
|
||||
|
||||
#include <vppinfra/clib.h>
|
||||
#include <vppinfra/xxhash.h>
|
||||
#include <vppinfra/crc32.h>
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[3];
|
||||
} flowhash_skey_24_16_t;
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[3];
|
||||
} flowhash_lkey_24_16_t;
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[2];
|
||||
} flowhash_value_24_16_t;
|
||||
|
||||
#define FLOWHASH_TYPE _24_16
|
||||
#include <vppinfra/flowhash_template.h>
|
||||
#undef FLOWHASH_TYPE
|
||||
|
||||
static_always_inline
|
||||
u32 flowhash_hash_24_16(flowhash_lkey_24_16_t *k)
|
||||
{
|
||||
#ifdef clib_crc32c_uses_intrinsics
|
||||
return clib_crc32c ((u8 *) &k->as_u64[0], 24);
|
||||
#else
|
||||
u64 val = 0;
|
||||
val ^= k->as_u64[0];
|
||||
val ^= k->as_u64[1];
|
||||
val ^= k->as_u64[2];
|
||||
return (u32)clib_xxhash (val);
|
||||
#endif
|
||||
}
|
||||
|
||||
static_always_inline
|
||||
u8 flowhash_cmp_key_24_16(flowhash_skey_24_16_t *a,
|
||||
flowhash_lkey_24_16_t *b)
|
||||
{
|
||||
u8 val = 0;
|
||||
val |= (a->as_u64[0] != b->as_u64[0]);
|
||||
val |= (a->as_u64[1] != b->as_u64[1]);
|
||||
val |= (a->as_u64[2] != b->as_u64[2]);
|
||||
return val;
|
||||
}
|
||||
|
||||
static_always_inline
|
||||
void flowhash_cpy_key_24_16(flowhash_skey_24_16_t *dst,
|
||||
flowhash_lkey_24_16_t *src)
|
||||
{
|
||||
dst->as_u64[0] = src->as_u64[0];
|
||||
dst->as_u64[1] = src->as_u64[1];
|
||||
dst->as_u64[2] = src->as_u64[2];
|
||||
}
|
||||
|
||||
#endif /* SRC_VPPINFRA_FLOWHASH_24_16_H_ */
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2012 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 SRC_VPPINFRA_FLOWHASH_8_8_H_
|
||||
#define SRC_VPPINFRA_FLOWHASH_8_8_H_
|
||||
|
||||
#ifdef __included_flowhash_template_h__
|
||||
#undef __included_flowhash_template_h__
|
||||
#endif
|
||||
|
||||
#include <vppinfra/clib.h>
|
||||
#include <vppinfra/xxhash.h>
|
||||
#include <vppinfra/crc32.h>
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[1];
|
||||
} flowhash_skey_8_8_t;
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[1];
|
||||
} flowhash_lkey_8_8_t;
|
||||
|
||||
typedef struct {
|
||||
u64 as_u64[1];
|
||||
} flowhash_value_8_8_t;
|
||||
|
||||
#define FLOWHASH_TYPE _8_8
|
||||
#include <vppinfra/flowhash_template.h>
|
||||
#undef FLOWHASH_TYPE
|
||||
|
||||
static_always_inline
|
||||
u32 flowhash_hash_8_8(flowhash_lkey_8_8_t *k)
|
||||
{
|
||||
#ifdef clib_crc32c_uses_intrinsics
|
||||
return clib_crc32c ((u8 *) &k->as_u64[0], 8);
|
||||
#else
|
||||
return clib_xxhash (k->as_u64[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static_always_inline
|
||||
u8 flowhash_cmp_key_8_8(flowhash_skey_8_8_t *a,
|
||||
flowhash_lkey_8_8_t *b)
|
||||
{
|
||||
return a->as_u64[0] != b->as_u64[0];
|
||||
}
|
||||
|
||||
static_always_inline
|
||||
void flowhash_cpy_key_8_8(flowhash_skey_8_8_t *dst,
|
||||
flowhash_lkey_8_8_t *src)
|
||||
{
|
||||
dst->as_u64[0] = src->as_u64[0];
|
||||
}
|
||||
|
||||
#endif /* SRC_VPPINFRA_FLOWHASH_8_8_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
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:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2005 Eliot Dresselhaus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef included_phash_h
|
||||
#define included_phash_h
|
||||
|
||||
#include <vppinfra/hash.h> /* for Bob's mixing functions */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Maybe either pointer to vector or inline word. */
|
||||
uword key;
|
||||
|
||||
/* Hash code (A, B). */
|
||||
u32 a, b;
|
||||
} phash_key_t;
|
||||
|
||||
/* Table indexed by B. */
|
||||
typedef struct
|
||||
{
|
||||
/* Vector of key indices with this same value of B. */
|
||||
u32 *keys;
|
||||
|
||||
/* hash=a^tabb[b].val_b */
|
||||
u32 val_b;
|
||||
|
||||
/* High watermark of who has visited this map node. */
|
||||
u32 water_b;
|
||||
} phash_tabb_t;
|
||||
|
||||
always_inline void
|
||||
phash_tabb_free (phash_tabb_t * b)
|
||||
{
|
||||
vec_free (b->keys);
|
||||
b->val_b = b->water_b = 0;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* b that currently occupies this hash */
|
||||
u32 b_q;
|
||||
|
||||
/* Queue position of parent that could use this hash. */
|
||||
u32 parent_q;
|
||||
|
||||
/* What to change parent tab[b] to use this hash. */
|
||||
u32 newval_q;
|
||||
|
||||
/* Original value of tab[b]. */
|
||||
u32 oldval_q;
|
||||
} phash_tabq_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 a_bits, b_bits, s_bits, a_shift;
|
||||
u32 b_mask;
|
||||
u32 *tab;
|
||||
u32 *scramble;
|
||||
|
||||
/* Seed value for hash mixer. */
|
||||
u64 hash_seed;
|
||||
|
||||
u32 flags;
|
||||
|
||||
/* Key functions want 64 bit keys.
|
||||
Use hash_mix64 rather than hash_mix32. */
|
||||
#define PHASH_FLAG_MIX64 (1 << 0)
|
||||
#define PHASH_FLAG_MIX32 (0 << 0)
|
||||
|
||||
/* When b_bits is large enough (>= 12) we scramble. */
|
||||
#define PHASH_FLAG_USE_SCRAMBLE (1 << 1)
|
||||
|
||||
/* Slow mode gives smaller tables but at the expense of more run time. */
|
||||
#define PHASH_FLAG_SLOW_MODE (0 << 2)
|
||||
#define PHASH_FLAG_FAST_MODE (1 << 2)
|
||||
|
||||
/* Generate minimal perfect hash instead of perfect hash. */
|
||||
#define PHASH_FLAG_NON_MINIMAL (0 << 3)
|
||||
#define PHASH_FLAG_MINIMAL (1 << 3)
|
||||
|
||||
/* vec_len (keys) for minimal hash;
|
||||
1 << s_bits for non-minimal hash. */
|
||||
u32 hash_max;
|
||||
|
||||
/* Vector of keys. */
|
||||
phash_key_t *keys;
|
||||
|
||||
/* Used by callbacks to identify keys. */
|
||||
void *private;
|
||||
|
||||
/* Key comparison callback. */
|
||||
int (*key_is_equal) (void *private, uword key1, uword key2);
|
||||
|
||||
/* Callback to reduce single key -> hash seeds. */
|
||||
void (*key_seed1) (void *private, uword key, void *seed);
|
||||
|
||||
/* Callback to reduce two key2 -> hash seeds. */
|
||||
void (*key_seed2) (void *private, uword key1, uword key2, void *seed);
|
||||
|
||||
/* Stuff used to compute perfect hash. */
|
||||
u32 random_seed;
|
||||
|
||||
/* Stuff indexed by B. */
|
||||
phash_tabb_t *tabb;
|
||||
|
||||
/* Table of B ordered by number of keys in tabb[b]. */
|
||||
u32 *tabb_sort;
|
||||
|
||||
/* Unique key (or ~0 if none) for a given hash
|
||||
H = A ^ scramble[tab[B].val_b]. */
|
||||
u32 *tabh;
|
||||
|
||||
/* Stuff indexed by q. */
|
||||
phash_tabq_t *tabq;
|
||||
|
||||
/* Stats. */
|
||||
u32 n_seed_trials, n_perfect_calls;
|
||||
} phash_main_t;
|
||||
|
||||
always_inline void
|
||||
phash_main_free_working_memory (phash_main_t * pm)
|
||||
{
|
||||
vec_free (pm->tabb);
|
||||
vec_free (pm->tabq);
|
||||
vec_free (pm->tabh);
|
||||
vec_free (pm->tabb_sort);
|
||||
if (!(pm->flags & PHASH_FLAG_USE_SCRAMBLE))
|
||||
vec_free (pm->scramble);
|
||||
}
|
||||
|
||||
always_inline void
|
||||
phash_main_free (phash_main_t * pm)
|
||||
{
|
||||
phash_main_free_working_memory (pm);
|
||||
vec_free (pm->tab);
|
||||
vec_free (pm->keys);
|
||||
clib_memset (pm, 0, sizeof (pm[0]));
|
||||
}
|
||||
|
||||
/* Slow hash computation for general keys. */
|
||||
uword phash_hash_slow (phash_main_t * pm, uword key);
|
||||
|
||||
/* Main routine to compute perfect hash. */
|
||||
clib_error_t *phash_find_perfect_hash (phash_main_t * pm);
|
||||
|
||||
/* Validates that hash is indeed perfect. */
|
||||
clib_error_t *phash_validate (phash_main_t * pm);
|
||||
|
||||
/* Unit test. */
|
||||
int phash_test_main (unformat_input_t * input);
|
||||
|
||||
#endif /* included_phash_h */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
/*
|
||||
* pipeline.h: software pipeline infrastructure
|
||||
*
|
||||
* Copyright (c) 2010 Eliot Dresselhaus
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef included_clib_pipeline_h
|
||||
#define included_clib_pipeline_h
|
||||
|
||||
#define clib_pipeline_stage(F,TYPE,ARG,I,BODY) \
|
||||
always_inline void F##_inline (void * _, u32 I) \
|
||||
{ TYPE ARG = _; { BODY; } } \
|
||||
never_inline void F##_no_inline (TYPE ARG, u32 I) \
|
||||
{ F##_inline (ARG, I); }
|
||||
|
||||
#define clib_pipeline_stage_static(F,TYPE,ARG,I,BODY) \
|
||||
static_always_inline void F##_inline (void * _, u32 I) \
|
||||
{ TYPE ARG = _; { BODY; } } \
|
||||
never_inline void F##_no_inline (TYPE ARG, u32 I) \
|
||||
{ F##_inline (ARG, I); }
|
||||
|
||||
#define clib_pipeline_stage_no_inline(F,TYPE,ARG,I,BODY) \
|
||||
never_inline void F##_no_inline (void * _, u32 I) \
|
||||
{ TYPE ARG = _; { BODY; } } \
|
||||
never_inline void F##_inline (TYPE ARG, u32 I) \
|
||||
{ F##_no_inline (ARG, I); }
|
||||
|
||||
#define _clib_pipeline_var(v) _clib_pipeline_##v
|
||||
|
||||
#define clib_pipeline_stage_execute(F,A,I,S) \
|
||||
F##_##S (A, _clib_pipeline_var(i) - (I))
|
||||
|
||||
#define clib_pipeline_main_stage(F,A,I) \
|
||||
clib_pipeline_stage_execute (F, A, I, inline)
|
||||
#define clib_pipeline_init_stage(F,A,I) \
|
||||
if (_clib_pipeline_var(i) >= (I)) clib_pipeline_stage_execute (F, A, I, no_inline)
|
||||
#define clib_pipeline_exit_stage(F,A,I) \
|
||||
if (_clib_pipeline_var(i) >= (I) && _clib_pipeline_var(i) - (I) < _clib_pipeline_var(n_vectors)) \
|
||||
clib_pipeline_stage_execute (F, A, I, no_inline)
|
||||
|
||||
#define clib_pipeline_init_loop \
|
||||
for (_clib_pipeline_var(i) = 0; \
|
||||
_clib_pipeline_var(i) < \
|
||||
clib_min (_clib_pipeline_var(n_stages) - 1, \
|
||||
_clib_pipeline_var(n_vectors)); \
|
||||
_clib_pipeline_var(i)++)
|
||||
|
||||
#define clib_pipeline_main_loop \
|
||||
for (; _clib_pipeline_var(i) < _clib_pipeline_var(n_vectors); \
|
||||
_clib_pipeline_var(i)++)
|
||||
|
||||
#define clib_pipeline_exit_loop \
|
||||
for (; _clib_pipeline_var(i) < (_clib_pipeline_var(n_vectors) \
|
||||
+ _clib_pipeline_var(n_stages) - 1); \
|
||||
_clib_pipeline_var(i)++)
|
||||
|
||||
#define clib_pipeline_run_2_stage(N,ARG,STAGE0,STAGE1) \
|
||||
do { \
|
||||
uword _clib_pipeline_var(n_vectors) = (N); \
|
||||
uword _clib_pipeline_var(n_stages) = 2; \
|
||||
uword _clib_pipeline_var(i); \
|
||||
\
|
||||
clib_pipeline_init_loop \
|
||||
{ \
|
||||
clib_pipeline_init_stage (STAGE0, ARG, 0); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_main_loop \
|
||||
{ \
|
||||
clib_pipeline_main_stage (STAGE0, ARG, 0); \
|
||||
clib_pipeline_main_stage (STAGE1, ARG, 1); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_exit_loop \
|
||||
{ \
|
||||
clib_pipeline_exit_stage (STAGE1, ARG, 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define clib_pipeline_run_3_stage(N,ARG,STAGE0,STAGE1,STAGE2) \
|
||||
do { \
|
||||
uword _clib_pipeline_var(n_vectors) = (N); \
|
||||
uword _clib_pipeline_var(n_stages) = 3; \
|
||||
uword _clib_pipeline_var(i); \
|
||||
\
|
||||
clib_pipeline_init_loop \
|
||||
{ \
|
||||
clib_pipeline_init_stage (STAGE0, ARG, 0); \
|
||||
clib_pipeline_init_stage (STAGE1, ARG, 1); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_main_loop \
|
||||
{ \
|
||||
clib_pipeline_main_stage (STAGE0, ARG, 0); \
|
||||
clib_pipeline_main_stage (STAGE1, ARG, 1); \
|
||||
clib_pipeline_main_stage (STAGE2, ARG, 2); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_exit_loop \
|
||||
{ \
|
||||
clib_pipeline_exit_stage (STAGE1, ARG, 1); \
|
||||
clib_pipeline_exit_stage (STAGE2, ARG, 2); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define clib_pipeline_run_4_stage(N,ARG,STAGE0,STAGE1,STAGE2,STAGE3) \
|
||||
do { \
|
||||
uword _clib_pipeline_var(n_vectors) = (N); \
|
||||
uword _clib_pipeline_var(n_stages) = 4; \
|
||||
uword _clib_pipeline_var(i); \
|
||||
\
|
||||
clib_pipeline_init_loop \
|
||||
{ \
|
||||
clib_pipeline_init_stage (STAGE0, ARG, 0); \
|
||||
clib_pipeline_init_stage (STAGE1, ARG, 1); \
|
||||
clib_pipeline_init_stage (STAGE2, ARG, 2); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_main_loop \
|
||||
{ \
|
||||
clib_pipeline_main_stage (STAGE0, ARG, 0); \
|
||||
clib_pipeline_main_stage (STAGE1, ARG, 1); \
|
||||
clib_pipeline_main_stage (STAGE2, ARG, 2); \
|
||||
clib_pipeline_main_stage (STAGE3, ARG, 3); \
|
||||
} \
|
||||
\
|
||||
clib_pipeline_exit_loop \
|
||||
{ \
|
||||
clib_pipeline_exit_stage (STAGE1, ARG, 1); \
|
||||
clib_pipeline_exit_stage (STAGE2, ARG, 2); \
|
||||
clib_pipeline_exit_stage (STAGE3, ARG, 3); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* included_clib_pipeline_h */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2006 Eliot Dresselhaus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef included_qhash_h
|
||||
#define included_qhash_h
|
||||
|
||||
#include <vppinfra/cache.h>
|
||||
#include <vppinfra/hash.h>
|
||||
|
||||
/* Word hash tables. */
|
||||
typedef struct
|
||||
{
|
||||
/* Number of elements in hash. */
|
||||
u32 n_elts;
|
||||
|
||||
u32 log2_hash_size;
|
||||
|
||||
/* Jenkins hash seeds. */
|
||||
u32 hash_seeds[3];
|
||||
|
||||
/* Fall back CLIB hash for overflow in fixed sized buckets. */
|
||||
uword *overflow_hash;
|
||||
|
||||
u32 *overflow_counts, *overflow_free_indices;
|
||||
|
||||
u8 *hash_key_valid_bitmap;
|
||||
|
||||
uword *hash_keys;
|
||||
} qhash_t;
|
||||
|
||||
always_inline qhash_t *
|
||||
qhash_header (void *v)
|
||||
{
|
||||
return vec_header (v, sizeof (qhash_t));
|
||||
}
|
||||
|
||||
always_inline uword
|
||||
qhash_elts (void *v)
|
||||
{
|
||||
return v ? qhash_header (v)->n_elts : 0;
|
||||
}
|
||||
|
||||
always_inline uword
|
||||
qhash_n_overflow (void *v)
|
||||
{
|
||||
return v ? hash_elts (qhash_header (v)->overflow_hash) : 0;
|
||||
}
|
||||
|
||||
#define QHASH_LOG2_KEYS_PER_BUCKET 2
|
||||
#define QHASH_KEYS_PER_BUCKET (1 << QHASH_LOG2_KEYS_PER_BUCKET)
|
||||
|
||||
always_inline uword
|
||||
qhash_hash_mix (qhash_t * h, uword key)
|
||||
{
|
||||
u32 a, b, c;
|
||||
|
||||
a = h->hash_seeds[0];
|
||||
b = h->hash_seeds[1];
|
||||
c = h->hash_seeds[2];
|
||||
|
||||
a ^= key;
|
||||
#if uword_bits == 64
|
||||
b ^= key >> 32;
|
||||
#endif
|
||||
|
||||
hash_mix32 (a, b, c);
|
||||
|
||||
return c & pow2_mask (h->log2_hash_size);
|
||||
}
|
||||
|
||||
#define qhash_resize(v,n) (v) = _qhash_resize ((v), (n), sizeof ((v)[0]))
|
||||
|
||||
#define qhash_foreach(var,v,body)
|
||||
|
||||
#define qhash_set_multiple(v,keys,n,results) \
|
||||
(v) = _qhash_set_multiple ((v), sizeof ((v)[0]), (keys), (n), (results))
|
||||
|
||||
#define qhash_unset_multiple(v,keys,n,results) \
|
||||
_qhash_unset_multiple ((v), sizeof ((v)[0]), (keys), (n), (results))
|
||||
|
||||
#define qhash_get(v,key) \
|
||||
({ \
|
||||
uword _qhash_get_k = (key); \
|
||||
qhash_get_first_match ((v), &_qhash_get_k, 1, &_qhash_get_k); \
|
||||
})
|
||||
|
||||
#define qhash_set(v,k) \
|
||||
({ \
|
||||
uword _qhash_set_k = (k); \
|
||||
qhash_set_multiple ((v), &_qhash_set_k, 1, &_qhash_set_k); \
|
||||
_qhash_set_k; \
|
||||
})
|
||||
|
||||
#define qhash_unset(v,k) \
|
||||
({ \
|
||||
uword _qhash_unset_k = (k); \
|
||||
qhash_unset_multiple ((v), &_qhash_unset_k, 1, &_qhash_unset_k); \
|
||||
_qhash_unset_k; \
|
||||
})
|
||||
|
||||
void *_qhash_resize (void *v, uword length, uword elt_bytes);
|
||||
|
||||
/* Lookup multiple keys in the same hash table. */
|
||||
void
|
||||
qhash_get_multiple (void *v,
|
||||
uword * search_keys,
|
||||
uword n_search_keys, u32 * result_indices);
|
||||
|
||||
/* Lookup multiple keys in the same hash table.
|
||||
Returns index of first matching key. */
|
||||
u32
|
||||
qhash_get_first_match (void *v,
|
||||
uword * search_keys,
|
||||
uword n_search_keys, uword * matching_key);
|
||||
|
||||
/* Set/unset helper functions. */
|
||||
void *_qhash_set_multiple (void *v,
|
||||
uword elt_bytes,
|
||||
uword * search_keys,
|
||||
uword n_search_keys, u32 * result_indices);
|
||||
void
|
||||
_qhash_unset_multiple (void *v,
|
||||
uword elt_bytes,
|
||||
uword * search_keys,
|
||||
uword n_search_keys, u32 * result_indices);
|
||||
|
||||
#endif /* included_qhash_h */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Copyright (c) 2012 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_slist_h
|
||||
#define included_slist_h
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <vppinfra/clib.h>
|
||||
#include <vppinfra/vec.h>
|
||||
#include <vppinfra/pool.h>
|
||||
#include <vppinfra/error.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/cache.h>
|
||||
|
||||
typedef word (clib_slist_key_compare_function_t)
|
||||
(void *key, u32 elt_pool_index);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLIB_SLIST_MATCH = 0,
|
||||
CLIB_SLIST_NO_MATCH
|
||||
} clib_slist_search_result_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Vector of next elements. Every valid instance has at least one */
|
||||
union
|
||||
{
|
||||
u32 next0[2];
|
||||
u32 *nexts;
|
||||
} n;
|
||||
|
||||
/* Index of item in user's pool */
|
||||
u32 user_pool_index;
|
||||
/* $$$ pad to even divisor of cache line */
|
||||
} clib_slist_elt_t;
|
||||
|
||||
static inline u32
|
||||
clib_slist_get_next_at_level (clib_slist_elt_t * elt, int level)
|
||||
{
|
||||
if (elt->n.next0[0] & 1)
|
||||
{
|
||||
ASSERT (level < 2);
|
||||
if (level == 1)
|
||||
return elt->n.next0[1];
|
||||
/* preserve ~0 (end of list) */
|
||||
return (elt->n.next0[0] == (u32) ~ 0) ? elt->n.next0[0] :
|
||||
(elt->n.next0[0] >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT (level < vec_len (elt->n.nexts));
|
||||
return elt->n.nexts[level];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
clib_slist_set_next_at_level (clib_slist_elt_t * elt, u32 index, int level)
|
||||
{
|
||||
u32 old_level0_value[2];
|
||||
/* level0 and not a vector */
|
||||
if (level < 2 && (elt->n.next0[0] == 0 || elt->n.next0[0] & 1))
|
||||
{
|
||||
if (level == 0)
|
||||
{
|
||||
elt->n.next0[0] = (index << 1) | 1;
|
||||
return;
|
||||
}
|
||||
elt->n.next0[1] = index;
|
||||
return;
|
||||
}
|
||||
/* have to save old level0 values? */
|
||||
if (elt->n.next0[0] & 1)
|
||||
{
|
||||
old_level0_value[0] = (elt->n.next0[0] == (u32) ~ 0) ?
|
||||
elt->n.next0[0] : elt->n.next0[0] >> 1;
|
||||
old_level0_value[1] = elt->n.next0[1];
|
||||
elt->n.nexts = 0;
|
||||
vec_add1 (elt->n.nexts, old_level0_value[0]);
|
||||
vec_add1 (elt->n.nexts, old_level0_value[1]);
|
||||
}
|
||||
vec_validate (elt->n.nexts, level);
|
||||
elt->n.nexts[level] = index;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* pool of skip-list elements */
|
||||
clib_slist_elt_t *elts;
|
||||
|
||||
/* last search path */
|
||||
u32 *path;
|
||||
|
||||
/* last search number of compares */
|
||||
u32 ncompares;
|
||||
|
||||
/* occupancy stats */
|
||||
u32 *occupancy;
|
||||
|
||||
/* Comparison function */
|
||||
clib_slist_key_compare_function_t *compare;
|
||||
|
||||
/* Format function */
|
||||
format_function_t *format_user_element;
|
||||
|
||||
/* items appear in successive plies with Pr (1 / branching_factor) */
|
||||
f64 branching_factor;
|
||||
|
||||
/* random seed */
|
||||
u32 seed;
|
||||
} clib_slist_t;
|
||||
|
||||
clib_error_t *clib_slist_init (clib_slist_t * sp, f64 branching_factor,
|
||||
clib_slist_key_compare_function_t compare,
|
||||
format_function_t format_user_element);
|
||||
|
||||
format_function_t format_slist;
|
||||
|
||||
void clib_slist_add (clib_slist_t * sp, void *key, u32 user_pool_index);
|
||||
clib_slist_search_result_t clib_slist_del (clib_slist_t * sp, void *key);
|
||||
u32 clib_slist_search (clib_slist_t * sp, void *key, u32 * ncompares);
|
||||
|
||||
#endif /* included_slist_h */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
|
||||
#include <vppinfra/time.h>
|
||||
#include <vppinfra/cache.h>
|
||||
#include <vppinfra/error.h>
|
||||
|
||||
#include <vppinfra/heap.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/random.h>
|
||||
#include <vppinfra/hash.h>
|
||||
|
||||
#include <vppinfra/flowhash_8_8.h>
|
||||
|
||||
/* Not actually tested here. But included for compilation purposes. */
|
||||
#include <vppinfra/flowhash_24_16.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 seed;
|
||||
u32 fixed_entries;
|
||||
u32 collision_buckets;
|
||||
u32 nitems;
|
||||
u32 iterations;
|
||||
u32 prefetch;
|
||||
int non_random_keys;
|
||||
uword *key_hash;
|
||||
flowhash_lkey_8_8_t *keys;
|
||||
flowhash_8_8_t *hash;
|
||||
clib_time_t clib_time;
|
||||
unformat_input_t *input;
|
||||
} test_main_t;
|
||||
|
||||
test_main_t test_main;
|
||||
|
||||
static clib_error_t *
|
||||
test_flowhash (test_main_t * tm)
|
||||
{
|
||||
f64 before, delta;
|
||||
u64 total;
|
||||
u32 overflow;
|
||||
int i, j;
|
||||
uword *p;
|
||||
tm->hash = flowhash_alloc_8_8 (tm->fixed_entries, tm->collision_buckets);
|
||||
if (tm->hash == NULL)
|
||||
return clib_error_return (0, "Could not alloc hash");
|
||||
|
||||
fformat (stdout, "Allocated hash memory size: %llu\n",
|
||||
flowhash_memory_size (tm->hash));
|
||||
|
||||
fformat (stdout, "Pick %lld unique %s keys...\n",
|
||||
tm->nitems, tm->non_random_keys ? "non-random" : "random");
|
||||
|
||||
for (i = 0; i < tm->nitems; i++)
|
||||
{
|
||||
flowhash_lkey_8_8_t rndkey;
|
||||
if (tm->non_random_keys == 0)
|
||||
{
|
||||
again:
|
||||
rndkey.as_u64[0] = random_u64 (&tm->seed);
|
||||
if ((p = hash_get (tm->key_hash, rndkey.as_u64[0])))
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
rndkey.as_u64[0] = (u64) (i + 1) << 16;
|
||||
|
||||
hash_set (tm->key_hash, rndkey.as_u64[0], i + 1);
|
||||
vec_add1 (tm->keys, rndkey);
|
||||
}
|
||||
|
||||
hash_free (tm->key_hash);
|
||||
|
||||
/* Additions */
|
||||
overflow = 0;
|
||||
before = clib_time_now (&tm->clib_time);
|
||||
fformat (stdout, "Adding %u items...\n", tm->nitems);
|
||||
for (i = 0; i < tm->nitems; i++)
|
||||
{
|
||||
u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
|
||||
u32 ei;
|
||||
flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
|
||||
if (flowhash_is_overflow (ei))
|
||||
overflow++;
|
||||
|
||||
/* Set value (No matter if success) */
|
||||
flowhash_value (tm->hash, ei)->as_u64[0] = i + 1;
|
||||
|
||||
/* Save value until time > 1 */
|
||||
flowhash_timeout (tm->hash, ei) = 1;
|
||||
}
|
||||
|
||||
delta = clib_time_now (&tm->clib_time) - before;
|
||||
total = tm->nitems;
|
||||
fformat (stdout, "%lld additions in %.6f seconds\n", total, delta);
|
||||
if (delta > 0)
|
||||
fformat (stdout, "%.f additions per second\n", ((f64) total) / delta);
|
||||
|
||||
fformat (stdout, "%u elements in table\n", flowhash_elts_8_8 (tm->hash, 1));
|
||||
fformat (stdout, "Flowhash counters:\n");
|
||||
fformat (stdout, " collision-lookup: %lu\n",
|
||||
tm->hash->collision_lookup_counter);
|
||||
fformat (stdout, " not-enough-buckets: %lu\n",
|
||||
tm->hash->not_enough_buckets_counter);
|
||||
fformat (stdout, " overflows: %lu\n", overflow);
|
||||
|
||||
/* Lookups (very similar to additions) */
|
||||
overflow = 0;
|
||||
before = clib_time_now (&tm->clib_time);
|
||||
fformat (stdout, "Looking up %u items %u times...\n", tm->nitems,
|
||||
tm->iterations);
|
||||
|
||||
for (j = 0; j < tm->iterations; j++)
|
||||
{
|
||||
i = 0;
|
||||
if (tm->prefetch)
|
||||
for (; i < tm->nitems - tm->prefetch; i++)
|
||||
{
|
||||
u32 ei;
|
||||
u32 hash = flowhash_hash_8_8 (&tm->keys[i + tm->prefetch]);
|
||||
flowhash_prefetch (tm->hash, hash);
|
||||
hash = flowhash_hash_8_8 (&tm->keys[i]);
|
||||
flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
|
||||
if (flowhash_is_overflow (ei))
|
||||
overflow++;
|
||||
else if (flowhash_timeout (tm->hash, ei) != 1)
|
||||
clib_warning ("Key not found: %lld\n", tm->keys[i].as_u64[0]);
|
||||
else if (flowhash_value (tm->hash, ei)->as_u64[0] != i + 1)
|
||||
clib_warning ("Value mismatch for key %lld\n",
|
||||
tm->keys[i].as_u64[0]);
|
||||
}
|
||||
|
||||
for (; i < tm->nitems; i++)
|
||||
{
|
||||
u32 ei;
|
||||
u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
|
||||
flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
|
||||
if (flowhash_is_overflow (ei))
|
||||
overflow++;
|
||||
else if (flowhash_timeout (tm->hash, ei) != 1)
|
||||
clib_warning ("Key not found: %lld\n", tm->keys[i].as_u64[0]);
|
||||
else if (flowhash_value (tm->hash, ei)->as_u64[0] != i + 1)
|
||||
clib_warning ("Value mismatch for key %lld\n",
|
||||
tm->keys[i].as_u64[0]);
|
||||
}
|
||||
}
|
||||
|
||||
delta = clib_time_now (&tm->clib_time) - before;
|
||||
total = tm->nitems * tm->iterations;
|
||||
fformat (stdout, "%lld lookups in %.6f seconds\n", total, delta);
|
||||
if (delta > 0)
|
||||
fformat (stdout, "%.f lookups per second\n", ((f64) total) / delta);
|
||||
|
||||
/* Delete */
|
||||
for (i = 0; i < tm->nitems; i++)
|
||||
{
|
||||
u32 hash = flowhash_hash_8_8 (&tm->keys[i]);
|
||||
u32 ei;
|
||||
flowhash_get_8_8 (tm->hash, &tm->keys[i], hash, 1, &ei);
|
||||
flowhash_timeout (tm->hash, ei) = 0;
|
||||
}
|
||||
|
||||
fformat (stdout, "%u elements in table\n", flowhash_elts_8_8 (tm->hash, 1));
|
||||
|
||||
vec_free (tm->keys);
|
||||
flowhash_free_8_8 (tm->hash);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
clib_error_t *
|
||||
test_flowhash_main (test_main_t * tm)
|
||||
{
|
||||
unformat_input_t *i = tm->input;
|
||||
clib_error_t *error;
|
||||
|
||||
while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (i, "seed %u", &tm->seed))
|
||||
;
|
||||
else if (unformat (i, "fixed-entries %d", &tm->fixed_entries))
|
||||
;
|
||||
else if (unformat (i, "collision-buckets %d", &tm->collision_buckets))
|
||||
;
|
||||
else if (unformat (i, "non-random-keys"))
|
||||
tm->non_random_keys = 1;
|
||||
else if (unformat (i, "nitems %d", &tm->nitems))
|
||||
;
|
||||
else if (unformat (i, "prefetch %d", &tm->prefetch))
|
||||
;
|
||||
else if (unformat (i, "iterations %d", &tm->iterations))
|
||||
;
|
||||
else
|
||||
return clib_error_return (0, "unknown input '%U'",
|
||||
format_unformat_error, i);
|
||||
}
|
||||
|
||||
error = test_flowhash (tm);
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef CLIB_UNIX
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
|
||||
unformat_input_t i;
|
||||
clib_error_t *error;
|
||||
test_main_t *tm = &test_main;
|
||||
|
||||
clib_mem_init (0, 3ULL << 30);
|
||||
|
||||
tm->fixed_entries = 8 << 20;
|
||||
tm->collision_buckets = 1 << 20;
|
||||
tm->seed = 0xdeadf00l;
|
||||
tm->iterations = 1;
|
||||
tm->input = &i;
|
||||
tm->nitems = 1000;
|
||||
tm->non_random_keys = 0;
|
||||
tm->key_hash = hash_create (0, sizeof (uword));
|
||||
tm->prefetch = 0;
|
||||
clib_time_init (&tm->clib_time);
|
||||
|
||||
unformat_init_command_line (&i, argv);
|
||||
error = test_flowhash_main (tm);
|
||||
unformat_free (&i);
|
||||
|
||||
if (error)
|
||||
{
|
||||
clib_error_report (error);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CLIB_UNIX */
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2005 Eliot Dresselhaus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <vppinfra/phash.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/random.h>
|
||||
|
||||
static int verbose;
|
||||
#define if_verbose(format,args...) \
|
||||
if (verbose) { clib_warning(format, ## args); }
|
||||
|
||||
int
|
||||
test_phash_main (unformat_input_t * input)
|
||||
{
|
||||
phash_main_t _pm = { 0 }, *pm = &_pm;
|
||||
int n_keys, random_keys;
|
||||
u32 seed;
|
||||
clib_error_t *error;
|
||||
|
||||
random_keys = 1;
|
||||
n_keys = 1000;
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (0 == unformat (input, "keys %d", &n_keys)
|
||||
&& 0 == unformat (input, "verbose %=", &verbose, 1)
|
||||
&& 0 == unformat (input, "random-keys %=", &random_keys, 1)
|
||||
&& 0 == unformat (input, "sequential-keys %=", &random_keys, 0)
|
||||
&& 0 == unformat (input, "seed %d", &pm->random_seed)
|
||||
&& 0 == unformat (input, "64-bit %|", &pm->flags, PHASH_FLAG_MIX64)
|
||||
&& 0 == unformat (input, "32-bit %|", &pm->flags, PHASH_FLAG_MIX32)
|
||||
&& 0 == unformat (input, "fast %|", &pm->flags,
|
||||
PHASH_FLAG_FAST_MODE)
|
||||
&& 0 == unformat (input, "slow %|", &pm->flags,
|
||||
PHASH_FLAG_SLOW_MODE)
|
||||
&& 0 == unformat (input, "minimal %|", &pm->flags,
|
||||
PHASH_FLAG_MINIMAL)
|
||||
&& 0 == unformat (input, "non-minimal %|", &pm->flags,
|
||||
PHASH_FLAG_NON_MINIMAL))
|
||||
clib_error ("unknown input `%U'", format_unformat_error, input);
|
||||
}
|
||||
|
||||
if (!pm->random_seed)
|
||||
pm->random_seed = random_default_seed ();
|
||||
|
||||
if_verbose
|
||||
("%d %d-bit keys, random seed %d, %s mode, looking for %sminimal hash",
|
||||
n_keys, (pm->flags & PHASH_FLAG_MIX64) ? 64 : 32, pm->random_seed,
|
||||
(pm->flags & PHASH_FLAG_FAST_MODE) ? "fast" : "slow",
|
||||
(pm->flags & PHASH_FLAG_MINIMAL) ? "" : "non-");
|
||||
|
||||
seed = pm->random_seed;
|
||||
|
||||
/* Initialize random keys. */
|
||||
{
|
||||
phash_key_t *k;
|
||||
|
||||
vec_resize (pm->keys, n_keys);
|
||||
vec_foreach (k, pm->keys)
|
||||
{
|
||||
k->key = k - pm->keys;
|
||||
if (random_keys)
|
||||
{
|
||||
if (pm->flags & PHASH_FLAG_MIX64)
|
||||
k->key = random_u64 (&seed);
|
||||
else
|
||||
k->key = random_u32 (&seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error = phash_find_perfect_hash (pm);
|
||||
if (error)
|
||||
{
|
||||
clib_error_report (error);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if_verbose ("(%d,%d) (a,b) bits, %d seeds tried, %d tree walks",
|
||||
pm->a_bits, pm->b_bits,
|
||||
pm->n_seed_trials, pm->n_perfect_calls);
|
||||
|
||||
error = phash_validate (pm);
|
||||
if (error)
|
||||
{
|
||||
clib_error_report (error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CLIB_UNIX
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
unformat_input_t i;
|
||||
int res;
|
||||
|
||||
clib_mem_init (0, 64ULL << 20);
|
||||
|
||||
verbose = (argc > 1);
|
||||
unformat_init_command_line (&i, argv);
|
||||
res = test_phash_main (&i);
|
||||
unformat_free (&i);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
|
||||
#ifdef CLIB_UNIX
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <vppinfra/slist.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 *random_pool;
|
||||
u32 seed;
|
||||
u32 iter;
|
||||
u32 verbose;
|
||||
f64 branching_factor;
|
||||
clib_slist_t slist;
|
||||
} test_main_t;
|
||||
|
||||
test_main_t test_main;
|
||||
|
||||
#define foreach_simple_test \
|
||||
_(2) \
|
||||
_(4) \
|
||||
_(3) \
|
||||
_(1)
|
||||
|
||||
|
||||
void
|
||||
run_test (test_main_t * tm)
|
||||
{
|
||||
int i;
|
||||
u32 *tv;
|
||||
u32 ncompares;
|
||||
u64 total_compares = 0;
|
||||
|
||||
if (1)
|
||||
{
|
||||
/*
|
||||
* Add a bunch of random numbers to the skip-list,
|
||||
* sorting them.
|
||||
*/
|
||||
for (i = 0; i < tm->iter; i++)
|
||||
{
|
||||
pool_get (tm->random_pool, tv);
|
||||
*tv = random_u32 (&tm->seed);
|
||||
clib_slist_add (&tm->slist, tv, tv - tm->random_pool);
|
||||
}
|
||||
/* make sure we can find each one */
|
||||
for (i = 0; i < tm->iter; i++)
|
||||
{
|
||||
u32 search_result;
|
||||
tv = pool_elt_at_index (tm->random_pool, i);
|
||||
|
||||
search_result = clib_slist_search (&tm->slist, tv, &ncompares);
|
||||
ASSERT (search_result == i);
|
||||
|
||||
total_compares += ncompares;
|
||||
}
|
||||
|
||||
fformat (stdout, "%.2f avg compares/search\n",
|
||||
(f64) total_compares / (f64) i);
|
||||
|
||||
fformat (stdout, "%U\n", format_slist, &tm->slist,
|
||||
tm->iter < 1000 /* verbose */ );
|
||||
|
||||
/* delete half of them */
|
||||
for (i = tm->iter / 2; i < tm->iter; i++)
|
||||
{
|
||||
tv = pool_elt_at_index (tm->random_pool, i);
|
||||
(void) clib_slist_del (&tm->slist, tv);
|
||||
}
|
||||
|
||||
/* make sure we can find the set we should find, and no others */
|
||||
for (i = 0; i < tm->iter; i++)
|
||||
{
|
||||
u32 search_result;
|
||||
tv = pool_elt_at_index (tm->random_pool, i);
|
||||
|
||||
search_result = clib_slist_search (&tm->slist, tv, &ncompares);
|
||||
if (i >= tm->iter / 2)
|
||||
ASSERT (search_result == (u32) ~ 0);
|
||||
else
|
||||
ASSERT (search_result == i);
|
||||
|
||||
}
|
||||
|
||||
fformat (stdout, "%U\n", format_slist, &tm->slist,
|
||||
tm->iter < 1000 /* verbose */ );
|
||||
|
||||
/* delete the rest */
|
||||
for (i = 0; i < tm->iter; i++)
|
||||
{
|
||||
tv = pool_elt_at_index (tm->random_pool, i);
|
||||
|
||||
(void) clib_slist_del (&tm->slist, tv);
|
||||
}
|
||||
|
||||
fformat (stdout, "%U\n", format_slist, &tm->slist,
|
||||
tm->iter < 1000 /* verbose */ );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
#define _(n) \
|
||||
do { \
|
||||
pool_get (tm->random_pool, tv); \
|
||||
*tv = n; \
|
||||
clib_slist_add (&tm->slist, tv, tv - tm->random_pool); \
|
||||
fformat(stdout, "%U\n", format_slist, &tm->slist, 1 /* verbose */); \
|
||||
} while (0);
|
||||
foreach_simple_test;
|
||||
#undef _
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
word
|
||||
test_compare (void *key, u32 elt_index)
|
||||
{
|
||||
u32 *k = (u32 *) key;
|
||||
u32 elt = test_main.random_pool[elt_index];
|
||||
|
||||
if (*k < elt)
|
||||
return -1;
|
||||
if (*k > elt)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 *
|
||||
test_format (u8 * s, va_list * args)
|
||||
{
|
||||
u32 elt_index = va_arg (*args, u32);
|
||||
u32 elt = test_main.random_pool[elt_index];
|
||||
|
||||
return format (s, "%u", elt);
|
||||
}
|
||||
|
||||
void
|
||||
initialize_slist (test_main_t * tm)
|
||||
{
|
||||
clib_slist_init (&tm->slist, tm->branching_factor,
|
||||
test_compare, test_format);
|
||||
}
|
||||
|
||||
int
|
||||
test_slist_main (unformat_input_t * input)
|
||||
{
|
||||
test_main_t *tm = &test_main;
|
||||
u32 tmp;
|
||||
|
||||
tm->seed = 0xbabeb00b;
|
||||
tm->iter = 100000;
|
||||
tm->verbose = 1;
|
||||
tm->branching_factor = 1.0 / 5.0;
|
||||
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (unformat (input, "seed %d", &tm->seed))
|
||||
continue;
|
||||
else if (unformat (input, "iter %d", &tm->iter))
|
||||
continue;
|
||||
else if (unformat (input, "verbose"))
|
||||
tm->verbose = 1;
|
||||
else if (unformat (input, "branch %d", &tmp))
|
||||
{
|
||||
if (tmp > 0)
|
||||
tm->branching_factor = 1.0 / (f64) tmp;
|
||||
else
|
||||
fformat (stderr, "warning: branch = 0, ignored\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
clib_error ("unknown input `%U'", format_unformat_error, input);
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
initialize_slist (tm);
|
||||
run_test (tm);
|
||||
|
||||
return 0;
|
||||
|
||||
usage:
|
||||
fformat (stderr, "usage: test_slist seed <seed> iter <iter> [verbose]\n");
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
#ifdef CLIB_UNIX
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
unformat_input_t i;
|
||||
int ret;
|
||||
|
||||
clib_mem_init (0, (u64) 4 << 30);
|
||||
|
||||
unformat_init_command_line (&i, argv);
|
||||
ret = test_slist_main (&i);
|
||||
unformat_free (&i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CLIB_UNIX */
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2015 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.
|
||||
*/
|
||||
/*
|
||||
Copyright (c) 2005 Eliot Dresselhaus
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <vppinfra/zvec.h>
|
||||
#include <vppinfra/format.h>
|
||||
#include <vppinfra/random.h>
|
||||
|
||||
static int verbose;
|
||||
#define if_verbose(format,args...) \
|
||||
if (verbose) { clib_warning(format, ## args); }
|
||||
|
||||
int
|
||||
test_zvec_main (unformat_input_t * input)
|
||||
{
|
||||
uword n_iterations;
|
||||
uword i;
|
||||
u32 seed;
|
||||
|
||||
n_iterations = 1024;
|
||||
seed = 0;
|
||||
|
||||
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
|
||||
{
|
||||
if (0 == unformat (input, "iter %d", &n_iterations)
|
||||
&& 0 == unformat (input, "seed %d", &seed))
|
||||
clib_error ("unknown input `%U'", format_unformat_error, input);
|
||||
}
|
||||
|
||||
if_verbose ("%d iterations, seed %d\n", n_iterations, seed);
|
||||
|
||||
for (i = 0; i < n_iterations; i++)
|
||||
{
|
||||
uword coding, data, d[2], limit, n_zdata_bits[2];
|
||||
|
||||
if (seed)
|
||||
coding = random_u32 (&seed);
|
||||
else
|
||||
coding = i;
|
||||
|
||||
limit = coding - 1;
|
||||
if (limit > (1 << 16))
|
||||
limit = 1 << 16;
|
||||
for (data = 0; data <= limit; data++)
|
||||
{
|
||||
d[0] = zvec_encode (coding, data, &n_zdata_bits[0]);
|
||||
|
||||
if (coding != 0)
|
||||
ASSERT ((d[0] >> n_zdata_bits[0]) == 0);
|
||||
|
||||
d[1] = zvec_decode (coding, d[0], &n_zdata_bits[1]);
|
||||
ASSERT (data == d[1]);
|
||||
|
||||
ASSERT (n_zdata_bits[0] == n_zdata_bits[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CLIB_UNIX
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
unformat_input_t i;
|
||||
int ret;
|
||||
|
||||
clib_mem_init (0, 64ULL << 20);
|
||||
|
||||
verbose = (argc > 1);
|
||||
unformat_init_command_line (&i, argv);
|
||||
ret = test_zvec_main (&i);
|
||||
unformat_free (&i);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CLIB_UNIX */
|
||||
|
||||
|
||||
/*
|
||||
* fd.io coding-style-patch-verification: ON
|
||||
*
|
||||
* Local Variables:
|
||||
* eval: (c-set-style "gnu")
|
||||
* End:
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user