kernel/Kconfig: Reorgnize wait_q and sched algorithm choices

Make these "choice" items instead of a single boolean that implies the
element unset.

Also renames WAITQ_FAST to WAITQ_SCALABLE, as the rbtree is really
only "fast" for large queue sizes (it's constant factor overhead is
bigger than a list's!)

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2018-06-27 11:20:50 -07:00 committed by Anas Nashif
commit 225c74bbdf
5 changed files with 67 additions and 28 deletions

View file

@ -22,5 +22,5 @@ CONFIG_USERSPACE=y
CONFIG_APPLICATION_MEMORY=y
CONFIG_X86_PAE_MODE=y
CONFIG_DEBUG_INFO=y
CONFIG_SCHED_DUMB=n
CONFIG_WAITQ_FAST=y
CONFIG_SCHED_SCALABLE=y
CONFIG_WAITQ_SCALABLE=y

View file

@ -73,7 +73,7 @@ extern "C" {
#define K_HIGHEST_APPLICATION_THREAD_PRIO (K_HIGHEST_THREAD_PRIO)
#define K_LOWEST_APPLICATION_THREAD_PRIO (K_LOWEST_THREAD_PRIO - 1)
#ifdef CONFIG_WAITQ_FAST
#ifdef CONFIG_WAITQ_SCALABLE
typedef struct {
struct _priq_rb waitq;
@ -406,7 +406,7 @@ struct _thread_base {
struct rbnode qnode_rb;
};
#ifdef CONFIG_WAITQ_FAST
#ifdef CONFIG_WAITQ_SCALABLE
/* wait queue on which the thread is pended (needed only for
* trees, not dumb lists)
*/

View file

@ -195,23 +195,17 @@ config APPLICATION_MEMORY
will have the project-level application objects and any libraries
including the C library in it.
config WAITQ_FAST
bool
prompt "Use scalable wait_q implementation"
choice SCHED_ALGORITHM
prompt "Scheduler priority queue algorithm"
default SCHED_DUMB
help
When selected, the wait_q abstraction used in IPC primitives
to pend threads for wakeup later will be implemented with a
balanced tree instead of a linear list. Choose this if you
expect to have many threads waiting on individual
primitives, or if you have already included the red/black
tree code in the build for some other purpose (in which case
this results in less code size increase than the default
implementation).
The kernel can be built with with several choices for the
ready queue implementation, offering different choices between
code size, constant factor runtime overhead and performance
scaling when many threads are added.
config SCHED_DUMB
bool
prompt "Use a simple linked list scheduler"
default y
bool "Simple linked-list ready queue"
help
When selected, the scheduler ready queue will be implemented
as a simple unordered list, with very fast constant time
@ -222,6 +216,51 @@ config SCHED_DUMB
(that are not otherwise using the red/black tree) this
results in a savings of ~2k of code size.
config SCHED_SCALABLE
bool "Red/black tree ready queue"
help
When selected, the scheduler ready queue will be implemented
as a red/black tree. This has rather slower constant-time
insertion and removal overhead, and on most platforms (that
are not otherwise using the rbtree somehwere) requires an
extra ~2kb of code. But the resulting behavior will scale
cleanly and quickly into the many thousands of threads. Use
this on platforms where you may have MANY threads marked as
runnable at a given time. Most applications don't want this.
endchoice # SCHED_ALGORITHM
choice WAITQ_ALGORITHM
prompt "Wait queue priority algorithm"
default WAITQ_DUMB
help
The wait_q abstraction used in IPC primitives to pend threads
for later wakeup shares the same backend data structure
choices as the scheduler, and can use the same options.
config WAITQ_SCALABLE
bool
prompt "Use scalable wait_q implementation"
help
When selected, the wait_q will be implemented with a
balanced tree. Choose this if you expect to have many
threads waiting on individual primitives. There is a ~2kb
code size increase over WAITQ_DUMB (which may be shared with
SCHED_SCALABLE) if the rbtree is not used elsewhere in the
application, and pend/unpend operations on "small" queues
will be somewhat slower (though this is not generally a
performance path).
config WAITQ_DUMB
bool
prompt "Simple linked-list wait_q"
help
When selected, the wait_q will be implemented with a
doubly-linked list. Choose this if you expect to have only
a few threads blocked on any single IPC primitive.
endchoice # WAITQ_ALGORITHM
menu "Kernel Debugging and Metrics"
config INIT_STACKS

View file

@ -44,7 +44,7 @@ static ALWAYS_INLINE int _abort_thread_timeout(struct k_thread *thread)
#define _get_next_timeout_expiry() (K_FOREVER)
#endif
#ifdef CONFIG_WAITQ_FAST
#ifdef CONFIG_WAITQ_SCALABLE
#define _WAIT_Q_FOR_EACH(wq, thread_ptr) \
RB_FOR_EACH_CONTAINER(&(wq)->waitq.tree, thread_ptr, base.qnode_rb)
@ -63,7 +63,7 @@ static inline struct k_thread *_waitq_head(_wait_q_t *w)
return (void *)rb_get_min(&w->waitq.tree);
}
#else /* !CONFIG_WAITQ_FAST: */
#else /* !CONFIG_WAITQ_SCALABLE: */
#define _WAIT_Q_FOR_EACH(wq, thread_ptr) \
SYS_DLIST_FOR_EACH_CONTAINER(&((wq)->waitq), thread_ptr, \
@ -79,7 +79,7 @@ static inline struct k_thread *_waitq_head(_wait_q_t *w)
return (void *)sys_dlist_peek_head(&w->waitq);
}
#endif /* !CONFIG_WAITQ_FAST */
#endif /* !CONFIG_WAITQ_SCALABLE */
#ifdef __cplusplus
}

View file

@ -12,21 +12,21 @@
#include <kernel_arch_func.h>
#include <syscall_handler.h>
#ifdef CONFIG_SCHED_DUMB
#if defined(CONFIG_SCHED_DUMB)
#define _priq_run_add _priq_dumb_add
#define _priq_run_remove _priq_dumb_remove
#define _priq_run_best _priq_dumb_best
#else
#elif defined(CONFIG_SCHED_SCALABLE)
#define _priq_run_add _priq_rb_add
#define _priq_run_remove _priq_rb_remove
#define _priq_run_best _priq_rb_best
#endif
#ifdef CONFIG_WAITQ_FAST
#if defined(CONFIG_WAITQ_SCALABLE)
#define _priq_wait_add _priq_rb_add
#define _priq_wait_remove _priq_rb_remove
#define _priq_wait_best _priq_rb_best
#else
#elif defined(CONFIG_WAITQ_DUMB)
#define _priq_wait_add _priq_dumb_add
#define _priq_wait_remove _priq_dumb_remove
#define _priq_wait_best _priq_dumb_best
@ -275,7 +275,7 @@ static void pend(struct k_thread *thread, _wait_q_t *wait_q, s32_t timeout)
}
if (wait_q) {
#ifdef CONFIG_WAITQ_FAST
#ifdef CONFIG_WAITQ_SCALABLE
thread->base.pended_on = wait_q;
#endif
_priq_wait_add(&wait_q->waitq, thread);
@ -294,7 +294,7 @@ void _pend_thread(struct k_thread *thread, _wait_q_t *wait_q, s32_t timeout)
static _wait_q_t *pended_on(struct k_thread *thread)
{
#ifdef CONFIG_WAITQ_FAST
#ifdef CONFIG_WAITQ_SCALABLE
__ASSERT_NO_MSG(thread->base.pended_on);
return thread->base.pended_on;
@ -325,7 +325,7 @@ void _unpend_thread_no_timeout(struct k_thread *thread)
_mark_thread_as_not_pending(thread);
}
#if defined(CONFIG_ASSERT) && defined(CONFIG_WAITQ_FAST)
#if defined(CONFIG_ASSERT) && defined(CONFIG_WAITQ_SCALABLE)
thread->base.pended_on = NULL;
#endif
}