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_low);
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
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

View file

@ -215,7 +215,7 @@ cluster_unintern (struct cluster_list *cluster)
static 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
@ -403,9 +403,9 @@ encap_hash_cmp (const void *p1, const void *p2)
static 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
vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp);
vnc_hash = hash_create (encap_hash_key_make, encap_hash_cmp, NULL);
#endif
}
@ -517,7 +517,7 @@ transit_hash_cmp (const void *p1, const void *p2)
static 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
@ -765,7 +765,7 @@ attrhash_cmp (const void *p1, const void *p2)
static 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)
{
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

View file

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

View file

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

View file

@ -140,7 +140,7 @@ void
bgp_address_init (struct bgp *bgp)
{
bgp->address_hash = hash_create (bgp_address_hash_key_make,
bgp_address_hash_cmp);
bgp_address_hash_cmp, NULL);
}
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->withdraw);
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 RX a BGP_UPDATE where the attributes alone are just
@ -1559,7 +1559,7 @@ update_bgp_group_init (struct bgp *bgp)
AF_FOREACH (afid)
bgp->update_groups[afid] = hash_create (updgrp_hash_key_make,
updgrp_hash_cmp);
updgrp_hash_cmp, NULL);
}
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 = list_new ();
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->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_CFLAGS)
dnl ---------------
dnl math
dnl ---------------
AC_SEARCH_LIBS([sqrt], [m])
dnl ---------------
dnl dlopen & dlinfo
dnl ---------------

View file

@ -233,7 +233,7 @@ install_node (struct cmd_node *node,
// add start node
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);
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 ();
workqueue_cmd_init ();
hash_cmd_init ();
}
install_element (CONFIG_NODE, &hostname_cmd);

View file

@ -522,7 +522,8 @@ void
distribute_list_init (int node)
{
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, ) */
if (node == RIP_NODE) {

View file

@ -55,7 +55,7 @@ void frr_pthread_init()
pthread_mutex_lock(&pthread_table_mtx);
{
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);
}

View file

@ -19,23 +19,33 @@
*/
#include <zebra.h>
#include <math.h>
#include "hash.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_BACKET, "Hash Bucket")
DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct list *_hashes;
/* Allocate a new hash. */
struct hash *
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;
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,
sizeof (struct hash_backet *) * 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_cmp = hash_cmp;
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;
}
@ -50,9 +71,10 @@ hash_create_size (unsigned int size, unsigned int (*hash_key) (void *),
/* Allocate a new hash with default hash size. */
struct hash *
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
@ -64,6 +86,15 @@ hash_alloc_intern (void *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. */
static void hash_expand (struct hash *hash)
{
@ -75,6 +106,8 @@ static void hash_expand (struct hash *hash)
if (new_index == NULL)
return;
hash->stats.empty = new_size;
for (i = 0; i < hash->size; i++)
for (hb = hash->index[i]; hb; hb = hbnext)
{
@ -82,6 +115,19 @@ static void hash_expand (struct hash *hash)
hbnext = hb->next;
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;
}
@ -91,19 +137,17 @@ static void hash_expand (struct hash *hash)
hash->index = new_index;
/* Ideally, new index should have chains half as long as the original.
If expansion didn't help, then not worth expanding again,
the problem is the hash function. */
* If expansion didn't help, then not worth expanding again,
* the problem is the hash function. */
losers = 0;
for (i = 0; i < hash->size; i++)
{
unsigned int len = 0;
for (hb = hash->index[i]; hb; hb = hb->next)
{
if (++len > HASH_THRESHOLD/2)
++losers;
if (len >= HASH_THRESHOLD)
hash->no_expand = 1;
}
unsigned int len = hash->index[i] ? hash->index[i]->len : 0;
if (len > HASH_THRESHOLD/2)
++losers;
if (len >= HASH_THRESHOLD)
hash->no_expand = 1;
}
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);
}
backet = XMALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
backet = XCALLOC (MTYPE_HASH_BACKET, sizeof (struct hash_backet));
backet->data = newdata;
backet->key = key;
backet->next = hash->index[index];
hash->index[index] = backet;
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 NULL;
@ -193,11 +250,21 @@ hash_release (struct hash *hash, void *data)
{
if (backet->key == key && (*hash->hash_cmp) (backet->data, data))
{
int oldlen = hash->index[index]->len;
int newlen = oldlen - 1;
if (backet == pp)
hash->index[index] = backet->next;
else
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;
XFREE (MTYPE_HASH_BACKET, backet);
hash->count--;
@ -275,6 +342,9 @@ hash_clean (struct hash *hash, void (*free_func) (void *))
}
hash->index[i] = NULL;
}
hash->stats.ssq = 0;
hash->stats.empty = hash->size;
}
/* 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
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, 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
#include "memory.h"
#include "frratomic.h"
DECLARE_MTYPE(HASH)
DECLARE_MTYPE(HASH_BACKET)
@ -35,6 +36,10 @@ DECLARE_MTYPE(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. */
struct hash_backet *next;
@ -45,6 +50,14 @@ struct hash_backet
void *data;
};
struct hashstats
{
/* number of empty hash buckets */
_Atomic int empty;
/* sum of squares of bucket length */
_Atomic uint64_t ssq;
};
struct hash
{
/* Hash backet. */
@ -64,12 +77,19 @@ struct hash
/* Backet alloc. */
unsigned long count;
struct hashstats stats;
/* hash name */
char *name;
};
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 *),
int (*) (const void *, const void *));
int (*) (const void *, const void *),
const char *);
extern void *hash_get (struct hash *, void *, void * (*) (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 void hash_cmd_init (void);
#endif /* _ZEBRA_HASH_H */

View file

@ -316,7 +316,7 @@ if_rmap_reset ()
void
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) {
} else if (node == RIP_NODE) {
install_element (RIP_NODE, &if_rmap_cmd);

View file

@ -97,7 +97,7 @@ void qobj_init (void)
if (!nodes)
{
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->dep_name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, dep_name);
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;
return((void *)dep_entry);
@ -2986,11 +2986,11 @@ route_map_init (void)
/* Make vector for match and set. */
route_match_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++)
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);

View file

@ -388,7 +388,7 @@ thread_master_create (const char *name)
rv->cpu_record = hash_create ((unsigned int (*) (void *))cpu_record_hash_key,
(int (*) (const void *, const void *))
cpu_record_hash_cmp);
cpu_record_hash_cmp, NULL);
/* 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;
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)
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;
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;
}

View file

@ -196,7 +196,7 @@ void nhrp_vc_init(void)
{
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++)
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 *))
{
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;
}

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_hash = hash_create (pim_ifchannel_hash_key,
pim_ifchannel_equal);
pim_ifchannel_equal, NULL);
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_hash = hash_create (igmp_group_hash_key,
igmp_group_hash_equal);
igmp_group_hash_equal, NULL);
igmp->fd = fd;
igmp->interface = ifp;

View file

@ -1570,13 +1570,13 @@ pim_msdp_init(struct thread_master *master)
msdp->master = master;
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->del = (void (*)(void *))pim_msdp_peer_free;
msdp->peer_list->cmp = (int (*)(void *, void *))pim_msdp_peer_comp;
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->del = (void (*)(void *))pim_msdp_sa_free;
msdp->sa_list->cmp = (int (*)(void *, void *))pim_msdp_sa_comp;

View file

@ -103,7 +103,7 @@ void
pim_oil_init (void)
{
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();
if (!pim_channel_oil_list) {

View file

@ -1760,7 +1760,7 @@ pim_upstream_init (void)
pim_upstream_hash_key,
pim_upstream_sg_running);
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->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.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)
zlog_debug ("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);

View file

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

View file

@ -2103,6 +2103,33 @@ DEFUN (vtysh_show_work_queues_daemon,
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,
vtysh_link_params,
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_daemon_cmd);
install_element (VIEW_NODE, &vtysh_show_hashtable_cmd);
install_element (VIEW_NODE, &vtysh_show_thread_cmd);
/* Logging */

View file

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