From owner-svn-src-head@FreeBSD.ORG Mon Jan 23 16:43:14 2012 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 47DA6106564A; Mon, 23 Jan 2012 16:43:14 +0000 (UTC) (envelope-from glebius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 2C5FA8FC1A; Mon, 23 Jan 2012 16:43:14 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q0NGhEEx034944; Mon, 23 Jan 2012 16:43:14 GMT (envelope-from glebius@svn.freebsd.org) Received: (from glebius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q0NGhE9B034942; Mon, 23 Jan 2012 16:43:14 GMT (envelope-from glebius@svn.freebsd.org) Message-Id: <201201231643.q0NGhE9B034942@svn.freebsd.org> From: Gleb Smirnoff Date: Mon, 23 Jan 2012 16:43:14 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r230487 - head/sys/netgraph X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Jan 2012 16:43:14 -0000 Author: glebius Date: Mon Jan 23 16:43:13 2012 New Revision: 230487 URL: http://svn.freebsd.org/changeset/base/230487 Log: Provide a findhook method for ng_socket(4). The node stores a hash with names of its hooks. It starts with size of 16, and grows when number of hooks reaches twice the current size. A failure to grow (memory is allocated with M_NOWAIT) isn't fatal, however. I used standard hash(9) function for the hash. With 25000 hooks named in the mpd (ports/net/mpd5) manner of "b%u", the distributions is the following: 72.1% entries consist of one element, 22.1% consist of two, 5.2% consist of three and 0.6% of four. Speedup in a synthetic test that creates 25000 hooks and then runs through a long cyclce dereferencing them in a random order is over 25 times. Modified: head/sys/netgraph/ng_socket.c Modified: head/sys/netgraph/ng_socket.c ============================================================================== --- head/sys/netgraph/ng_socket.c Mon Jan 23 16:31:46 2012 (r230486) +++ head/sys/netgraph/ng_socket.c Mon Jan 23 16:43:13 2012 (r230487) @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -112,6 +113,7 @@ static ng_rcvmsg_t ngs_rcvmsg; static ng_shutdown_t ngs_shutdown; static ng_newhook_t ngs_newhook; static ng_connect_t ngs_connect; +static ng_findhook_t ngs_findhook; static ng_rcvdata_t ngs_rcvdata; static ng_disconnect_t ngs_disconnect; @@ -137,6 +139,7 @@ static struct ng_type typestruct = { .shutdown = ngs_shutdown, .newhook = ngs_newhook, .connect = ngs_connect, + .findhook = ngs_findhook, .rcvdata = ngs_rcvdata, .disconnect = ngs_disconnect, }; @@ -162,11 +165,19 @@ static struct mtx ngsocketlist_mtx; #define TRAP_ERROR #endif +struct hookpriv { + LIST_ENTRY(hookpriv) next; + hook_p hook; +}; +LIST_HEAD(ngshash, hookpriv); + /* Per-node private data */ struct ngsock { struct ng_node *node; /* the associated netgraph node */ struct ngpcb *datasock; /* optional data socket */ struct ngpcb *ctlsock; /* optional control socket */ + struct ngshash *hash; /* hash for hook names */ + u_long hmask; /* hash mask */ int flags; int refs; struct mtx mtx; /* mtx to wait on */ @@ -537,8 +548,14 @@ ng_attach_cntl(struct socket *so) return (error); } - /* Allocate node private info */ + /* + * Allocate node private info and hash. We start + * with 16 hash entries, however we may grow later + * in ngs_newhook(). We can't predict how much hooks + * does this node plan to have. + */ priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); + priv->hash = hashinit(16, M_NETGRAPH_SOCK, &priv->hmask); /* Initialize mutex. */ mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF); @@ -643,6 +660,7 @@ ng_socket_free_priv(struct ngsock *priv) if (priv->refs == 0) { mtx_destroy(&priv->mtx); + hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask); free(priv, M_NETGRAPH_SOCK); return; } @@ -752,6 +770,35 @@ ngs_constructor(node_p nodep) return (EINVAL); } +static void +ngs_rehash(node_p node) +{ + struct ngsock *priv = NG_NODE_PRIVATE(node); + struct ngshash *new; + struct hookpriv *hp; + hook_p hook; + uint32_t h; + u_long hmask; + + new = hashinit_flags((priv->hmask + 1) * 2, M_NETGRAPH_SOCK, &hmask, + HASH_NOWAIT); + if (new == NULL) + return; + + LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) { + hp = NG_HOOK_PRIVATE(hook); +#ifdef INVARIANTS + LIST_REMOVE(hp, next); +#endif + h = hash32_str(NG_HOOK_NAME(hook), HASHINIT) & hmask; + LIST_INSERT_HEAD(&new[h], hp, next); + } + + hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask); + priv->hash = new; + priv->hmask = hmask; +} + /* * We allow any hook to be connected to the node. * There is no per-hook private information though. @@ -759,7 +806,20 @@ ngs_constructor(node_p nodep) static int ngs_newhook(node_p node, hook_p hook, const char *name) { - NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); + struct ngsock *const priv = NG_NODE_PRIVATE(node); + struct hookpriv *hp; + uint32_t h; + + hp = malloc(sizeof(*hp), M_NETGRAPH_SOCK, M_NOWAIT); + if (hp == NULL) + return (ENOMEM); + if (node->nd_numhooks * 2 > priv->hmask) + ngs_rehash(node); + hp->hook = hook; + h = hash32_str(name, HASHINIT) & priv->hmask; + LIST_INSERT_HEAD(&priv->hash[h], hp, next); + NG_HOOK_SET_PRIVATE(hook, hp); + return (0); } @@ -781,6 +841,41 @@ ngs_connect(hook_p hook) return (0); } +/* Look up hook by name */ +static hook_p +ngs_findhook(node_p node, const char *name) +{ + struct ngsock *priv = NG_NODE_PRIVATE(node); + struct hookpriv *hp; + uint32_t h; + + /* + * Microoptimisations for a ng_socket with no + * hooks, or with a single hook, which is a + * common case. + */ + if (node->nd_numhooks == 0) + return (NULL); + if (node->nd_numhooks == 1) { + hook_p hook; + + hook = LIST_FIRST(&node->nd_hooks); + + if (strcmp(NG_HOOK_NAME(hook), name) == 0) + return (hook); + else + return (NULL); + } + + h = hash32_str(name, HASHINIT) & priv->hmask; + + LIST_FOREACH(hp, &priv->hash[h], next) + if (strcmp(NG_HOOK_NAME(hp->hook), name) == 0) + return (hp->hook); + + return (NULL); +} + /* * Incoming messages get passed up to the control socket. * Unless they are for us specifically (socket_type) @@ -948,6 +1043,10 @@ ngs_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct ngsock *const priv = NG_NODE_PRIVATE(node); + struct hookpriv *hp = NG_HOOK_PRIVATE(hook); + + LIST_REMOVE(hp, next); + free(hp, M_NETGRAPH_SOCK); if ((priv->datasock) && (priv->datasock->ng_socket)) { if (NG_NODE_NUMHOOKS(node) == 1)