Merge pull request #742 from qlyoung/hashstats

Hashtable statistics
This commit is contained in:
Martin Winter 2017-07-04 11:58:10 -07:00 committed by GitHub
commit c6200b5467
32 changed files with 314 additions and 56 deletions

View file

@ -267,7 +267,7 @@ bgp_sync_init (struct peer *peer)
BGP_ADV_FIFO_INIT (&sync->withdraw); BGP_ADV_FIFO_INIT (&sync->withdraw);
BGP_ADV_FIFO_INIT (&sync->withdraw_low); BGP_ADV_FIFO_INIT (&sync->withdraw_low);
peer->sync[afi][safi] = sync; peer->sync[afi][safi] = sync;
peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp, NULL);
} }
} }

View file

@ -2134,7 +2134,7 @@ aspath_cmp (const void *arg1, const void *arg2)
void void
aspath_init (void) aspath_init (void)
{ {
ashash = hash_create_size (32768, aspath_key_make, aspath_cmp); ashash = hash_create_size (32768, aspath_key_make, aspath_cmp, NULL);
} }
void void

View file

@ -215,7 +215,7 @@ cluster_unintern (struct cluster_list *cluster)
static void static void
cluster_init (void) cluster_init (void)
{ {
cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp); cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp, NULL);
} }
static void static void
@ -403,9 +403,9 @@ encap_hash_cmp (const void *p1, const void *p2)
static void static void
encap_init (void) encap_init (void)
{ {
encap_hash = hash_create (encap_hash_key_make, encap_hash_cmp); encap_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
#if ENABLE_BGP_VNC #if ENABLE_BGP_VNC
vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp); vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
#endif #endif
} }
@ -517,7 +517,7 @@ transit_hash_cmp (const void *p1, const void *p2)
static void static void
transit_init (void) transit_init (void)
{ {
transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp); transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp, NULL);
} }
static void static void
@ -765,7 +765,7 @@ attrhash_cmp (const void *p1, const void *p2)
static void static void
attrhash_init (void) attrhash_init (void)
{ {
attrhash = hash_create (attrhash_key_make, attrhash_cmp); attrhash = hash_create (attrhash_key_make, attrhash_cmp, "BGP Attributes");
} }
/* /*

View file

@ -686,7 +686,7 @@ void
community_init (void) community_init (void)
{ {
comhash = hash_create ((unsigned int (*) (void *))community_hash_make, comhash = hash_create ((unsigned int (*) (void *))community_hash_make,
(int (*) (const void *, const void *))community_cmp); (int (*) (const void *, const void *))community_cmp, NULL);
} }
void void

View file

@ -284,7 +284,7 @@ ecommunity_cmp (const void *arg1, const void *arg2)
void void
ecommunity_init (void) ecommunity_init (void)
{ {
ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp); ecomhash = hash_create (ecommunity_hash_make, ecommunity_cmp, NULL);
} }
void void

View file

@ -286,7 +286,7 @@ lcommunity_hash (void)
void void
lcommunity_init (void) lcommunity_init (void)
{ {
lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp); lcomhash = hash_create (lcommunity_hash_make, lcommunity_cmp, NULL);
} }
void void

View file

@ -140,7 +140,7 @@ void
bgp_address_init (struct bgp *bgp) bgp_address_init (struct bgp *bgp)
{ {
bgp->address_hash = hash_create (bgp_address_hash_key_make, bgp->address_hash = hash_create (bgp_address_hash_key_make,
bgp_address_hash_cmp); bgp_address_hash_cmp, NULL);
} }
void void

View file

@ -87,7 +87,7 @@ sync_init (struct update_subgroup *subgrp)
BGP_ADV_FIFO_INIT (&subgrp->sync->update); BGP_ADV_FIFO_INIT (&subgrp->sync->update);
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw); BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw);
BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw_low); BGP_ADV_FIFO_INIT (&subgrp->sync->withdraw_low);
subgrp->hash = hash_create (baa_hash_key, baa_hash_cmp); subgrp->hash = hash_create (baa_hash_key, baa_hash_cmp, NULL);
/* We use a larger buffer for subgrp->work in the event that: /* We use a larger buffer for subgrp->work in the event that:
* - We RX a BGP_UPDATE where the attributes alone are just * - We RX a BGP_UPDATE where the attributes alone are just
@ -1559,7 +1559,7 @@ update_bgp_group_init (struct bgp *bgp)
AF_FOREACH (afid) AF_FOREACH (afid)
bgp->update_groups[afid] = hash_create (updgrp_hash_key_make, bgp->update_groups[afid] = hash_create (updgrp_hash_key_make,
updgrp_hash_cmp); updgrp_hash_cmp, NULL);
} }
void void

View file

@ -2910,7 +2910,7 @@ bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement"); bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
bgp->peer = list_new (); bgp->peer = list_new ();
bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp; bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
bgp->peerhash = hash_create (peer_hash_key_make, peer_hash_cmp); bgp->peerhash = hash_create (peer_hash_key_make, peer_hash_cmp, NULL);
bgp->group = list_new (); bgp->group = list_new ();
bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp; bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;

View file

@ -1589,6 +1589,11 @@ AM_CONDITIONAL([SNMP], [test "x${SNMP_METHOD}" != "x"])
AC_SUBST(SNMP_LIBS) AC_SUBST(SNMP_LIBS)
AC_SUBST(SNMP_CFLAGS) AC_SUBST(SNMP_CFLAGS)
dnl ---------------
dnl math
dnl ---------------
AC_SEARCH_LIBS([sqrt], [m])
dnl --------------- dnl ---------------
dnl dlopen & dlinfo dnl dlopen & dlinfo
dnl --------------- dnl ---------------

View file

@ -233,7 +233,7 @@ install_node (struct cmd_node *node,
// add start node // add start node
struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL); struct cmd_token *token = cmd_token_new (START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
graph_new_node (node->cmdgraph, token, (void (*)(void *)) &cmd_token_del); graph_new_node (node->cmdgraph, token, (void (*)(void *)) &cmd_token_del);
node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp); node->cmd_hash = hash_create (cmd_hash_key, cmd_hash_cmp, NULL);
} }
/** /**
@ -2520,6 +2520,7 @@ cmd_init (int terminal)
thread_cmd_init (); thread_cmd_init ();
workqueue_cmd_init (); workqueue_cmd_init ();
hash_cmd_init ();
} }
install_element (CONFIG_NODE, &hostname_cmd); install_element (CONFIG_NODE, &hostname_cmd);

View file

@ -522,7 +522,8 @@ void
distribute_list_init (int node) distribute_list_init (int node)
{ {
disthash = hash_create (distribute_hash_make, disthash = hash_create (distribute_hash_make,
(int (*) (const void *, const void *)) distribute_cmp); (int (*) (const void *, const void *))
distribute_cmp, NULL);
/* vtysh command-extraction doesn't grok install_element(node, ) */ /* vtysh command-extraction doesn't grok install_element(node, ) */
if (node == RIP_NODE) { if (node == RIP_NODE) {

View file

@ -55,7 +55,7 @@ void frr_pthread_init()
pthread_mutex_lock(&pthread_table_mtx); pthread_mutex_lock(&pthread_table_mtx);
{ {
pthread_table = pthread_table =
hash_create(pthread_table_hash_key, pthread_table_hash_cmp); hash_create(pthread_table_hash_key, pthread_table_hash_cmp, NULL);
} }
pthread_mutex_unlock(&pthread_table_mtx); pthread_mutex_unlock(&pthread_table_mtx);
} }

View file

@ -19,23 +19,33 @@
*/ */
#include <zebra.h> #include <zebra.h>
#include <math.h>
#include "hash.h" #include "hash.h"
#include "memory.h" #include "memory.h"
#include "linklist.h"
#include "termtable.h"
#include "vty.h"
#include "command.h"
#include "libfrr.h"
DEFINE_MTYPE( LIB, HASH, "Hash") DEFINE_MTYPE( LIB, HASH, "Hash")
DEFINE_MTYPE( LIB, HASH_BACKET, "Hash Bucket") DEFINE_MTYPE( LIB, HASH_BACKET, "Hash Bucket")
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index") DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct list *_hashes;
/* Allocate a new hash. */ /* Allocate a new hash. */
struct hash * struct hash *
hash_create_size (unsigned int size, unsigned int (*hash_key) (void *), hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
int (*hash_cmp) (const void *, const void *)) int (*hash_cmp) (const void *, const void *),
const char *name)
{ {
struct hash *hash; struct hash *hash;
assert ((size & (size-1)) == 0); assert ((size & (size-1)) == 0);
hash = XMALLOC (MTYPE_HASH, sizeof (struct hash)); hash = XCALLOC (MTYPE_HASH, sizeof (struct hash));
hash->index = XCALLOC (MTYPE_HASH_INDEX, hash->index = XCALLOC (MTYPE_HASH_INDEX,
sizeof (struct hash_backet *) * size); sizeof (struct hash_backet *) * size);
hash->size = size; hash->size = size;
@ -43,6 +53,17 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
hash->hash_key = hash_key; hash->hash_key = hash_key;
hash->hash_cmp = hash_cmp; hash->hash_cmp = hash_cmp;
hash->count = 0; hash->count = 0;
hash->name = name ? XSTRDUP(MTYPE_HASH, name) : NULL;
hash->stats.empty = hash->size;
pthread_mutex_lock (&_hashes_mtx);
{
if (!_hashes)
_hashes = list_new();
listnode_add (_hashes, hash);
}
pthread_mutex_unlock (&_hashes_mtx);
return hash; return hash;
} }
@ -50,9 +71,10 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
/* Allocate a new hash with default hash size. */ /* Allocate a new hash with default hash size. */
struct hash * struct hash *
hash_create (unsigned int (*hash_key) (void *), hash_create (unsigned int (*hash_key) (void *),
int (*hash_cmp) (const void *, const void *)) int (*hash_cmp) (const void *, const void *),
const char *name)
{ {
return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp); return hash_create_size (HASH_INITIAL_SIZE, hash_key, hash_cmp, name);
} }
/* Utility function for hash_get(). When this function is specified /* Utility function for hash_get(). When this function is specified
@ -64,6 +86,15 @@ hash_alloc_intern (void *arg)
return arg; return arg;
} }
#define hash_update_ssq(hz, old, new) \
do { \
long double res; \
res = powl(old, 2.0); \
hz->stats.ssq -= (uint64_t) res;\
res = powl(new, 2.0); \
hz->stats.ssq += (uint64_t) res; \
} while (0); \
/* Expand hash if the chain length exceeds the threshold. */ /* Expand hash if the chain length exceeds the threshold. */
static void hash_expand (struct hash *hash) static void hash_expand (struct hash *hash)
{ {
@ -75,6 +106,8 @@ static void hash_expand (struct hash *hash)
if (new_index == NULL) if (new_index == NULL)
return; return;
hash->stats.empty = new_size;
for (i = 0; i < hash->size; i++) for (i = 0; i < hash->size; i++)
for (hb = hash->index[i]; hb; hb = hbnext) for (hb = hash->index[i]; hb; hb = hbnext)
{ {
@ -82,6 +115,19 @@ static void hash_expand (struct hash *hash)
hbnext = hb->next; hbnext = hb->next;
hb->next = new_index[h]; hb->next = new_index[h];
int oldlen = hb->next ? hb->next->len : 0;
int newlen = oldlen + 1;
if (newlen == 1)
hash->stats.empty--;
else
hb->next->len = 0;
hb->len = newlen;
hash_update_ssq(hash, oldlen, newlen);
new_index[h] = hb; new_index[h] = hb;
} }
@ -91,19 +137,17 @@ static void hash_expand (struct hash *hash)
hash->index = new_index; hash->index = new_index;
/* Ideally, new index should have chains half as long as the original. /* Ideally, new index should have chains half as long as the original.
If expansion didn't help, then not worth expanding again, * If expansion didn't help, then not worth expanding again,
the problem is the hash function. */ * the problem is the hash function. */
losers = 0; losers = 0;
for (i = 0; i < hash->size; i++) for (i = 0; i < hash->size; i++)
{ {
unsigned int len = 0; unsigned int len = hash->index[i] ? hash->index[i]->len : 0;
for (hb = hash->index[i]; hb; hb = hb->next)
{ if (len > HASH_THRESHOLD/2)
if (++len > HASH_THRESHOLD/2) ++losers;
++losers; if (len >= HASH_THRESHOLD)
if (len >= HASH_THRESHOLD) hash->no_expand = 1;
hash->no_expand = 1;
}
} }
if (losers > hash->count / 2) if (losers > hash->count / 2)
@ -145,12 +189,25 @@ hash_get (struct hash *hash, void *data, void * (*alloc_func) (void *))
index = key & (hash->size - 1); index = key & (hash->size - 1);
} }
backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet)); backet = XCALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
backet->data = newdata; backet->data = newdata;
backet->key = key; backet->key = key;
backet->next = hash->index[index]; backet->next = hash->index[index];
hash->index[index] = backet; hash->index[index] = backet;
hash->count++; hash->count++;
int oldlen = backet->next ? backet->next->len : 0;
int newlen = oldlen + 1;
if (newlen == 1)
hash->stats.empty--;
else
backet->next->len = 0;
backet->len = newlen;
hash_update_ssq(hash, oldlen, newlen);
return backet->data; return backet->data;
} }
return NULL; return NULL;
@ -193,11 +250,21 @@ hash_release (struct hash *hash, void *data)
{ {
if (backet->key == key && (*hash->hash_cmp) (backet->data, data)) if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
{ {
if (backet == pp) int oldlen = hash->index[index]->len;
int newlen = oldlen - 1;
if (backet == pp)
hash->index[index] = backet->next; hash->index[index] = backet->next;
else else
pp->next = backet->next; pp->next = backet->next;
if (hash->index[index])
hash->index[index]->len = newlen;
else
hash->stats.empty++;
hash_update_ssq(hash, oldlen, newlen);
ret = backet->data; ret = backet->data;
XFREE (MTYPE_HASH_BACKET, backet); XFREE (MTYPE_HASH_BACKET, backet);
hash->count--; hash->count--;
@ -275,6 +342,9 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
} }
hash->index[i] = NULL; hash->index[i] = NULL;
} }
hash->stats.ssq = 0;
hash->stats.empty = hash->size;
} }
/* Free hash memory. You may call hash_clean before call this /* Free hash memory. You may call hash_clean before call this
@ -282,6 +352,136 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
void void
hash_free (struct hash *hash) hash_free (struct hash *hash)
{ {
pthread_mutex_lock (&_hashes_mtx);
{
if (_hashes)
{
listnode_delete (_hashes, hash);
if (_hashes->count == 0)
{
list_delete (_hashes);
_hashes = NULL;
}
}
}
pthread_mutex_unlock (&_hashes_mtx);
if (hash->name)
XFREE (MTYPE_HASH, hash->name);
XFREE (MTYPE_HASH_INDEX, hash->index); XFREE (MTYPE_HASH_INDEX, hash->index);
XFREE (MTYPE_HASH, hash); XFREE (MTYPE_HASH, hash);
} }
/* CLI commands ------------------------------------------------------------ */
DEFUN(show_hash_stats,
show_hash_stats_cmd,
"show hashtable [statistics]",
SHOW_STR
"Statistics about hash tables\n"
"Statistics about hash tables\n")
{
struct hash *h;
struct listnode *ln;
struct ttable *tt = ttable_new (&ttable_styles[TTSTYLE_BLANK]);
ttable_add_row (tt, "Hash table|Buckets|Entries|Empty|LF|SD|FLF|SD");
tt->style.cell.lpad = 2;
tt->style.cell.rpad = 1;
tt->style.corner = '+';
ttable_restyle (tt);
ttable_rowseps (tt, 0, BOTTOM, true, '-');
/* Summary statistics calculated are:
*
* - Load factor: This is the number of elements in the table divided by the
* number of buckets. Since this hash table implementation uses chaining,
* this value can be greater than 1. This number provides information on
* how 'full' the table is, but does not provide information on how evenly
* distributed the elements are. Notably, a load factor >= 1 does not imply
* that every bucket has an element; with a pathological hash function, all
* elements could be in a single bucket.
*
* - Full load factor: this is the number of elements in the table divided by
* the number of buckets that have some elements in them.
*
* - Std. Dev.: This is the standard deviation calculated from the relevant
* load factor. If the load factor is the mean of number of elements per
* bucket, the standard deviation measures how much any particular bucket
* is likely to deviate from the mean. As a rule of thumb this number
* should be less than 2, and ideally <= 1 for optimal performance. A
* number larger than 3 generally indicates a poor hash function.
*/
double lf; // load factor
double flf; // full load factor
double var; // overall variance
double fvar; // full variance
double stdv; // overall stddev
double fstdv; // full stddev
long double x2; // h->count ^ 2
long double ldc; // (long double) h->count
long double full; // h->size - h->stats.empty
long double ssq; // ssq casted to long double
pthread_mutex_lock (&_hashes_mtx);
for (ALL_LIST_ELEMENTS_RO (_hashes, ln, h))
{
if (!h->name)
continue;
ssq = (long double) h->stats.ssq;
x2 = powl(h->count, 2.0);
ldc = (long double) h->count;
full = h->size - h->stats.empty;
lf = h->count / (double) h->size;
flf = full ? h->count / (double) (full) : 0;
var = ldc ? (1.0 / ldc) * (ssq - x2 / ldc) : 0;
fvar = full ? (1.0 / full) * (ssq - x2 / full) : 0;
var = (var < .0001) ? 0 : var;
fvar = (fvar < .0001) ? 0 : fvar;
stdv = sqrt(var);
fstdv = sqrt(fvar);
ttable_add_row (tt, "%s|%d|%ld|%.0f%%|%.2lf|%.2lf|%.2lf|%.2lf", h->name,
h->size, h->count,
(h->stats.empty / (double) h->size)*100, lf, stdv, flf,
fstdv);
}
pthread_mutex_unlock (&_hashes_mtx);
/* display header */
char header[] = "Showing hash table statistics for ";
char underln[sizeof(header) + strlen(frr_protonameinst)];
memset (underln, '-', sizeof(underln));
underln[sizeof(underln) - 1] = '\0';
vty_outln (vty, "%s%s", header, frr_protonameinst);
vty_outln (vty, "%s", underln);
vty_outln (vty, "# allocated: %d", _hashes->count);
vty_outln (vty, "# named: %d%s", tt->nrows - 1, VTYNL);
if (tt->nrows > 1)
{
ttable_colseps (tt, 0, RIGHT, true, '|');
char *table = ttable_dump (tt, VTYNL);
vty_out (vty, "%s%s", table, VTYNL);
XFREE (MTYPE_TMP, table);
}
else
vty_outln (vty, "No named hash tables to display.");
ttable_del (tt);
return CMD_SUCCESS;
}
void
hash_cmd_init ()
{
_hashes = list_new();
install_element (ENABLE_NODE, &show_hash_stats_cmd);
}

View file

@ -22,6 +22,7 @@
#define _ZEBRA_HASH_H #define _ZEBRA_HASH_H
#include "memory.h" #include "memory.h"
#include "frratomic.h"
DECLARE_MTYPE(HASH) DECLARE_MTYPE(HASH)
DECLARE_MTYPE(HASH_BACKET) DECLARE_MTYPE(HASH_BACKET)
@ -35,6 +36,10 @@ DECLARE_MTYPE(HASH_BACKET)
struct hash_backet struct hash_backet
{ {
/* if this backet is the head of the linked listed, len denotes the number of
* elements in the list */
int len;
/* Linked list. */ /* Linked list. */
struct hash_backet *next; struct hash_backet *next;
@ -45,6 +50,14 @@ struct hash_backet
void *data; void *data;
}; };
struct hashstats
{
/* number of empty hash buckets */
_Atomic int empty;
/* sum of squares of bucket length */
_Atomic uint64_t ssq;
};
struct hash struct hash
{ {
/* Hash backet. */ /* Hash backet. */
@ -64,12 +77,19 @@ struct hash
/* Backet alloc. */ /* Backet alloc. */
unsigned long count; unsigned long count;
struct hashstats stats;
/* hash name */
char *name;
}; };
extern struct hash *hash_create (unsigned int (*) (void *), extern struct hash *hash_create (unsigned int (*) (void *),
int (*) (const void *, const void *)); int (*) (const void *, const void *),
const char *);
extern struct hash *hash_create_size (unsigned int, unsigned int (*) (void *), extern struct hash *hash_create_size (unsigned int, unsigned int (*) (void *),
int (*) (const void *, const void *)); int (*) (const void *, const void *),
const char *);
extern void *hash_get (struct hash *, void *, void * (*) (void *)); extern void *hash_get (struct hash *, void *, void * (*) (void *));
extern void *hash_alloc_intern (void *); extern void *hash_alloc_intern (void *);
@ -87,4 +107,6 @@ extern void hash_free (struct hash *);
extern unsigned int string_hash_make (const char *); extern unsigned int string_hash_make (const char *);
extern void hash_cmd_init (void);
#endif /* _ZEBRA_HASH_H */ #endif /* _ZEBRA_HASH_H */

View file

@ -316,7 +316,7 @@ if_rmap_reset ()
void void
if_rmap_init (int node) if_rmap_init (int node)
{ {
ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp); ifrmaphash = hash_create (if_rmap_hash_make, if_rmap_hash_cmp, NULL);
if (node == RIPNG_NODE) { if (node == RIPNG_NODE) {
} else if (node == RIP_NODE) { } else if (node == RIP_NODE) {
install_element (RIP_NODE, &if_rmap_cmd); install_element (RIP_NODE, &if_rmap_cmd);

View file

@ -97,7 +97,7 @@ void qobj_init (void)
if (!nodes) if (!nodes)
{ {
pthread_rwlock_init (&nodes_lock, NULL); pthread_rwlock_init (&nodes_lock, NULL);
nodes = hash_create (qobj_key, qobj_cmp); nodes = hash_create (qobj_key, qobj_cmp, NULL);
} }
} }

View file

@ -1767,7 +1767,7 @@ route_map_dep_hash_alloc(void *p)
dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep)); dep_entry = XCALLOC(MTYPE_ROUTE_MAP_DEP, sizeof(struct route_map_dep));
dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name); dep_entry->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key, dep_entry->dep_rmap_hash = hash_create(route_map_dep_hash_make_key,
route_map_rmap_hash_cmp); route_map_rmap_hash_cmp, NULL);
dep_entry->this_hash = NULL; dep_entry->this_hash = NULL;
return((void *)dep_entry); return((void *)dep_entry);
@ -2986,11 +2986,11 @@ route_map_init (void)
/* Make vector for match and set. */ /* Make vector for match and set. */
route_match_vec = vector_init (1); route_match_vec = vector_init (1);
route_set_vec = vector_init (1); route_set_vec = vector_init (1);
route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp); route_map_master_hash = hash_create(route_map_hash_key_make, route_map_hash_cmp, NULL);
for (i = 1; i < ROUTE_MAP_DEP_MAX; i++) for (i = 1; i < ROUTE_MAP_DEP_MAX; i++)
route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key, route_map_dep_hash[i] = hash_create(route_map_dep_hash_make_key,
route_map_dep_hash_cmp); route_map_dep_hash_cmp, NULL);
cmd_variable_handler_register(rmap_var_handlers); cmd_variable_handler_register(rmap_var_handlers);

View file

@ -388,7 +388,7 @@ thread_master_create (const char *name)
rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key, rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
(int (*) (const void *, const void *)) (int (*) (const void *, const void *))
cpu_record_hash_cmp); cpu_record_hash_cmp, NULL);
/* Initialize the timer queues */ /* Initialize the timer queues */

View file

@ -81,7 +81,7 @@ struct nhrp_cache *nhrp_cache_get(struct interface *ifp, union sockunion *remote
struct nhrp_cache key; struct nhrp_cache key;
if (!nifp->cache_hash) { if (!nifp->cache_hash) {
nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp); nifp->cache_hash = hash_create(nhrp_cache_protocol_key, nhrp_cache_protocol_cmp, NULL);
if (!nifp->cache_hash) if (!nifp->cache_hash)
return NULL; return NULL;
} }

View file

@ -182,7 +182,7 @@ struct nhrp_peer *nhrp_peer_get(struct interface *ifp, const union sockunion *re
struct nhrp_vc *vc; struct nhrp_vc *vc;
if (!nifp->peer_hash) { if (!nifp->peer_hash) {
nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp); nifp->peer_hash = hash_create(nhrp_peer_key, nhrp_peer_cmp, NULL);
if (!nifp->peer_hash) return NULL; if (!nifp->peer_hash) return NULL;
} }

View file

@ -196,7 +196,7 @@ void nhrp_vc_init(void)
{ {
size_t i; size_t i;
nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp); nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, NULL);
for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
list_init(&childlist_head[i]); list_init(&childlist_head[i]);
} }

View file

@ -17,7 +17,7 @@ static int nhrp_reqid_cmp(const void *data, const void *key)
uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *)) uint32_t nhrp_reqid_alloc(struct nhrp_reqid_pool *p, struct nhrp_reqid *r, void (*cb)(struct nhrp_reqid *, void *))
{ {
if (!p->reqid_hash) { if (!p->reqid_hash) {
p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp); p->reqid_hash = hash_create(nhrp_reqid_key, nhrp_reqid_cmp, NULL);
p->next_request_id = 1; p->next_request_id = 1;
} }

View file

@ -180,7 +180,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare; pim_ifp->pim_ifchannel_list->cmp = (int (*)(void *, void *)) pim_ifchannel_compare;
pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key, pim_ifp->pim_ifchannel_hash = hash_create (pim_ifchannel_hash_key,
pim_ifchannel_equal); pim_ifchannel_equal, NULL);
ifp->info = pim_ifp; ifp->info = pim_ifp;

View file

@ -822,7 +822,7 @@ static struct igmp_sock *igmp_sock_new(int fd,
igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free; igmp->igmp_group_list->del = (void (*)(void *)) igmp_group_free;
igmp->igmp_group_hash = hash_create (igmp_group_hash_key, igmp->igmp_group_hash = hash_create (igmp_group_hash_key,
igmp_group_hash_equal); igmp_group_hash_equal, NULL);
igmp->fd = fd; igmp->fd = fd;
igmp->interface = ifp; igmp->interface = ifp;

View file

@ -1570,13 +1570,13 @@ pim_msdp_init(struct thread_master *master)
msdp->master = master; msdp->master = master;
msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make, msdp->peer_hash = hash_create(pim_msdp_peer_hash_key_make,
pim_msdp_peer_hash_eq); pim_msdp_peer_hash_eq, NULL);
msdp->peer_list = list_new(); msdp->peer_list = list_new();
msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free; msdp->peer_list->del = (void (*)(void *))pim_msdp_peer_free;
msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp; msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make, msdp->sa_hash = hash_create(pim_msdp_sa_hash_key_make,
pim_msdp_sa_hash_eq); pim_msdp_sa_hash_eq, NULL);
msdp->sa_list = list_new(); msdp->sa_list = list_new();
msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free; msdp->sa_list->del = (void (*)(void *))pim_msdp_sa_free;
msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp; msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;

View file

@ -103,7 +103,7 @@ void
pim_oil_init (void) pim_oil_init (void)
{ {
pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key, pim_channel_oil_hash = hash_create_size (8192, pim_oil_hash_key,
pim_oil_equal); pim_oil_equal, NULL);
pim_channel_oil_list = list_new(); pim_channel_oil_list = list_new();
if (!pim_channel_oil_list) { if (!pim_channel_oil_list) {

View file

@ -1760,7 +1760,7 @@ pim_upstream_init (void)
pim_upstream_hash_key, pim_upstream_hash_key,
pim_upstream_sg_running); pim_upstream_sg_running);
pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key, pim_upstream_hash = hash_create_size (8192, pim_upstream_hash_key,
pim_upstream_equal); pim_upstream_equal, NULL);
pim_upstream_list = list_new (); pim_upstream_list = list_new ();
pim_upstream_list->del = (void (*)(void *)) pim_upstream_free; pim_upstream_list->del = (void (*)(void *)) pim_upstream_free;

View file

@ -250,7 +250,7 @@ pim_instance_init (vrf_id_t vrf_id, afi_t afi)
pim->spt.switchover = PIM_SPT_IMMEDIATE; pim->spt.switchover = PIM_SPT_IMMEDIATE;
pim->spt.plist = NULL; pim->spt.plist = NULL;
pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal); pim->rpf_hash = hash_create_size (256, pim_rpf_hash_key, pim_rpf_equal, NULL);
if (PIM_DEBUG_ZEBRA) if (PIM_DEBUG_ZEBRA)
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__); zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);

View file

@ -140,7 +140,7 @@ test_state_new(void)
rv->table = srcdest_table_init(); rv->table = srcdest_table_init();
assert(rv->table); assert(rv->table);
rv->log = hash_create(log_key, log_cmp); rv->log = hash_create(log_key, log_cmp, NULL);
return rv; return rv;
} }

View file

@ -2103,6 +2103,33 @@ DEFUN (vtysh_show_work_queues_daemon,
return ret; return ret;
} }
DEFUN (vtysh_show_hashtable,
vtysh_show_hashtable_cmd,
"show hashtable [statistics]",
SHOW_STR
"Statistics about hash tables\n"
"Statistics about hash tables\n")
{
char cmd[] = "do show hashtable statistics";
unsigned long i;
int ret = CMD_SUCCESS;
fprintf (stdout, "\n");
fprintf (stdout, "Load factor (LF) - average number of elements across all buckets\n");
fprintf (stdout, "Full load factor (FLF) - average number of elements across full buckets\n\n");
fprintf (stdout, "Standard deviation (SD) is calculated for both the LF and FLF\n");
fprintf (stdout, "and indicates the typical deviation of bucket chain length\n");
fprintf (stdout, "from the value in the corresponding load factor.\n\n");
for (i = 0; i < array_size(vtysh_client); i++)
if ( vtysh_client[i].fd >= 0 ) {
ret = vtysh_client_execute (&vtysh_client[i], cmd, stdout);
fprintf (stdout, "\n");
}
return ret;
}
DEFUNSH (VTYSH_ZEBRA, DEFUNSH (VTYSH_ZEBRA,
vtysh_link_params, vtysh_link_params,
vtysh_link_params_cmd, vtysh_link_params_cmd,
@ -3575,6 +3602,8 @@ vtysh_init_vty (void)
install_element (VIEW_NODE, &vtysh_show_work_queues_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_cmd);
install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); install_element (VIEW_NODE, &vtysh_show_work_queues_daemon_cmd);
install_element (VIEW_NODE, &vtysh_show_hashtable_cmd);
install_element (VIEW_NODE, &vtysh_show_thread_cmd); install_element (VIEW_NODE, &vtysh_show_thread_cmd);
/* Logging */ /* Logging */

View file

@ -2994,8 +2994,8 @@ zebra_mpls_init_tables (struct zebra_vrf *zvrf)
{ {
if (!zvrf) if (!zvrf)
return; return;
zvrf->slsp_table = hash_create(label_hash, label_cmp); zvrf->slsp_table = hash_create(label_hash, label_cmp, NULL);
zvrf->lsp_table = hash_create(label_hash, label_cmp); zvrf->lsp_table = hash_create(label_hash, label_cmp, NULL);
zvrf->fec_table[AFI_IP] = route_table_init(); zvrf->fec_table[AFI_IP] = route_table_init();
zvrf->fec_table[AFI_IP6] = route_table_init(); zvrf->fec_table[AFI_IP6] = route_table_init();
zvrf->mpls_flags = 0; zvrf->mpls_flags = 0;