ASoC: Intel: avs: Mark avs_path_module_type_create() as noinline
Subsystems (3)
PATCH 1/1 ASoC: Intel: avs: Mark avs_path_module_type_create() as noinline
When building ARCH=arm64 allmodconfig with clang, there is a warning about high stack usage in avs_path_create(), which breaks the build due to CONFIG_WERROR=y:
sound/soc/intel/avs/path.c:815:18: error: stack frame size (2176) exceeds limit (2048) in 'avs_path_create' [-Werror,-Wframe-larger-than] struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
^
1 error generated.
This warning is also visible with allmodconfig on other architectures. The minimum set of configs that triggers this on top of ARCH=arm64 allnoconfig:
CONFIG_COMPILE_TEST=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_KASAN=y
CONFIG_PCI=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_INTEL_AVS=y
When CONFIG_FORTIFY_SOURCE is enabled, memcmp() (called from guid_equal()) becomes a wrapper to do compile time checking, which interacts poorly with inlining plus CONFIG_KASAN=y.
With ARCH=arm64 allmodconfig + CONFIG_KASAN=n + CONFIG_FRAME_WARN=128, the stack usage is much better:
sound/soc/intel/avs/path.c:815:18: warning: stack frame size (624) exceeds limit (128) in 'avs_path_create' [-Wframe-larger-than] struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
^
sound/soc/intel/avs/path.c:873:5: warning: stack frame size (144) exceeds limit (128) in 'avs_path_bind' [-Wframe-larger-than]
int avs_path_bind(struct avs_path *path)
^2 warnings generated.
To avoid this warning, mark avs_path_module_type_create() as noinline_for_stack, which redistributes the stack usage across multiple functions, regardless of CONFIG_KASAN.
With ARCH=arm64 allmodconfig + CONFIG_FRAME_WARN=128, the warnings show:
avs_path_create(): 192
avs_path_bind(): 272
avs_path_module_type_create(): 416
avs_mux_create(): 160 avs_updown_mix_create(): 160 avs_aec_create(): 176 avs_asrc_create(): 144
With ARCH=arm64 allmodconfig + CONFIG_FRAME_WARN=128 + CONFIG_KASAN=n, the warnings show:
avs_path_create(): 192
avs_path_bind(): 144
avs_path_module_type_create(): 416
avs_mux_create(): 176 avs_updown_mix_create(): 176 avs_src_create(): 144 avs_aec_create(): 192 avs_asrc_create(): 144 avs_wov_create(): 144
--- sound/soc/intel/avs/path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
sound/soc/intel/avs/path.c +2 -1
@@ -449,7 +449,8 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)return ret; } -static int avs_path_module_type_create (struct avs_dev *adev,struct avs_path_module *mod) +static noinline_for_stack int avs_path_module_type_create(struct avs_dev *adev, +struct avs_path_module *mod) {const guid_t *type = &mod->template->cfg_ext->type;
base-commit: ff6992735ade75aae3e35d16b17da1008d753d28
Signature · 1 line
2.37.1
Quoted 85 lines · Nathan Chancellor
When building ARCH=arm64 allmodconfig with clang, there is a warning about high stack usage in
avs_path_create(), which breaks the build due toCONFIG_WERROR=y:
sound/soc/intel/avs/path.c:815:18: error: stack frame size (2176) exceeds limit (2048) in 'avs_path_create' [-Werror,-Wframe-larger-than] structavs_path*avs_path_create(structavs_dev*adev, u32dma_id,^1 error generated.
This warning is also visible with allmodconfig on other architectures. The minimum set of configs that triggers this on top of ARCH=arm64 allnoconfig:
CONFIG_COMPILE_TEST=y
CONFIG_FORTIFY_SOURCE=y
CONFIG_KASAN=y
CONFIG_PCI=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_INTEL_AVS=yWhen
CONFIG_FORTIFY_SOURCEis enabled,memcmp()(called fromguid_equal()) becomes a wrapper to do compile time checking, which interacts poorly with inlining plusCONFIG_KASAN=y.With ARCH=arm64 allmodconfig +
CONFIG_KASAN=n+CONFIG_FRAME_WARN=128, the stack usage is much better:sound/soc/intel/avs/path.c:815:18: warning: stack frame size (624) exceeds limit (128) in 'avs_path_create' [-Wframe-larger-than] struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id, ^ sound/soc/intel/avs/path.c:873:5: warning: stack frame size (144) exceeds limit (128) in 'avs_path_bind' [-Wframe-larger-than] int avs_path_bind(struct avs_path *path) ^ 2 warnings generated.To avoid this warning, mark
avs_path_module_type_create()asnoinline_for_stack, which redistributes the stack usage across multiple functions, regardless ofCONFIG_KASAN.With ARCH=arm64 allmodconfig +
CONFIG_FRAME_WARN=128, the warnings show:avs_path_create(): 192 avs_path_bind(): 272 avs_path_module_type_create(): 416 avs_mux_create(): 160 avs_updown_mix_create(): 160 avs_aec_create(): 176 avs_asrc_create(): 144With ARCH=arm64 allmodconfig +
CONFIG_FRAME_WARN=128+CONFIG_KASAN=n, the warnings show:avs_path_create(): 192 avs_path_bind(): 144 avs_path_module_type_create(): 416 avs_mux_create(): 176 avs_updown_mix_create(): 176 avs_src_create(): 144 avs_aec_create(): 192 avs_asrc_create(): 144 avs_wov_create(): 144Signed-off-by Nathan Chancellor <[email protected]>--- sound/soc/intel/avs/path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)sound/soc/intel/avs/path.c +2
-1@@ -449,7 +449,8 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)return ret; } -static int avs_path_module_type_create (struct avs_dev *adev,struct avs_path_module *mod) +static noinline_for_stack int avs_path_module_type_create(struct avs_dev *adev, +struct avs_path_module *mod) {const guid_t *type = &mod->template->cfg_ext->type;
Quoted 1 line
base-commit:
ff6992735ade75aae3e35d16b17da1008d753d28
Not a fan of this.
My first question would be what clang does differently in this configuration (ARM) than in all other configurations (x86, etc.) and gcc.
Overall as evidenced by:
Quoted 1 line
CONFIG_COMPILE_TEST=y
this is test only and this commit doesn't fix anything for x86 this driver targets.
Based on description in message and in github link:
Looking at avs_path_module_type_create() it uses guid_equal() which is marked as inline, but is just a wrapper around memcmp(), which in case of fortify is still marked as inline... memcmp itself has 2 size_t variables for performing fortify check... no matter how I calculate, it shouldn't go above stack size, unless clang decides to also inline all calls to static avs_xxx_create functions. They are not marked as inline or noinline, so in theory compiler is free to do whatever it wants, but apparently it goes wrong way? Of course the above may be wrong, because I just analyzed code, not real output of clang.
Anyway it is probably ok, to do this, as while it needs to be fast module creation is not really time critical, and some time will be spend to communicate with DSP instead of calculating things, but still wonder if there isn't something that can be done on compiler side...
Mark Brown
maintainerQuoted 6 lines · Amadeusz Sławiński
Quoted 1 line · Nathan Chancellor
This warning is also visible with allmodconfig on other architectures.
My first question would be what clang does differently in this configuration (ARM) than in all other configurations (x86, etc.) and gcc.
See above from Nathan's commit message...
Quoted 9 lines · Mark Brown
Quoted 6 lines · Amadeusz Sławiński
Quoted 1 line · Nathan Chancellor
This warning is also visible with allmodconfig on other architectures.
My first question would be what clang does differently in this configuration (ARM) than in all other configurations (x86, etc.) and gcc.
See above from Nathan's commit message...
Ah, missed that. Anyway, what about if we replace multiple calls to guid_equal with lookup table and one call in loop?
Do let me know if something like the following works and I will send it as a proper patch:
sound/soc/intel/avs/path.c +26 -0
@@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)return ret; } +static int avs_probe_create (struct avs_dev *adev,struct avs_path_module *mod) +{ +dev_err (adev->dev,"Probe module can't be instantiated by topology" ); +return -EINVAL ; +} + +struct avs_module_create { +guid_t *guid; +int (*create)(struct avs_dev *adev,struct avs_path_module *mod); +}; + +static struct avs_module_create avs_module_create[] = { + { &AVS_MIXIN_MOD_UUID , avs_modbase_create }, + { &AVS_MIXOUT_MOD_UUID , avs_modbase_create }, + { &AVS_KPBUFF_MOD_UUID , avs_modbase_create }, + { &AVS_COPIER_MOD_UUID , avs_copier_create }, + { &AVS_MICSEL_MOD_UUID , avs_micsel_create }, + { &AVS_MUX_MOD_UUID , avs_mux_create }, + { &AVS_UPDWMIX_MOD_UUID , avs_updown_mix_create }, + { &AVS_SRCINTC_MOD_UUID , avs_src_create }, + { &AVS_AEC_MOD_UUID , avs_aec_create }, + { &AVS_ASRC_MOD_UUID , avs_asrc_create }, + { &AVS_INTELWOV_MOD_UUID , avs_wov_create }, + { &AVS_PROBE_MOD_UUID , avs_probe_create }, +}; + static int avs_path_module_type_create(struct avs_dev *adev, struct
avs_path_module *mod)
{
const guid_t *type = &mod->template->cfg_ext->type;- if (guid_equal(type, &AVS_MIXIN_MOD_UUID) ||
- guid_equal(type, &AVS_MIXOUT_MOD_UUID) ||
- guid_equal(type, &AVS_KPBUFF_MOD_UUID))
- return avs_modbase_create(adev, mod);
- if (guid_equal(type, &AVS_COPIER_MOD_UUID))
- return avs_copier_create(adev, mod);
- if (guid_equal(type, &AVS_MICSEL_MOD_UUID))
- return avs_micsel_create(adev, mod);
- if (guid_equal(type, &AVS_MUX_MOD_UUID))
- return avs_mux_create(adev, mod);
- if (guid_equal(type, &AVS_UPDWMIX_MOD_UUID))
- return avs_updown_mix_create(adev, mod);
- if (guid_equal(type, &AVS_SRCINTC_MOD_UUID))
- return avs_src_create(adev, mod);
- if (guid_equal(type, &AVS_AEC_MOD_UUID))
- return avs_aec_create(adev, mod);
- if (guid_equal(type, &AVS_ASRC_MOD_UUID))
- return avs_asrc_create(adev, mod);
- if (guid_equal(type, &AVS_INTELWOV_MOD_UUID))
- return avs_wov_create(adev, mod);
-
- if (guid_equal(type, &AVS_PROBE_MOD_UUID)) {
- dev_err(adev->dev, "Probe module can't be instantiated by topology");
- return -EINVAL;
- }
+ for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++)
+ if (guid_equal(type, avs_module_create[i].guid))
+ return avs_module_create[i].create(adev, mod);
return avs_modext_create(adev, mod);
}
Nathan Chancellor
Tested-byQuoted 9 lines · Amadeusz Sławiński
Quoted 8 lines · Mark Brown
Quoted 6 lines · Amadeusz Sławiński
Quoted 1 line · Nathan Chancellor
This warning is also visible with allmodconfig on other architectures.
My first question would be what clang does differently in this configuration (ARM) than in all other configurations (x86, etc.) and gcc.
Quoted 7 lines
Quoted 1 line
See above from Nathan's commit message...
Ah, missed that. Anyway, what about if we replace multiple calls to
guid_equalwith lookup table and one call in loop?Do let me know if something like the following works and I will send it as a proper patch:
Yes, that works! With ARCH=arm64 allmodconfig + CONFIG_FRAME_WARN=128, there is no single large function, they are all far below the default 2048 limit.
sound/soc/intel/avs/path.c:819:18: warning: stack frame size (256) exceeds limit (128) in 'avs_path_create' [-Wframe-larger-than] struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,
^
sound/soc/intel/avs/path.c:877:5: warning: stack frame size (272) exceeds limit (128) in 'avs_path_bind' [-Wframe-larger-than]
int avs_path_bind(struct avs_path *path)
^
sound/soc/intel/avs/path.c:143:12: warning: stack frame size (144) exceeds limit (128) in 'avs_copier_create' [-Wframe-larger-than]
static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)
^
sound/soc/intel/avs/path.c:379:12: warning: stack frame size (144) exceeds limit (128) in 'avs_micsel_create' [-Wframe-larger-than]
static int avs_micsel_create(struct avs_dev *adev, struct avs_path_module *mod)
^
sound/soc/intel/avs/path.c:344:12: warning: stack frame size (160) exceeds limit (128) in 'avs_mux_create' [-Wframe-larger-than]
static int avs_mux_create(struct avs_dev *adev, struct avs_path_module *mod)
^
sound/soc/intel/avs/path.c:267:12: warning: stack frame size (160) exceeds limit (128) in 'avs_updown_mix_create' [-Wframe-larger-than]
static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod)
^
sound/soc/intel/avs/path.c:325:12: warning: stack frame size (176) exceeds limit (128) in 'avs_aec_create' [-Wframe-larger-than]
static int avs_aec_create(struct avs_dev *adev, struct avs_path_module *mod)
^
sound/soc/intel/avs/path.c:306:12: warning: stack frame size (144) exceeds limit (128) in 'avs_asrc_create' [-Wframe-larger-than]
static int avs_asrc_create(struct avs_dev *adev, struct avs_path_module *mod)
^8 warnings generated.
Feel free to add either
or
when formally sending, thank you a lot for the fix!
Cheers,
Nathan
Quoted 75 lines
sound/soc/intel/avs/path.c +29
-25@@ -449,35 +449,39 @@ static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)return ret; } +static int avs_probe_create (struct avs_dev *adev,struct avs_path_module *mod) +{ +dev_err (adev->dev,"Probe module can't be instantiated by topology"); +return -EINVAL ; +} + +struct avs_module_create { +guid_t *guid; +int (*create)(struct avs_dev *adev,struct avs_path_module *mod); +}; + +static struct avs_module_create avs_module_create[] = { + { &AVS_MIXIN_MOD_UUID , avs_modbase_create }, + { &AVS_MIXOUT_MOD_UUID , avs_modbase_create }, + { &AVS_KPBUFF_MOD_UUID , avs_modbase_create }, + { &AVS_COPIER_MOD_UUID , avs_copier_create }, + { &AVS_MICSEL_MOD_UUID , avs_micsel_create }, + { &AVS_MUX_MOD_UUID , avs_mux_create }, + { &AVS_UPDWMIX_MOD_UUID , avs_updown_mix_create }, + { &AVS_SRCINTC_MOD_UUID , avs_src_create }, + { &AVS_AEC_MOD_UUID , avs_aec_create }, + { &AVS_ASRC_MOD_UUID , avs_asrc_create }, + { &AVS_INTELWOV_MOD_UUID , avs_wov_create }, + { &AVS_PROBE_MOD_UUID , avs_probe_create }, +}; +static int avs_path_module_type_create (struct avs_dev *adev,struct avs_path_module *mod) {const guid_t *type = &mod->template->cfg_ext->type; -if (guid_equal (type, &AVS_MIXIN_MOD_UUID ) || -guid_equal (type, &AVS_MIXOUT_MOD_UUID ) || -guid_equal (type, &AVS_KPBUFF_MOD_UUID )) -return avs_modbase_create (adev, mod); -if (guid_equal (type, &AVS_COPIER_MOD_UUID )) -return avs_copier_create (adev, mod); -if (guid_equal (type, &AVS_MICSEL_MOD_UUID )) -return avs_micsel_create (adev, mod); -if (guid_equal (type, &AVS_MUX_MOD_UUID )) -return avs_mux_create (adev, mod); -if (guid_equal (type, &AVS_UPDWMIX_MOD_UUID )) -return avs_updown_mix_create (adev, mod); -if (guid_equal (type, &AVS_SRCINTC_MOD_UUID )) -return avs_src_create (adev, mod); -if (guid_equal (type, &AVS_AEC_MOD_UUID )) -return avs_aec_create (adev, mod); -if (guid_equal (type, &AVS_ASRC_MOD_UUID )) -return avs_asrc_create (adev, mod); -if (guid_equal (type, &AVS_INTELWOV_MOD_UUID )) -return avs_wov_create (adev, mod); - -if (guid_equal (type, &AVS_PROBE_MOD_UUID )) { -dev_err (adev->dev,"Probe module can't be instantiated by topology"); -return -EINVAL ; - } + for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++) +if (guid_equal (type, avs_module_create[i].guid)) +return avs_module_create[i].create (adev, mod);return avs_modext_create (adev, mod); }