Bluetooth: controller: Improve ticker_by_next_slot_get

Fixes ticker_by_next_slot_get for JIT scheduler by allowing iterating
through ticker nodes without ticks_slot information, and improves
performance for legacy ticker scheduling use.

To reduce the processing and context switching overhead, a new feature
is introduced via BT_TICKER_NEXT_SLOT_GET_MATCH, by which an operation
callback may be added via the ticker_next_slot_get_ext interface, and
the match function is then called when the ticker_job is processing the
request.
By returning true in this callback, iteration stops and normal operation
callback is invoked. If the match function returns false, node iteration
continues. This reduces the number of ticker_job executions for node
iteration.

Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
Morten Priess 2021-05-21 09:36:54 +02:00 committed by Carles Cufí
commit fa20fa95d0
5 changed files with 124 additions and 24 deletions

View file

@ -553,6 +553,15 @@ config BT_TICKER_LAZY_GET
ticker nodes, returning tick to expire and lazy count from a reference ticker nodes, returning tick to expire and lazy count from a reference
tick. tick.
config BT_TICKER_NEXT_SLOT_GET_MATCH
bool "Ticker Next Slot Get with match callback"
default y if BT_TICKER_SLOT_AGNOSTIC
help
This option enables ticker interface to iterate through active
ticker nodes with a callback for every found ticker node. When
returning true in the callback, iteration will stop and the normal
operation callback invoked.
config BT_TICKER_EXT config BT_TICKER_EXT
bool "Ticker extensions" bool "Ticker extensions"
depends on !BT_TICKER_LOW_LAT && !BT_TICKER_SLOT_AGNOSTIC depends on !BT_TICKER_LOW_LAT && !BT_TICKER_SLOT_AGNOSTIC

View file

@ -925,6 +925,7 @@ static void mfy_sync_offset_get(void *param)
TICKER_USER_ID_ULL_LOW, TICKER_USER_ID_ULL_LOW,
&id, &ticks_current, &id, &ticks_current,
&ticks_to_expire, &lazy, &ticks_to_expire, &lazy,
NULL, NULL,
ticker_op_cb, (void *)&ret_cb); ticker_op_cb, (void *)&ret_cb);
if (ret == TICKER_STATUS_BUSY) { if (ret == TICKER_STATUS_BUSY) {
while (ret_cb == TICKER_STATUS_BUSY) { while (ret_cb == TICKER_STATUS_BUSY) {

View file

@ -46,6 +46,20 @@ static void after_mstr_offset_get(uint16_t conn_interval, uint32_t ticks_slot,
uint32_t *win_offset_us); uint32_t *win_offset_us);
static void ticker_op_cb(uint32_t status, void *param); static void ticker_op_cb(uint32_t status, void *param);
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
bool ticker_match_op_cb(uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire, void *op_context)
{
ARG_UNUSED(ticks_slot);
ARG_UNUSED(ticks_to_expire);
ARG_UNUSED(op_context);
bool match = ticker_id >= TICKER_ID_CONN_BASE &&
ticker_id <= TICKER_ID_CONN_LAST;
return match;
}
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs, void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
uint32_t *ticks_anchor, uint32_t *us_offset) uint32_t *ticks_anchor, uint32_t *us_offset)
{ {
@ -67,10 +81,20 @@ void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
bool success; bool success;
ret_cb = TICKER_STATUS_BUSY; ret_cb = TICKER_STATUS_BUSY;
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR, user_id,
&ticker_id, ticks_anchor,
&ticks_to_expire,
NULL, /* lazy */
ticker_match_op_cb,
NULL, /* match_op_context */
ticker_op_cb, (void *)&ret_cb);
#else
ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id, ret = ticker_next_slot_get(TICKER_INSTANCE_ID_CTLR, user_id,
&ticker_id, ticks_anchor, &ticker_id, ticks_anchor,
&ticks_to_expire, ticker_op_cb, &ticks_to_expire,
(void *)&ret_cb); ticker_op_cb, (void *)&ret_cb);
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
if (ret == TICKER_STATUS_BUSY) { if (ret == TICKER_STATUS_BUSY) {
while (ret_cb == TICKER_STATUS_BUSY) { while (ret_cb == TICKER_STATUS_BUSY) {
ticker_job_sched(TICKER_INSTANCE_ID_CTLR, ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
@ -85,10 +109,12 @@ void ull_sched_after_mstr_slot_get(uint8_t user_id, uint32_t ticks_slot_abs,
break; break;
} }
#if !defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
if ((ticker_id < TICKER_ID_CONN_BASE) || if ((ticker_id < TICKER_ID_CONN_BASE) ||
(ticker_id > TICKER_ID_CONN_LAST)) { (ticker_id > TICKER_ID_CONN_LAST)) {
continue; continue;
} }
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE); conn = ll_conn_get(ticker_id - TICKER_ID_CONN_BASE);
if (conn && !conn->lll.role) { if (conn && !conn->lll.role) {

View file

@ -183,6 +183,10 @@ struct ticker_user_op_slot_get {
#if defined(CONFIG_BT_TICKER_LAZY_GET) #if defined(CONFIG_BT_TICKER_LAZY_GET)
uint16_t *lazy; uint16_t *lazy;
#endif /* CONFIG_BT_TICKER_LAZY_GET */ #endif /* CONFIG_BT_TICKER_LAZY_GET */
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
ticker_op_match_func fp_match_op_func;
void *match_op_context;
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
}; };
/* User operation data structure for priority_set opcode. Used for passing /* User operation data structure for priority_set opcode. Used for passing
@ -351,27 +355,40 @@ static uint8_t ticker_by_slot_get(struct ticker_node *node, uint8_t ticker_id_he
#endif /* CONFIG_BT_TICKER_LOW_LAT */ #endif /* CONFIG_BT_TICKER_LOW_LAT */
/** /**
* @brief Get next ticker with slot ticks * @brief Get next ticker with slot ticks or match
* *
* @details Gets the next ticker which has slot ticks specified and * @details Iterates ticker nodes from ticker_id_head. If no head id is provided
* return the ticker id and accumulated ticks until expiration. If no * (TICKER_NULL), iteration starts from the first node.
* ticker nodes have slot ticks, the next ticker node is returned. * Operation details:
* If no head id is provided (TICKER_NULL) the first node is returned. *
* NORMAL MODE (!CONFIG_BT_TICKER_SLOT_AGNOSTIC)
* - Gets the next ticker which has slot ticks specified and return the ticker
* id and accumulated ticks until expiration.
* - If a matching function is provided, this function is called and node iteration
* continues until match function returns true.
*
* SLOT AGNOSTIC MODE (CONFIG_BT_TICKER_SLOT_AGNOSTIC)
* - Gets the next ticker node.
* - If a matching function is provided, this function is called and node iteration
* continues until match function returns true.
* *
* @param instance Pointer to ticker instance * @param instance Pointer to ticker instance
* @param ticker_id_head Pointer to id of first ticker node [in/out] * @param ticker_id_head Pointer to id of first ticker node [in/out]
* @param ticks_current Pointer to current ticks count [in/out] * @param ticks_current Pointer to current ticks count [in/out]
* @param ticks_to_expire Pointer to ticks to expire [in/out] * @param ticks_to_expire Pointer to ticks to expire [in/out]
* * @param fp_match_op_func Pointer to match function or NULL if unused
* @param match_op_context Pointer to operation context passed to match
* function or NULL if unused
* @param lazy Pointer to lazy variable to receive lazy_current
* of found ticker node
* @internal * @internal
*/ */
static void ticker_by_next_slot_get(struct ticker_instance *instance, static void ticker_by_next_slot_get(struct ticker_instance *instance,
uint8_t *ticker_id_head, uint32_t *ticks_current, uint8_t *ticker_id_head, uint32_t *ticks_current,
#if defined(CONFIG_BT_TICKER_LAZY_GET) uint32_t *ticks_to_expire,
uint32_t *ticks_to_expire, uint16_t *lazy) ticker_op_match_func fp_match_op_func,
#else /* !CONFIG_BT_TICKER_LAZY_GET */ void *match_op_context,
uint32_t *ticks_to_expire) uint16_t *lazy)
#endif /* !CONFIG_BT_TICKER_LAZY_GET */
{ {
struct ticker_node *ticker; struct ticker_node *ticker;
struct ticker_node *node; struct ticker_node *node;
@ -394,18 +411,44 @@ static void ticker_by_next_slot_get(struct ticker_instance *instance,
_ticker_id_head = ticker->next; _ticker_id_head = ticker->next;
} }
/* Find first ticker node with match or slot ticks */
while (_ticker_id_head != TICKER_NULL) {
ticker = &node[_ticker_id_head];
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
if (fp_match_op_func) {
uint32_t ticks_slot = 0;
#if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC) #if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC)
/* Find first ticker node with slot ticks */ ticks_slot += ticker->ticks_slot;
while ((_ticker_id_head != TICKER_NULL) && #endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */
((ticker = &node[_ticker_id_head])->ticks_slot == 0U)) {
/* Match node id */
if (fp_match_op_func(_ticker_id_head, ticks_slot,
_ticks_to_expire +
ticker->ticks_to_expire,
match_op_context)) {
/* Match found */
break;
}
} else
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
#if !defined(CONFIG_BT_TICKER_SLOT_AGNOSTIC)
if (ticker->ticks_slot) {
/* Matching not used and node has slot ticks */
break;
#else
{
/* Matching not used and slot agnostic */
break;
#endif /* !CONFIG_BT_TICKER_SLOT_AGNOSTIC */
}
/* Accumulate expire ticks */ /* Accumulate expire ticks */
_ticks_to_expire += ticker->ticks_to_expire; _ticks_to_expire += ticker->ticks_to_expire;
_ticker_id_head = ticker->next; _ticker_id_head = ticker->next;
} }
#else
/* TODO: Come up with different way to find/match the ticker */
LL_ASSERT(0);
#endif
if (_ticker_id_head != TICKER_NULL) { if (_ticker_id_head != TICKER_NULL) {
/* Add ticks for found ticker */ /* Add ticks for found ticker */
_ticks_to_expire += ticker->ticks_to_expire; _ticks_to_expire += ticker->ticks_to_expire;
@ -2154,11 +2197,17 @@ static inline void ticker_job_op_inquire(struct ticker_instance *instance,
ticker_by_next_slot_get(instance, ticker_by_next_slot_get(instance,
uop->params.slot_get.ticker_id, uop->params.slot_get.ticker_id,
uop->params.slot_get.ticks_current, uop->params.slot_get.ticks_current,
#if defined(CONFIG_BT_TICKER_LAZY_GET)
uop->params.slot_get.ticks_to_expire, uop->params.slot_get.ticks_to_expire,
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
uop->params.slot_get.fp_match_op_func,
uop->params.slot_get.match_op_context,
#else
NULL, NULL,
#endif
#if defined(CONFIG_BT_TICKER_LAZY_GET)
uop->params.slot_get.lazy); uop->params.slot_get.lazy);
#else /* !CONFIG_BT_TICKER_LAZY_GET */ #else /* !CONFIG_BT_TICKER_LAZY_GET */
uop->params.slot_get.ticks_to_expire); NULL);
#endif /* !CONFIG_BT_TICKER_LAZY_GET */ #endif /* !CONFIG_BT_TICKER_LAZY_GET */
__fallthrough; __fallthrough;
case TICKER_USER_OP_TYPE_IDLE_GET: case TICKER_USER_OP_TYPE_IDLE_GET:
@ -2894,18 +2943,22 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
uint32_t *ticks_to_expire, uint32_t *ticks_to_expire,
ticker_op_func fp_op_func, void *op_context) ticker_op_func fp_op_func, void *op_context)
{ {
#if defined(CONFIG_BT_TICKER_LAZY_GET) #if defined(CONFIG_BT_TICKER_LAZY_GET) || \
defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
return ticker_next_slot_get_ext(instance_index, user_id, ticker_id, return ticker_next_slot_get_ext(instance_index, user_id, ticker_id,
ticks_current, ticks_to_expire, NULL, ticks_current, ticks_to_expire, NULL,
NULL, NULL,
fp_op_func, op_context); fp_op_func, op_context);
} }
uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id,
uint8_t *ticker_id, uint32_t *ticks_current, uint8_t *ticker_id, uint32_t *ticks_current,
uint32_t *ticks_to_expire, uint16_t *lazy, uint32_t *ticks_to_expire, uint16_t *lazy,
ticker_op_match_func fp_match_op_func,
void *match_op_context,
ticker_op_func fp_op_func, void *op_context) ticker_op_func fp_op_func, void *op_context)
{ {
#endif /* CONFIG_BT_TICKER_LAZY_GET */ #endif /* CONFIG_BT_TICKER_LAZY_GET || CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
struct ticker_instance *instance = &_instance[instance_index]; struct ticker_instance *instance = &_instance[instance_index];
struct ticker_user_op *user_op; struct ticker_user_op *user_op;
struct ticker_user *user; struct ticker_user *user;
@ -2931,6 +2984,10 @@ uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id,
#if defined(CONFIG_BT_TICKER_LAZY_GET) #if defined(CONFIG_BT_TICKER_LAZY_GET)
user_op->params.slot_get.lazy = lazy; user_op->params.slot_get.lazy = lazy;
#endif /* CONFIG_BT_TICKER_LAZY_GET */ #endif /* CONFIG_BT_TICKER_LAZY_GET */
#if defined(CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH)
user_op->params.slot_get.fp_match_op_func = fp_match_op_func;
user_op->params.slot_get.match_op_context = match_op_context;
#endif /* CONFIG_BT_TICKER_NEXT_SLOT_GET_MATCH */
user_op->status = TICKER_STATUS_BUSY; user_op->status = TICKER_STATUS_BUSY;
user_op->fp_op_func = fp_op_func; user_op->fp_op_func = fp_op_func;
user_op->op_context = op_context; user_op->op_context = op_context;

View file

@ -103,6 +103,11 @@ typedef void (*ticker_timeout_func) (uint32_t ticks_at_expire, uint32_t remainde
*/ */
typedef void (*ticker_op_func) (uint32_t status, void *op_context); typedef void (*ticker_op_func) (uint32_t status, void *op_context);
/** \brief Timer operation match callback function type.
*/
typedef bool (*ticker_op_match_func) (uint8_t ticker_id, uint32_t ticks_slot,
uint32_t ticks_to_expire, void *op_context);
#if defined(CONFIG_BT_TICKER_EXT) #if defined(CONFIG_BT_TICKER_EXT)
struct ticker_ext { struct ticker_ext {
uint32_t ticks_slot_window;/* Window in which the slot uint32_t ticks_slot_window;/* Window in which the slot
@ -158,6 +163,8 @@ uint32_t ticker_next_slot_get(uint8_t instance_index, uint8_t user_id,
uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id, uint32_t ticker_next_slot_get_ext(uint8_t instance_index, uint8_t user_id,
uint8_t *ticker_id, uint32_t *ticks_current, uint8_t *ticker_id, uint32_t *ticks_current,
uint32_t *ticks_to_expire, uint16_t *lazy, uint32_t *ticks_to_expire, uint16_t *lazy,
ticker_op_match_func fp_op_match_func,
void *match_op_context,
ticker_op_func fp_op_func, void *op_context); ticker_op_func fp_op_func, void *op_context);
uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id, uint32_t ticker_job_idle_get(uint8_t instance_index, uint8_t user_id,
ticker_op_func fp_op_func, void *op_context); ticker_op_func fp_op_func, void *op_context);