zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.83k stars 6.6k forks source link

Kconfig dependency inversion #67117

Open ankuns opened 10 months ago

ankuns commented 10 months ago

Is your feature request related to a problem? Please describe.

Some Kconfig options often come with set of default values depending on other options. Providing proper default configuration requires knowledge of all possible users of the Kconfig option. This becomes cumbersome with even growing number of modules using Kconfig options. Some of the modules are outside of Zephyr (customer applications/downstream forks) which makes it impossible to know all users of the Kconfig options.

Consider following use cases:

  1. A resource provides kind of "channels". The number of channels is configurable. We want to have as small number of "channels" as possible (memory footprint/runtime overhead) but satisfying all users.
config RESOURCE_CHANNELS_COUNT
    int "Number of channels provided by the resource"
    default 3 if KNOWN_OPTION_1 && KNOWN_OPTION_2
    default 2 if KNOWN_OPTION_1
    default 1 if KNOWN_OPTION_2
    default 0

Users expect that there will be enough "channels" of the resource they can use, independent of other users. During the build it is ensured that given capacity is provided, like in following simple example:

static resource_channel_t channels[CONFIG_RESOURCE_CHANNELS_COUNT];
  1. A resource is kind of memory which is required to be at least given value, like stack sizes.
    config SOME_THERAD_STACK_SIZE
    int "Stack size for some thread performing some important processing"
    default 8192 if KNOWN_OPTION_1
    default 4096 if KNOWN_OPTION_2
    default 1024

Describe the solution you'd like I would like the Kconfig language to be extended to allow dependency inversion so that users unaware of each other can "request" or "alloc" given Kconfig option an the Kconfig option itself serving some purpose does not need to know all it's users to provide reasonable default value. The build process would calculate final value of the Kconfig option. If calculated value is outside specified range the build fails. Following some hypothetical example:

"Resource" and "some_thread" are not aware of modules 1 and 2 being possibly part of external repositories.

config RESOURCE_CHANNELS_COUNT
    int "Number of channels provided by the resource"
    default 0

config SOME_THERAD_STACK_SIZE
    int "Stack size for some thread performing some important processing"
    default 1024

Module 1 is unaware of module 2, but it's KNOWN_OPTION_1 requires that "resource" reserves 2 channels and "some_thread" stack size is at least 8192 (can be greater).

config KNOWN_OPTION_1
    bool "Some feature 1"
    select RESOURCE_CHANNELS_COUNT alloc 2
    select SOME_THERAD_STACK_SIZE at_least 8192

Module 2 is unaware of module 1, but it's KNOWN_OPTION_2 requires that "resource" reserves 1 channel and "some_thread" stack size is at least 4096 (can be greater).

config KNOWN_OPTION_2
    bool "Some feature 2"
    select RESOURCE_CHANNELS_COUNT alloc 1
    select SOME_THERAD_STACK_SIZE at_least 4096

Build system would gather all requirements on value of (in example above) RESOURCE_CHANNELS_COUNT and SOME_THERAD_STACK_SIZE and would calculate final value of these options satisfying all needs. Given serving Kconfig like RESOURCE_CHANNELS_COUNT and SOME_THERAD_STACK_SIZE would not need to know all users but the system would provide correct default value for these Kconfig.

The syntax (select alloc at_least keywords ) is to be discussed as long as the goal ca be achieved.

Describe alternatives you've considered

Additional context

nordicjm commented 10 months ago

This has been done already with heap memory sizes without needing to extend Kconfig, see https://github.com/zephyrproject-rtos/zephyr/pull/65908

ankuns commented 10 months ago

Thanks for pointing https://github.com/zephyrproject-rtos/zephyr/pull/65908, IMHO it is a step in good direction. It seems there is really no need to change the Kconfig syntax itself. However I think that Zephyr being the base framework for many projects should provide some good convention about naming, possibly provide cmake functions to easily reuse the pattern and provide appropriate documentation about the selected convention.

Consider https://github.com/zephyrproject-rtos/zephyr/blob/89982b711bbda3cdeb2da6a7250ccab4f088ba10/subsys/ipc/ipc_service/backends/Kconfig.rpmsg#L24 Here the "_ADD_SIZE_xxxx" pattern would apply. There are many modules that require endpoints. The modules should not know about each other and definietely the IPC backend should not depend on it's users.

https://github.com/zephyrproject-rtos/zephyr/blob/89982b711bbda3cdeb2da6a7250ccab4f088ba10/subsys/ipc/ipc_service/backends/Kconfig.rpmsg#L6 For this some kind of "_MIN_SIZE_xxx" pattern would apply. Some modules could require bigger stack_size, however individual requirements do not sum. Just the maximum value of each individual minimum requirements matter.

https://github.com/zephyrproject-rtos/zephyr/blob/89982b711bbda3cdeb2da6a7250ccab4f088ba10/drivers/timer/Kconfig.nrf_rtc#L20 Here the "_ADD_SIZE_xxx" pattern would apply, but we have suffix "_CHAN_COUNT" instead of "_SIZE" so there is a need to have clear convention about how to express individual additive components. The "_ADD_SIZE" in the Kconfig name in PR https://github.com/zephyrproject-rtos/zephyr/pull/65908 starts to play kind of a "keyword" in identifier name. That's why it it important.

Some other stack size-related (there are plenty of ..._STACK_SIZE Kconfigs) https://github.com/zephyrproject-rtos/zephyr/blob/89982b711bbda3cdeb2da6a7250ccab4f088ba10/kernel/Kconfig#L156 https://github.com/zephyrproject-rtos/zephyr/blob/89982b711bbda3cdeb2da6a7250ccab4f088ba10/kernel/Kconfig#L168 The "_MIN_SIZE_xxx" pattern could apply.