From b5919cee6281f643363b5c645bf3f70a0658e449 Mon Sep 17 00:00:00 2001 From: Shriram Shastry Date: Wed, 5 Jun 2024 08:22:03 +0530 Subject: [PATCH] Audio: MDRC: Restructure MDRC for effective memory allocation This check-in attempts to decrease memory allocation overhead, enhance cache efficiency through data locality, and lessen heap fragmentation. Within the MDRC component, combine memory allocations for the crossover, emphasis, and deemphasis filter coefficients into a single block. By streamlining memory management, the update lowers the possibility of memory leaks. Signed-off-by: Shriram Shastry --- src/audio/multiband_drc/multiband_drc.c | 133 +++++++++++++++--------- src/audio/multiband_drc/multiband_drc.h | 14 +++ 2 files changed, 99 insertions(+), 48 deletions(-) diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index e10b63d28d9a..7c8741e16c89 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -94,17 +95,45 @@ static int multiband_drc_eq_init_coef_ch(struct sof_eq_iir_biquad *coef, return 0; } -static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, uint32_t rate) +/** + * @Description Initialize coefficients for multiband DRC processing. + * + * Allocates and initializes filter coefficients for the multiband DRC module. Memory + * for the crossover, emphasis, and de-emphasis filter coefficients is allocated within + * a contiguous block if not previously done. The function checks for configuration + * validity and adheres to predefined channel and band count limits. + * + * The memory layout for the coefficients_block is as follows: + * @code + * +-----------------------------------+ + * | coefficients_block | + * +-----------------------------------+ + * | crossover_coef | num_bands * nch * sizeof(struct sof_eq_iir_biquad) + * +-----------------------------------+ <-- offset for emp_coef (crossover_coef + num_bands * nch) + * | emp_coef | num_bands * nch * sizeof(struct sof_eq_iir_biquad) + * +-----------------------------------+ <-- offset for deemp_coef (emp_coef + num_bands * nch) + * | deemp_coef | num_bands * nch * sizeof(struct sof_eq_iir_biquad) + * +-----------------------------------+ + * @endcode + * + * @parameters mod Pointer to the processing module containing multiband DRC data. + * @parameters nch Number of channels to process, up to PLATFORM_MAX_CHANNELS. + * @parameters rate Sampling rate, not used in current implementation. + * + * @return 0 on success or a negative error code on failure (e.g., invalid configuration, + * memory allocation failure). + */ + +static int multiband_drc_init_coef(struct processing_module *mod, + int16_t nch, uint32_t rate) { struct comp_dev *dev = mod->dev; struct multiband_drc_comp_data *cd = module_get_private_data(mod); - struct sof_eq_iir_biquad *crossover; - struct sof_eq_iir_biquad *emphasis; - struct sof_eq_iir_biquad *deemphasis; struct sof_multiband_drc_config *config = cd->config; struct multiband_drc_state *state = &cd->state; uint32_t sample_bytes = get_sample_bytes(cd->source_format); int i, ch, ret, num_bands; + bool alloc_success = false; if (!config) { comp_err(dev, "multiband_drc_init_coef(), no config is set"); @@ -113,75 +142,65 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u num_bands = config->num_bands; - /* Sanity checks */ - if (nch > PLATFORM_MAX_CHANNELS) { - comp_err(dev, - "multiband_drc_init_coef(), invalid channels count(%i)", nch); - return -EINVAL; - } - if (config->num_bands > SOF_MULTIBAND_DRC_MAX_BANDS) { - comp_err(dev, "multiband_drc_init_coef(), invalid bands count(%i)", - config->num_bands); + if (nch > PLATFORM_MAX_CHANNELS || num_bands > SOF_MULTIBAND_DRC_MAX_BANDS) { + comp_err(dev, "Invalid ch count(%i) or band count(%i)", nch, num_bands); return -EINVAL; } comp_info(dev, "multiband_drc_init_coef(), initializing %i-way crossover", - config->num_bands); + num_bands); + + /* Allocation for coefficients_block */ + if (!cd->coefficients_block) { + cd->coefficients_block = rballoc(0, SOF_MEM_CAPS_RAM, + sizeof(struct multiband_drc_coefficients)); + if (!cd->coefficients_block) { + comp_err(dev, "Failed to allocate coeff block multiband_drc_init_coef()"); + return -ENOMEM; + } + alloc_success = true; /* Allocation was successful */ + } + struct multiband_drc_coefficients *coefficients_block = cd->coefficients_block; + + /* Crossover, Emphasis, and Deemphasis EQ initialization for each channel */ + struct sof_eq_iir_biquad *crossover, *emphasis, *deemphasis; - /* Crossover: collect the coef array and assign it to every channel */ - crossover = config->crossover_coef; for (ch = 0; ch < nch; ch++) { - ret = crossover_init_coef_ch(crossover, &state->crossover[ch], - config->num_bands); - /* Free all previously allocated blocks in case of an error */ + crossover = coefficients_block->crossover + ch * num_bands; + emphasis = coefficients_block->emphasis + ch * num_bands; + deemphasis = coefficients_block->deemphasis + ch * num_bands; + + ret = crossover_init_coef_ch(crossover, &state->crossover[ch], num_bands); if (ret < 0) { - comp_err(dev, - "multiband_drc_init_coef(), could not assign coeffs to ch %d", ch); + comp_err(dev, "Can't assign xover coeffs to ch %d", ch); goto err; } - } - comp_info(dev, "multiband_drc_init_coef(), initializing emphasis_eq"); - - /* Emphasis: collect the coef array and assign it to every channel */ - emphasis = config->emp_coef; - for (ch = 0; ch < nch; ch++) { ret = multiband_drc_eq_init_coef_ch(emphasis, &state->emphasis[ch]); - /* Free all previously allocated blocks in case of an error */ if (ret < 0) { - comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", - ch); + comp_err(dev, "Can't assign emp coeffs to ch %d", ch); goto err; } - } - - comp_info(dev, "multiband_drc_init_coef(), initializing deemphasis_eq"); - /* Deemphasis: collect the coef array and assign it to every channel */ - deemphasis = config->deemp_coef; - for (ch = 0; ch < nch; ch++) { ret = multiband_drc_eq_init_coef_ch(deemphasis, &state->deemphasis[ch]); - /* Free all previously allocated blocks in case of an error */ if (ret < 0) { - comp_err(dev, "multiband_drc_init_coef(), could not assign coeffs to ch %d", - ch); + comp_err(dev, "Can't assign deemp coeffs to ch %d", ch); goto err; } } - /* Allocate all DRC pre-delay buffers and set delay time with band number */ + /* Initialize DRC state for each band */ for (i = 0; i < num_bands; i++) { comp_info(dev, "multiband_drc_init_coef(), initializing drc band %d", i); - ret = drc_init_pre_delay_buffers(&state->drc[i], (size_t)sample_bytes, (int)nch); + ret = drc_init_pre_delay_buffers(&state->drc[i], sample_bytes, nch); if (ret < 0) { - comp_err(dev, - "multiband_drc_init_coef(), could not init pre delay buffers"); + comp_err(dev, "multiband_drc_init_coef(), could not init pre delay buffers"); goto err; } ret = drc_set_pre_delay_time(&state->drc[i], - cd->config->drc_coef[i].pre_delay_time, rate); + config->drc_coef[i].pre_delay_time, rate); if (ret < 0) { comp_err(dev, "multiband_drc_init_coef(), could not set pre delay time"); goto err; @@ -191,6 +210,10 @@ static int multiband_drc_init_coef(struct processing_module *mod, int16_t nch, u return 0; err: + if (alloc_success && ret < 0) { + rfree(cd->coefficients_block); + cd->coefficients_block = NULL; + } multiband_drc_reset_state(state); return ret; } @@ -220,7 +243,6 @@ static int multiband_drc_init(struct processing_module *mod) struct module_data *md = &mod->priv; struct comp_dev *dev = mod->dev; struct module_config *cfg = &md->cfg; - struct multiband_drc_comp_data *cd; size_t bs = cfg->size; int ret; @@ -235,9 +257,13 @@ static int multiband_drc_init(struct processing_module *mod) return -EINVAL; } - cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); - if (!cd) + /* Memory allocation for multiband_drc_comp_data */ + struct multiband_drc_comp_data *cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, + SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) { + comp_err(dev, "multiband_drc_init(), allocation for multiband_drc_comp_data failed"); return -ENOMEM; + } md->private = cd; cd->multiband_drc_func = NULL; @@ -279,7 +305,18 @@ static int multiband_drc_free(struct processing_module *mod) comp_info(mod->dev, "multiband_drc_free()"); - comp_data_blob_handler_free(cd->model_handler); + if (cd) { + struct multiband_drc_state *state = &cd->state; + + /* Free emphasis/deemphasis IIR filter states for all channels */ + for (int i = 0; i < PLATFORM_MAX_CHANNELS; i++) { + multiband_drc_iir_reset_state_ch(&state->emphasis[i]); + multiband_drc_iir_reset_state_ch(&state->deemphasis[i]); + } + + /* Freeing other resources as part of the component data */ + comp_data_blob_handler_free(cd->model_handler); + } rfree(cd); return 0; diff --git a/src/audio/multiband_drc/multiband_drc.h b/src/audio/multiband_drc/multiband_drc.h index a1801f27ab6c..37eeff3a0b85 100644 --- a/src/audio/multiband_drc/multiband_drc.h +++ b/src/audio/multiband_drc/multiband_drc.h @@ -21,6 +21,12 @@ /** * Stores the state of the sub-components in Multiband DRC */ +struct multiband_drc_coefficients { + struct sof_eq_iir_biquad crossover[SOF_MULTIBAND_DRC_MAX_BANDS * PLATFORM_MAX_CHANNELS]; + struct sof_eq_iir_biquad emphasis[SOF_MULTIBAND_DRC_MAX_BANDS * PLATFORM_MAX_CHANNELS]; + struct sof_eq_iir_biquad deemphasis[SOF_MULTIBAND_DRC_MAX_BANDS * PLATFORM_MAX_CHANNELS]; +} __packed; + struct multiband_drc_state { struct iir_state_df2t emphasis[PLATFORM_MAX_CHANNELS]; struct crossover_state crossover[PLATFORM_MAX_CHANNELS]; @@ -38,6 +44,14 @@ struct multiband_drc_comp_data { struct multiband_drc_state state; /**< compressor state */ struct comp_data_blob_handler *model_handler; struct sof_multiband_drc_config *config; /**< pointer to setup blob */ + /** + * Pointer to the coefficients of the filters used in multiband DRC processing + * which includes crossover, emphasis, and deemphasis filters. These coefficients + * are used by the processing functions and are allocated during the initialization + * phase. This allows efficient access to filter parameters required for audio + * processing across all channels and bands. + */ + struct multiband_drc_coefficients *coefficients_block; /**< Filter coefficients */ bool config_ready; /**< set when fully received */ enum sof_ipc_frame source_format; /**< source frame format */ bool process_enabled; /**< true if component is enabled */