| # 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 |