blob: 4d86f60f14a23c1341f96cbc1a86b5eac44069fe [file] [edit]
# Copyright (c) 2024 Intel Corp.
# SPDX-License-Identifier: Apache-2.0
#
menu "SMP Options"
config SMP
bool "Symmetric multiprocessing support"
depends on USE_SWITCH
help
When true, kernel will be built with SMP support, allowing
more than one CPU to schedule Zephyr tasks at a time.
config MP_MAX_NUM_CPUS
int "Maximum number of CPUs/cores"
default 1
range 1 32
help
Maximum number of multiprocessing-capable cores available to the
multicpu API and SMP features.
if SMP
config SCHED_IPI_SUPPORTED
bool
select EVENTS
help
True if the architecture supports a call to arch_sched_broadcast_ipi()
to broadcast an interrupt that will call z_sched_ipi() on other CPUs
in the system. Required for k_thread_abort() to operate with
reasonable latency (otherwise we might have to wait for the other
thread to take an interrupt, which can be arbitrarily far in the
future).
config SCHED_IPI_CASCADE
bool "Use cascading IPIs to correct localized scheduling"
depends on SCHED_CPU_MASK && !SCHED_CPU_MASK_PIN_ONLY
default n
help
Threads that are preempted by a local thread (a thread that is
restricted by its CPU mask to execute on a subset of all CPUs) may
trigger additional IPIs when the preempted thread is of higher
priority than a currently executing thread on another CPU. Although
these cascading IPIs will ensure that the system will settle upon a
valid set of high priority threads, it comes at a performance cost.
config SCHED_CPU_MASK
bool "CPU mask affinity/pinning API"
help
When true, the application will have access to the
k_thread_cpu_mask_*() APIs which control per-CPU affinity masks in
SMP mode, allowing applications to pin threads to specific CPUs or
disallow threads from running on given CPUs.
The API is supported with all three scheduler backends. The
performance characteristics of the mask-aware "best thread" search
differ per backend:
SCHED_SIMPLE (default): The run queue is a sorted linked list.
Finding the best runnable thread for the current CPU requires a
linear scan of the list until a thread whose cpu_mask includes the
current CPU is found. This is O(N) in the number of runnable
threads. Because the list is priority-ordered the scan terminates
as soon as the first eligible thread is found, so in practice the
cost is proportional to the number of higher-priority threads that
are pinned away from the current CPU.
SCHED_SCALABLE: The run queue is a red/black tree ordered by
priority. The mask-aware search performs an in-order tree walk
and returns the first thread whose cpu_mask matches. The walk is
O(N) in the worst case but terminates early once a matching thread
is found. Because the tree is already sorted by priority the walk
typically visits only a small number of nodes. The additional
~2 kB of code required by the rbtree is shared with WAITQ_SCALABLE
when both are enabled.
SCHED_MULTIQ: The run queue is an array of per-priority doubly
linked lists together with a bitmap of non-empty levels. The
mask-aware search iterates over non-empty priority levels from
highest to lowest using the bitmap (O(P) where P is the number of
distinct priorities in use) and within each level scans the thread
list for the first thread whose cpu_mask includes the current CPU.
In the common case where affinity-constrained threads are sparse,
the search is fast; in the pathological case where many threads at
the same high priority are all pinned away from the current CPU
the inner list scan becomes O(N). Note that SCHED_MULTIQ is
incompatible with SCHED_DEADLINE.
In all three cases the cpu_mask check adds overhead that is absent
without this option, so it should only be enabled when CPU affinity
is actually needed.
config SCHED_CPU_MASK_PIN_ONLY
bool "CPU mask variant with single-CPU pinning only"
depends on SCHED_CPU_MASK
help
When true, enables a variant of SCHED_CPU_MASK where only
one CPU may be specified for every thread. Effectively, all
threads have a single "assigned" CPU and they will never be
scheduled symmetrically. In general this is not helpful,
but some applications have a carefully designed threading
architecture and want to make their own decisions about how
to assign work to CPUs. In that circumstance, some moderate
optimizations can be made (e.g. having a separate run queue
per CPU, keeping the list length shorter). When selected,
the CPU mask becomes an immutable thread attribute. It can
only be modified before a thread is started. Most
applications don't want this.
config TRACE_SCHED_IPI
bool "Test IPI"
help
When true, it will add a hook into z_sched_ipi(), in order
to check if schedule IPI has called or not, for testing
purpose.
depends on SCHED_IPI_SUPPORTED
depends on MP_MAX_NUM_CPUS>1
config IPI_OPTIMIZE
bool "Optimize IPI delivery"
default n
depends on SCHED_IPI_SUPPORTED && MP_MAX_NUM_CPUS>1
help
When selected, the kernel will attempt to determine the minimum
set of CPUs that need an IPI to trigger a reschedule in response to
a thread newly made ready for execution. This increases the
computation required at every scheduler operation by a value that is
O(N) in the number of CPUs, and in exchange reduces the number of
interrupts delivered. Which to choose is going to depend on
application behavior. If the architecture also supports directing
IPIs to specific CPUs then this has the potential to significantly
reduce the number of IPIs (and consequently ISRs) processed by the
system as the number of CPUs increases. If not, the only benefit
would be to not issue any IPIs if the newly readied thread is of
lower priority than all the threads currently executing on other CPUs.
config KERNEL_COHERENCE
bool "Place all shared data into coherent memory"
depends on CACHE_CAN_SAY_MEM_COHERENCE
default y if SMP && MP_MAX_NUM_CPUS > 1
select THREAD_STACK_INFO
help
When available and selected, the kernel will build in a mode
where all shared data is placed in multiprocessor-coherent
(generally "uncached") memory. Thread stacks will remain
cached, as will application memory declared with
__incoherent. This is intended for Zephyr SMP kernels
running on cache-incoherent architectures only. Note that
when this is selected, there is an implicit API change that
assumes cache coherence to any memory passed to the kernel.
Code that creates kernel data structures in uncached regions
may fail strangely. Some assertions exist to catch these
mistakes, but not all circumstances can be tested.
config TICKET_SPINLOCKS
bool "Ticket spinlocks for lock acquisition fairness [EXPERIMENTAL]"
select EXPERIMENTAL
help
Basic spinlock implementation is based on single
atomic variable and doesn't guarantee locking fairness
across multiple CPUs. It's even possible that single CPU
will win the contention every time which will result
in a live-lock.
Ticket spinlocks provide a FIFO order of lock acquisition
which resolves such unfairness issue at the cost of slightly
increased memory footprint.
endif
endmenu