Skip to content

Commit

Permalink
debug: tester loadable module framework
Browse files Browse the repository at this point in the history
Tester module is a framework for a runtime testing
that need a special internal code i.e. provide an extra
load to CPU by running additional thread, etc.

The idea is to allow testing of special cases
using a standard "production" build. The module should
be compiled as a loadable module only, as it is not needed
in any real production case.

In order to keep only one testing module (in meaning of
a SOF module with separate UUID), a framework is introduced,
where a test to be executed is selected by IPC parameter

Signed-off-by: Marcin Szkudlinski <[email protected]>
  • Loading branch information
marcinszkudlinski committed Jan 21, 2025
1 parent e2c7630 commit 4f74e6f
Show file tree
Hide file tree
Showing 20 changed files with 544 additions and 3 deletions.
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace15_mtpm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CONFIG_COMP_CHAIN_DMA=y
CONFIG_COMP_CROSSOVER=y
CONFIG_COMP_DRC=y
CONFIG_COMP_KPB=y
CONFIG_COMP_TESTER=m
CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y
CONFIG_COMP_SRC_LITE=y
CONFIG_COMP_MFCC=y
Expand Down
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace20_lnl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ CONFIG_COMP_ARIA=y
CONFIG_COMP_CHAIN_DMA=y
CONFIG_COMP_DRC=m
CONFIG_COMP_KPB=y
CONFIG_COMP_TESTER=m
CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y
CONFIG_COMP_UP_DOWN_MIXER=y
CONFIG_COMP_VOLUME_WINDOWS_FADE=y
Expand Down
1 change: 1 addition & 0 deletions app/boards/intel_adsp_ace30_ptl.conf
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ CONFIG_COMP_ARIA=y
CONFIG_COMP_CHAIN_DMA=y
CONFIG_COMP_DRC=y
CONFIG_COMP_KPB=y
CONFIG_COMP_TESTER=m
CONFIG_COMP_SRC_IPC4_FULL_MATRIX=y
CONFIG_COMP_UP_DOWN_MIXER=y
CONFIG_COMP_VOLUME_WINDOWS_FADE=y
Expand Down
1 change: 1 addition & 0 deletions app/configs/mtl/modules.conf
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ CONFIG_COMP_CROSSOVER=m
CONFIG_COMP_MULTIBAND_DRC=m
CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=m
CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=m
CONFIG_COMP_TESTER=m
2 changes: 2 additions & 0 deletions src/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ rsource "library_manager/Kconfig"
rsource "debug/telemetry/Kconfig"

rsource "debug/debug_stream/Kconfig"

rsource "debug/tester/Kconfig"
5 changes: 2 additions & 3 deletions src/audio/sink_source_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ int source_to_sink_copy(struct sof_source *source,
sink_commit_buffer(sink, INT_MAX);
return 0;
}
EXPORT_SYMBOL(source_to_sink_copy);

int sink_fill_with_silence(struct sof_sink *sink, size_t size)
{
Expand Down Expand Up @@ -107,6 +108,7 @@ int sink_fill_with_silence(struct sof_sink *sink, size_t size)
sink_commit_buffer(sink, INT_MAX);
return 0;
}
EXPORT_SYMBOL(sink_fill_with_silence);

int source_drop_data(struct sof_source *source, size_t size)
{
Expand All @@ -130,7 +132,4 @@ int source_drop_data(struct sof_source *source, size_t size)
source_release_data(source, INT_MAX);
return 0;
}

EXPORT_SYMBOL(sink_fill_with_silence);
EXPORT_SYMBOL(source_to_sink_copy);
EXPORT_SYMBOL(source_drop_data);
4 changes: 4 additions & 0 deletions src/debug/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ if(CONFIG_GDB_DEBUG)
add_subdirectory(gdb)
endif()

if(CONFIG_COMP_TESTER)
add_subdirectory(tester)
endif()

add_local_sources(sof panic.c)
2 changes: 2 additions & 0 deletions src/debug/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
add_local_sources(tester.c)
add_local_sources(tester_dummy_test.c)
8 changes: 8 additions & 0 deletions src/debug/tester/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: BSD-3-Clause

config COMP_TESTER
tristate "tester module"
default n
depends on IPC_MAJOR_4
help
Select for loadable module for testing
7 changes: 7 additions & 0 deletions src/debug/tester/llext/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2024 Intel Corporation.
# SPDX-License-Identifier: Apache-2.0

sof_llext_build("tester"
SOURCES ../tester.c
../tester_dummy_test.c
)
6 changes: 6 additions & 0 deletions src/debug/tester/llext/llext.toml.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <tools/rimage/config/platform.toml>
#define LOAD_TYPE "2"
#include "../tester.toml"
[module]
count = __COUNTER__
244 changes: 244 additions & 0 deletions src/debug/tester/tester.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
//SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2025 Intel Corporation. All rights reserved.
//
// Author: Marcin Szkudlinski <[email protected]>

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <rtos/init.h>
#include <sof/lib/uuid.h>
#include <sof/audio/component.h>
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/sink_api.h>
#include <sof/audio/source_api.h>
#include <sof/audio/sink_source_utils.h>
#include "tester.h"
#include "tester_dummy_test.h"

/**
* Tester module is a framework for a runtime testing that need a special internal code
* i.e. provide an extra load to CPU by running additional thread, etc.
*
* The idea is to allow testing of special cases using a standard "production" build.
* The module should be compiled as a loadable module only, as it is not needed
* in any real production case.
*
* In order to keep only one testing module (in meaning of
* a SOF module with separate UUID), a framework is introduced,
* where a test to be executed is selected by IPC parameter
*/

LOG_MODULE_REGISTER(tester, CONFIG_SOF_LOG_LEVEL);

SOF_DEFINE_REG_UUID(tester);

DECLARE_TR_CTX(tester_tr, SOF_UUID(tester_uuid), LOG_LEVEL_INFO);

struct tester_init_config {
struct ipc4_base_module_cfg ipc4_cfg;
int32_t test_type;
} __attribute__((packed, aligned(4)));

static int tester_init(struct processing_module *mod)
{
struct module_data *md = &mod->priv;
struct comp_dev *dev = mod->dev;
struct module_config *cfg = &md->cfg;
size_t bs = cfg->size;
struct tester_module_data *cd = NULL;
int ret = 0;

if (bs != sizeof(struct tester_init_config)) {
comp_err(dev, "tester_init(): Invalid config");
return -EINVAL;
}

/* allocate ctx for test module in shared memory - to allow all non-standard operations
* without problems with cache
*/
cd = rzalloc(SOF_MEM_ZONE_SYS_SHARED, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
if (!cd) {
comp_err(dev, "Out of memory");
return -ENOMEM;
}

struct tester_init_config *init_cfg = (struct tester_init_config *)cfg->init_data;

cd->test_case_type = init_cfg->test_type;
switch (cd->test_case_type) {
case TESTER_MODULE_CASE_DUMMY_TEST:
cd->tester_case_interface = &tester_interface_dummy_test;
break;

default:
comp_err(dev, "Invalid config, unknown test type");
return -EINVAL;
}

module_set_private_data(mod, cd);

if (cd->tester_case_interface->init)
ret = cd->tester_case_interface->init(mod, &cd->test_case_ctx);

return ret;
}

static int tester_prepare(struct processing_module *mod,
struct sof_source **sources, int num_of_sources,
struct sof_sink **sinks, int num_of_sinks)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->prepare)
ret = cd->tester_case_interface->prepare(cd->test_case_ctx, mod,
sources, num_of_sources,
sinks, num_of_sinks);

return ret;
}

int tester_set_configuration(struct processing_module *mod,
uint32_t config_id,
enum module_cfg_fragment_position pos, uint32_t data_offset_size,
const uint8_t *fragment, size_t fragment_size, uint8_t *response,
size_t response_size)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->set_configuration)
ret = cd->tester_case_interface->set_configuration(
cd->test_case_ctx, mod, config_id, pos, data_offset_size,
fragment, fragment_size, response, response_size);

return ret;
}

static int tester_process(struct processing_module *mod,
struct sof_source **sources, int num_of_sources,
struct sof_sink **sinks, int num_of_sinks)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;
bool do_copy = true;

if (cd->tester_case_interface->process)
ret = cd->tester_case_interface->process(cd->test_case_ctx, mod,
sources, num_of_sources,
sinks, num_of_sinks, &do_copy);

if (!ret) {
size_t sink_free = sink_get_free_size(sinks[0]);
size_t source_avail = source_get_data_available(sources[0]);
size_t to_copy = MIN(sink_free, source_avail);

if (do_copy) {
/* copy data from input to output */
source_to_sink_copy(sources[0], sinks[0], true, to_copy);
} else {
/* drop data and generate silence */
source_drop_data(sources[0], to_copy);
sink_fill_with_silence(sinks[0], to_copy);
}
}

return ret;
}

static int tester_reset(struct processing_module *mod)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->reset)
ret = cd->tester_case_interface->reset(cd->test_case_ctx, mod);

return ret;
}

static int tester_free(struct processing_module *mod)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->free)
ret = cd->tester_case_interface->free(cd->test_case_ctx, mod);

rfree(cd);
return ret;
}

static int tester_bind(struct processing_module *mod, void *data)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->bind)
ret = cd->tester_case_interface->bind(cd->test_case_ctx, mod, data);

return ret;
}

static int tester_unbind(struct processing_module *mod, void *data)
{
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->unbind)
ret = cd->tester_case_interface->unbind(cd->test_case_ctx, mod, data);

return ret;
}

static int tester_trigger(struct processing_module *mod, int cmd)
{
struct comp_dev *dev = mod->dev;
struct tester_module_data *cd = module_get_private_data(mod);
int ret = 0;

if (cd->tester_case_interface->trigger)
ret = cd->tester_case_interface->trigger(cd->test_case_ctx, mod, cmd);

if (!ret)
ret = module_adapter_set_state(mod, mod->dev, cmd);

return ret;
}

static const struct module_interface tester_interface = {
.init = tester_init,
.prepare = tester_prepare,
.set_configuration = tester_set_configuration,
.process = tester_process,
.reset = tester_reset,
.free = tester_free,
.bind = tester_bind,
.unbind = tester_unbind,
.trigger = tester_trigger
};

DECLARE_MODULE_ADAPTER(tester_interface, tester_uuid, tester_tr);
SOF_MODULE_INIT(tester, sys_comp_module_tester_interface_init);

#if CONFIG_COMP_TESTER_MODULE
/* modular: llext dynamic link */

#include <module/module/api_ver.h>
#include <module/module/llext.h>
#include <rimage/sof/user/manifest.h>

/* 08aeb4ff-7f68-4c71-86c3c842b4262898 */
#define UUID_TESTER 0xff, 0xb4, 0xae, 0x08, 0x68, 0x7f, 0x71, 0x4c, \
0x86, 0xc3, 0xc8, 0x42, 0xb4, 0x26, 0x28, 0x98

SOF_LLEXT_MOD_ENTRY(tester, &tester_interface);

static const struct sof_man_module_manifest mod_manifest __section(".module") __used =
SOF_LLEXT_MODULE_MANIFEST("TESTER", tester_llext_entry, 1, UUID_TESTER, 40);

SOF_LLEXT_BUILDINFO;

#endif
Loading

0 comments on commit 4f74e6f

Please sign in to comment.