Skip to content

Commit

Permalink
net: Add buffer pool to replace connection allocation
Browse files Browse the repository at this point in the history
Our net socket connection allocations are powerful but redundant
because they're implemented once in each protocol.  This is not good for
further optimizing and extending to other allocations, so maybe we can
add a common implementation for the usage.

Impact:
1. We add a `struct net_bufpool_s` as pool descriptor, which may use a
   little bit more memory than previous implementation (~28Bytes).
2. We share same functions between pools, so code size may shrink under
   some scenarios.

Signed-off-by: Zhe Weng <[email protected]>
  • Loading branch information
wengzhe committed Dec 19, 2024
1 parent d700641 commit cc2cfe3
Show file tree
Hide file tree
Showing 15 changed files with 436 additions and 722 deletions.
79 changes: 17 additions & 62 deletions net/bluetooth/bluetooth_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,19 @@
#include <nuttx/net/bluetooth.h>

#include "devif/devif.h"
#include "utils/utils.h"
#include "bluetooth/bluetooth.h"

#ifdef CONFIG_NET_BLUETOOTH

/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

#ifndef CONFIG_NET_BLUETOOTH_MAX_CONNS
# define CONFIG_NET_BLUETOOTH_MAX_CONNS 0
#endif

/****************************************************************************
* Private Data
****************************************************************************/
Expand All @@ -54,14 +63,10 @@
* network lock.
*/

#if CONFIG_NET_BLUETOOTH_PREALLOC_CONNS > 0
static struct bluetooth_conn_s
g_bluetooth_connections[CONFIG_NET_BLUETOOTH_PREALLOC_CONNS];
#endif

/* A list of all free packet socket connections */

static dq_queue_t g_free_bluetooth_connections;
NET_BUFPOOL_DECLARE(g_bluetooth_connections, sizeof(struct bluetooth_conn_s),
CONFIG_NET_BLUETOOTH_PREALLOC_CONNS,
CONFIG_NET_BLUETOOTH_ALLOC_CONNS,
CONFIG_NET_BLUETOOTH_MAX_CONNS);

/* A list of all allocated packet socket connections */

Expand Down Expand Up @@ -90,17 +95,7 @@ static const bt_addr_t g_any_addr =

void bluetooth_conn_initialize(void)
{
#if CONFIG_NET_BLUETOOTH_PREALLOC_CONNS > 0
int i;

for (i = 0; i < CONFIG_NET_BLUETOOTH_PREALLOC_CONNS; i++)
{
/* Link each pre-allocated connection structure into the free list. */

dq_addlast(&g_bluetooth_connections[i].bc_conn.node,
&g_free_bluetooth_connections);
}
#endif
NET_BUFPOOL_INIT(g_bluetooth_connections);
}

/****************************************************************************
Expand All @@ -115,39 +110,12 @@ void bluetooth_conn_initialize(void)
FAR struct bluetooth_conn_s *bluetooth_conn_alloc(void)
{
FAR struct bluetooth_conn_s *conn;
#if CONFIG_NET_BLUETOOTH_ALLOC_CONNS > 0
int i;
#endif

/* The free list is protected by the network lock */

net_lock();
#if CONFIG_NET_BLUETOOTH_ALLOC_CONNS > 0
if (dq_peek(&g_active_bluetooth_connections) == NULL)
{
#if CONFIG_NET_BLUETOOTH_MAX_CONNS > 0
if (dq_count(&g_active_bluetooth_connections) +
CONFIG_NET_BLUETOOTH_ALLOC_CONNS > CONFIG_NET_BLUETOOTH_MAX_CONNS)
{
net_unlock();
return NULL;
}
#endif

conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_BLUETOOTH_ALLOC_CONNS);
if (conn != NULL)
{
for (i = 0; i < CONFIG_NET_BLUETOOTH_ALLOC_CONNS; i++)
{
dq_addlast(&conn[i].bc_conn.node,
&g_active_bluetooth_connections);
}
}
}
#endif

conn = (FAR struct bluetooth_conn_s *)
dq_remfirst(&g_free_bluetooth_connections);
conn = NET_BUFPOOL_TRYALLOC(g_bluetooth_connections);
if (conn)
{
/* Mark as unbound */
Expand Down Expand Up @@ -207,22 +175,9 @@ void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn)
bluetooth_container_free(container);
}

/* If this is a preallocated or a batch allocated connection store it in
* the free connections list. Else free it.
*/
/* Free the connection structure */

#if CONFIG_NET_BLUETOOTH_ALLOC_CONNS == 1
if (conn < g_bluetooth_connections || conn >= (g_bluetooth_connections +
CONFIG_NET_BLUETOOTH_PREALLOC_CONNS))
{
kmm_free(conn);
}
else
#endif
{
memset(conn, 0, sizeof(*conn));
dq_addlast(&conn->bc_conn.node, &g_free_bluetooth_connections);
}
NET_BUFPOOL_FREE(g_bluetooth_connections, conn);

net_unlock();
}
Expand Down
73 changes: 15 additions & 58 deletions net/can/can_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,22 @@
#ifdef CONFIG_NET_CAN

/****************************************************************************
* Private Data
* Pre-processor Definitions
****************************************************************************/

/* The array containing all NetLink connections. */

#if CONFIG_CAN_PREALLOC_CONNS > 0
static struct can_conn_s g_can_connections[CONFIG_CAN_PREALLOC_CONNS];
#ifndef CONFIG_CAN_MAX_CONNS
# define CONFIG_CAN_MAX_CONNS 0
#endif

/* A list of all free NetLink connections */
/****************************************************************************
* Private Data
****************************************************************************/

/* The array containing all NetLink connections. */

static dq_queue_t g_free_can_connections;
NET_BUFPOOL_DECLARE(g_can_connections, sizeof(struct can_conn_s),
CONFIG_CAN_PREALLOC_CONNS, CONFIG_CAN_ALLOC_CONNS,
CONFIG_CAN_MAX_CONNS);
static mutex_t g_free_lock = NXMUTEX_INITIALIZER;

/* A list of all allocated NetLink connections */
Expand All @@ -79,16 +83,7 @@ static dq_queue_t g_active_can_connections;

void can_initialize(void)
{
#if CONFIG_CAN_PREALLOC_CONNS > 0
int i;

for (i = 0; i < CONFIG_CAN_PREALLOC_CONNS; i++)
{
/* Mark the connection closed and move it to the free list */

dq_addlast(&g_can_connections[i].sconn.node, &g_free_can_connections);
}
#endif
NET_BUFPOOL_INIT(g_can_connections);
}

/****************************************************************************
Expand All @@ -103,37 +98,12 @@ void can_initialize(void)
FAR struct can_conn_s *can_alloc(void)
{
FAR struct can_conn_s *conn;
#if CONFIG_CAN_ALLOC_CONNS > 0
int i;
#endif

/* The free list is protected by a a mutex. */

nxmutex_lock(&g_free_lock);
#if CONFIG_CAN_ALLOC_CONNS > 0
if (dq_peek(&g_free_can_connections) == NULL)
{
#if CONFIG_CAN_MAX_CONNS > 0
if (dq_count(&g_active_can_connections) +
CONFIG_CAN_ALLOC_CONNS > CONFIG_CAN_MAX_CONNS)
{
nxmutex_unlock(&g_free_lock);
return NULL;
}
#endif

conn = kmm_zalloc(sizeof(*conn) * CONFIG_CAN_ALLOC_CONNS);
if (conn != NULL)
{
for (i = 0; i < CONFIG_CAN_ALLOC_CONNS; i++)
{
dq_addlast(&conn[i].sconn.node, &g_free_can_connections);
}
}
}
#endif

conn = (FAR struct can_conn_s *)dq_remfirst(&g_free_can_connections);
conn = NET_BUFPOOL_TRYALLOC(g_can_connections);
if (conn != NULL)
{
/* FIXME SocketCAN default behavior enables loopback */
Expand Down Expand Up @@ -184,22 +154,9 @@ void can_free(FAR struct can_conn_s *conn)

dq_rem(&conn->sconn.node, &g_active_can_connections);

/* If this is a preallocated or a batch allocated connection store it in
* the free connections list. Else free it.
*/
/* Free the connection. */

#if CONFIG_CAN_ALLOC_CONNS == 1
if (conn < g_can_connections || conn >= (g_can_connections +
CONFIG_CAN_PREALLOC_CONNS))
{
kmm_free(conn);
}
else
#endif
{
memset(conn, 0, sizeof(*conn));
dq_addlast(&conn->sconn.node, &g_free_can_connections);
}
NET_BUFPOOL_FREE(g_can_connections, conn);

nxmutex_unlock(&g_free_lock);
}
Expand Down
69 changes: 10 additions & 59 deletions net/devif/devif_callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <nuttx/net/netdev.h>

#include "netdev/netdev.h"
#include "utils/utils.h"
#include "devif/devif.h"

/****************************************************************************
Expand All @@ -52,11 +53,9 @@
* Private Data
****************************************************************************/

#if CONFIG_NET_PREALLOC_DEVIF_CALLBACKS > 0
static struct devif_callback_s
g_cbprealloc[CONFIG_NET_PREALLOC_DEVIF_CALLBACKS];
#endif
static FAR struct devif_callback_s *g_cbfreelist = NULL;
NET_BUFPOOL_DECLARE(g_cbprealloc, sizeof(struct devif_callback_s),
CONFIG_NET_PREALLOC_DEVIF_CALLBACKS,
CONFIG_NET_ALLOC_DEVIF_CALLBACKS, 0);

/****************************************************************************
* Private Functions
Expand Down Expand Up @@ -88,7 +87,7 @@ static void devif_callback_free(FAR struct net_driver_s *dev,
#ifdef CONFIG_DEBUG_FEATURES
/* Check for double freed callbacks */

curr = g_cbfreelist;
curr = (FAR struct devif_callback_s *)g_cbprealloc.freebuffers.head;

while (curr != NULL)
{
Expand Down Expand Up @@ -187,23 +186,9 @@ static void devif_callback_free(FAR struct net_driver_s *dev,
}
}

/* If this is a preallocated or a batch allocated callback store it in
* the free callbacks list. Else free it.
*/
/* Free the callback structure */

#if CONFIG_NET_ALLOC_DEVIF_CALLBACKS == 1
if (cb < g_cbprealloc || cb >= (g_cbprealloc +
CONFIG_NET_PREALLOC_DEVIF_CALLBACKS))
{
kmm_free(cb);
}
else
#endif
{
cb->nxtconn = g_cbfreelist;
cb->nxtdev = NULL;
g_cbfreelist = cb;
}
NET_BUFPOOL_FREE(g_cbprealloc, cb);

net_unlock();
}
Expand Down Expand Up @@ -266,15 +251,7 @@ static bool devif_event_trigger(uint16_t events, uint16_t triggers)

void devif_callback_init(void)
{
#if CONFIG_NET_PREALLOC_DEVIF_CALLBACKS > 0
int i;

for (i = 0; i < CONFIG_NET_PREALLOC_DEVIF_CALLBACKS; i++)
{
g_cbprealloc[i].nxtconn = g_cbfreelist;
g_cbfreelist = &g_cbprealloc[i];
}
#endif
NET_BUFPOOL_INIT(g_cbprealloc);
}

/****************************************************************************
Expand All @@ -299,9 +276,6 @@ FAR struct devif_callback_s *
FAR struct devif_callback_s **list_tail)
{
FAR struct devif_callback_s *ret;
#if CONFIG_NET_ALLOC_DEVIF_CALLBACKS > 0
int i;
#endif

net_lock();

Expand All @@ -324,34 +298,11 @@ FAR struct devif_callback_s *
return NULL;
}

/* Allocate the callback entry from heap */
/* Get a callback structure */

#if CONFIG_NET_ALLOC_DEVIF_CALLBACKS > 0
if (g_cbfreelist == NULL)
{
ret = kmm_zalloc(sizeof(struct devif_callback_s) *
CONFIG_NET_ALLOC_DEVIF_CALLBACKS);
if (ret != NULL)
{
for (i = 0; i < CONFIG_NET_ALLOC_DEVIF_CALLBACKS; i++)
{
ret[i].nxtconn = g_cbfreelist;
g_cbfreelist = &ret[i];
}
}
}
#endif

/* Check the head of the free list */

ret = g_cbfreelist;
ret = NET_BUFPOOL_TRYALLOC(g_cbprealloc);
if (ret)
{
/* Remove the next instance from the head of the free list */

g_cbfreelist = ret->nxtconn;
memset(ret, 0, sizeof(struct devif_callback_s));

/* Add the newly allocated instance to the head of the device event
* list.
*/
Expand Down
Loading

0 comments on commit cc2cfe3

Please sign in to comment.