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:
Dave Barach
2020-04-22 10:02:31 -04:00
committed by Florin Coras
parent f932f97d7d
commit 053d093524
37 changed files with 1 additions and 23 deletions
+172
View File
@@ -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:
*/
+89
View File
@@ -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:
*/
+128
View File
@@ -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:
*/
+120
View File
@@ -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:
*/
+83
View File
@@ -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
+140
View File
@@ -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_ */
+67
View File
@@ -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
+276
View File
@@ -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
+194
View File
@@ -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:
*/
+176
View File
@@ -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
+169
View File
@@ -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
+145
View File
@@ -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:
*/
+151
View File
@@ -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
+228
View File
@@ -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
+119
View File
@@ -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