Tools: Testbench: Track and print heap usage for modules#10593
Tools: Testbench: Track and print heap usage for modules#10593singalsu wants to merge 1 commit intothesofproject:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds reporting of per-module peak heap consumption at the end of a sof-testbench4 run by reading each module’s heap_high_water_mark tracked by the module adapter.
Changes:
- Collect IPC4 module heap high-water marks by iterating the IPC4 widget list and resolving component devices.
- Print per-module heap usage in the test summary output.
- Introduce a small record struct (
tb_heap_usage_record) to pass heap usage data to the stats printer.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| tools/testbench/testbench.c | Adds IPC4-only collection of module heap HWM and prints the results in the pipeline stats output. |
| tools/testbench/include/testbench/utils.h | Introduces tb_heap_usage_record used to carry module name and heap HWM to the stats function. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tools/testbench/testbench.c
Outdated
| } | ||
|
|
||
| records[count].module_name = info->name; | ||
| records[count].heap_max = (int)dev->mod->priv.resources.heap_high_water_mark; |
There was a problem hiding this comment.
heap_high_water_mark is a size_t (see src/include/sof/audio/module_adapter/module/generic.h), but it’s being cast to int and printed with %d. This can truncate/overflow and report incorrect (even negative) values on 64-bit hosts. Consider storing heap_max as size_t (or uint64_t) in tb_heap_usage_record and printing with the matching format specifier (e.g., %zu).
| records[count].heap_max = (int)dev->mod->priv.resources.heap_high_water_mark; | |
| /* heap_high_water_mark is size_t; clamp to INT_MAX to avoid overflow */ | |
| { | |
| size_t heap_high_water_mark = dev->mod->priv.resources.heap_high_water_mark; | |
| if (heap_high_water_mark > (size_t)INT_MAX) | |
| records[count].heap_max = INT_MAX; | |
| else | |
| records[count].heap_max = (int)heap_high_water_mark; | |
| } |
There was a problem hiding this comment.
Print of %zu isn't working with xt-clang/xt-run env. I can change the storage type and typecast the print.
There was a problem hiding this comment.
Storage is now size_t and print is with typecast to uint32_t. We can't use more heap in DSP than what the uint32_t range is.
This patch adds to end to sof-testbench4 run print of peak heap consumption for each module. The information is retrieved from heap_high_water_mark data that is tracked by module adapter for each module. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
215636e to
8fc72b9
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (count >= TB_NUM_WIDGETS_SUPPORTED) { | ||
| fprintf(stderr, "Error: Too many components for heap records, max %d.\n", | ||
| TB_NUM_WIDGETS_SUPPORTED); | ||
| break; |
There was a problem hiding this comment.
tb_collect_heap_usage() caps heap records at TB_NUM_WIDGETS_SUPPORTED (16) and breaks out, which will silently drop heap usage for remaining modules on larger topologies. Consider sizing the record buffer to the actual number of non-AIF/DAI components (e.g., first pass to count, then allocate), or introduce a dedicated "max components" constant that is large enough for real-world IPC4 topologies.
| break; | |
| *count_out = count; | |
| return -EINVAL; |
| } | ||
|
|
||
| records[count].module_name = info->name; | ||
| records[count].heap_max = dev->mod->priv.resources.heap_high_water_mark; |
There was a problem hiding this comment.
tb_collect_heap_usage() reads dev->mod->priv.resources.heap_high_water_mark directly. Since module_adapter_heap_usage(mod, &hwm) exists in the module adapter API, prefer using that accessor to avoid coupling testbench to internal processing_module layout/details.
| records[count].heap_max = dev->mod->priv.resources.heap_high_water_mark; | |
| if (module_adapter_heap_usage(dev->mod, &records[count].heap_max) < 0) | |
| continue; |
| delta_t = (td1.tv_sec - td0.tv_sec) * 1000000; | ||
| delta_t += (td1.tv_nsec - td0.tv_nsec) / 1000; | ||
| test_pipeline_stats(tp, delta_t); | ||
| test_pipeline_stats(tp, delta_t, heap_usage_records, heap_usage_records_count); |
There was a problem hiding this comment.
In error paths that goto out before tb_gettime(&td0) / tb_gettime(&td1) run, td0/td1 can be uninitialized, but delta_t is still computed from them. This is undefined behavior and can print garbage timing (or worse). Initialize td0/td1 and/or gate the delta_t calculation/printing behind a flag that indicates timing was captured.
| printf("\n"); | ||
| if (delta_t) | ||
| printf("Total execution time: %lld us, %.2f x realtime\n\n", delta_t, | ||
| (float)frames_out / tp->fs_out * 1000000 / delta_t); |
There was a problem hiding this comment.
test_pipeline_stats() no longer prints a trailing blank line when delta_t == 0 (previously it always printed \n). If delta_t can be 0 for short runs or error cases, consider keeping an unconditional newline to avoid the next output running into the summary block.
| (float)frames_out / tp->fs_out * 1000000 / delta_t); | |
| (float)frames_out / tp->fs_out * 1000000 / delta_t); | |
| else | |
| printf("\n"); |
This patch adds to end to sof-testbench4 run print of peak heap consumption for each module. The information is retrieved from heap_high_water_mark data that is tracked by module adapter for each module.
Example of output (sof-hda-generic.tplg):