This series provides a bunch of quick updates which should make the coverage from pcm-test a bit more useful, it adds some support for skipping tests when the hardware/driver is unable to support the requested configuration and then expands the set of cases we cover to include more sample rates and channel counts. This should exercise switching between 8kHz and 44.1kHz based rates and ensure that clocking doesn't get confused by non-stereo channel counts, both of which are I expect common real world errors, at least for embedded cards.
v2: - Rebase onto Takashi's current tree. - Tweak the buffer sizes for the newly added cases, don't be quite so ambitious in how big a buffer we request for 96kHz and don't go quite so small for 8kHz since some devices start hitting lower limits on period size and struggle to deliver accurate timing.
Mark Brown (6): kselftest/alsa: Refactor pcm-test to list the tests to run in a struct kselftest/alsa: Report failures to set the requested sample rate as skips kselftest/alsa: Report failures to set the requested channels as skips kselftest/alsa: Don't any configuration in the sample config kselftest/alsa: Provide more meaningful names for tests kselftest/alsa: Add more coverage of sample rates and channel counts
.../alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf | 35 ++++---- tools/testing/selftests/alsa/pcm-test.c | 88 +++++++++++++------ 2 files changed, 81 insertions(+), 42 deletions(-)
base-commit: 2133dc91d6658242009177b564ac47c49e08668a
In order to help make the list of tests a bit easier to maintain refactor things so we pass the tests around as a struct with the parameters in, enabling us to add new tests by adding to a table with comments saying what each of the number are. We could also use named initializers if we get more parameters.
Signed-off-by: Mark Brown broonie@kernel.org --- tools/testing/selftests/alsa/pcm-test.c | 53 +++++++++++++++---------- 1 file changed, 33 insertions(+), 20 deletions(-)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index 6e7dfc395b98..dc36f4099954 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -37,6 +37,15 @@ struct pcm_data *pcm_list = NULL; int num_missing = 0; struct pcm_data *pcm_missing = NULL;
+struct time_test_def { + const char *cfg_prefix; + const char *format; + long rate; + long channels; + long period_size; + long buffer_size; +}; + void timestamp_now(timestamp_t *tstamp) { if (clock_gettime(CLOCK_MONOTONIC_RAW, tstamp)) @@ -220,9 +229,7 @@ static void find_pcms(void) }
static void test_pcm_time1(struct pcm_data *data, - const char *cfg_prefix, const char *sformat, - long srate, long schannels, - long speriod_size, long sbuffer_size) + const struct time_test_def *test) { char name[64], key[128], msg[256]; const char *cs; @@ -244,20 +251,20 @@ static void test_pcm_time1(struct pcm_data *data, snd_pcm_hw_params_alloca(&hw_params); snd_pcm_sw_params_alloca(&sw_params);
- cs = conf_get_string(data->pcm_config, cfg_prefix, "format", sformat); + cs = conf_get_string(data->pcm_config, test->cfg_prefix, "format", test->format); format = snd_pcm_format_value(cs); if (format == SND_PCM_FORMAT_UNKNOWN) ksft_exit_fail_msg("Wrong format '%s'\n", cs); - rate = conf_get_long(data->pcm_config, cfg_prefix, "rate", srate); - channels = conf_get_long(data->pcm_config, cfg_prefix, "channels", schannels); - period_size = conf_get_long(data->pcm_config, cfg_prefix, "period_size", speriod_size); - buffer_size = conf_get_long(data->pcm_config, cfg_prefix, "buffer_size", sbuffer_size); + rate = conf_get_long(data->pcm_config, test->cfg_prefix, "rate", test->rate); + channels = conf_get_long(data->pcm_config, test->cfg_prefix, "channels", test->channels); + period_size = conf_get_long(data->pcm_config, test->cfg_prefix, "period_size", test->period_size); + buffer_size = conf_get_long(data->pcm_config, test->cfg_prefix, "buffer_size", test->buffer_size);
- automatic = strcmp(sformat, snd_pcm_format_name(format)) == 0 && - srate == rate && - schannels == channels && - speriod_size == period_size && - sbuffer_size == buffer_size; + automatic = strcmp(test->format, snd_pcm_format_name(format)) == 0 && + test->rate == rate && + test->channels == channels && + test->period_size == period_size && + test->buffer_size == buffer_size;
samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8); if (!samples) @@ -293,7 +300,7 @@ static void test_pcm_time1(struct pcm_data *data, if (automatic && format == SND_PCM_FORMAT_S16_LE) { format = SND_PCM_FORMAT_S32_LE; ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n", - cfg_prefix, + test->cfg_prefix, data->card, data->device, data->subdevice, snd_pcm_stream_name(data->stream), snd_pcm_access_name(access)); @@ -362,7 +369,7 @@ static void test_pcm_time1(struct pcm_data *data, }
ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n", - cfg_prefix, + test->cfg_prefix, data->card, data->device, data->subdevice, snd_pcm_stream_name(data->stream), snd_pcm_access_name(access), @@ -411,7 +418,7 @@ static void test_pcm_time1(struct pcm_data *data, pass = true; __close: ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n", - cfg_prefix, + test->cfg_prefix, data->card, data->device, data->subdevice, snd_pcm_stream_name(data->stream), msg[0] ? " " : "", msg); @@ -420,11 +427,16 @@ static void test_pcm_time1(struct pcm_data *data, snd_pcm_close(handle); }
-#define TESTS_PER_PCM 2 +static const struct time_test_def time_tests[] = { + /* name format rate chan period buffer */ + { "test.time1", "S16_LE", 48000, 2, 512, 4096 }, + { "test.time2", "S16_LE", 48000, 2, 24000, 192000 }, +};
int main(void) { struct pcm_data *pcm; + int i;
ksft_print_header();
@@ -432,7 +444,7 @@ int main(void)
find_pcms();
- ksft_set_plan(num_missing + num_pcms * TESTS_PER_PCM); + ksft_set_plan(num_missing + num_pcms * ARRAY_SIZE(time_tests));
for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) { ksft_test_result(false, "test.missing.%d.%d.%d.%s\n", @@ -441,8 +453,9 @@ int main(void) }
for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) { - test_pcm_time1(pcm, "test.time1", "S16_LE", 48000, 2, 512, 4096); - test_pcm_time1(pcm, "test.time2", "S16_LE", 48000, 2, 24000, 192000); + for (i = 0; i < ARRAY_SIZE(time_tests); i++) { + test_pcm_time1(pcm, &time_tests[i]); + } }
conf_free();
If constraint selection gives us a sample rate other than the one that we asked for that isn't a failure, that is the device implementing sample rate constraints and advertising that it can't support whatever we asked for. Report such cases as a test skip rather than failure so we don't have false positives.
Signed-off-by: Mark Brown broonie@kernel.org --- tools/testing/selftests/alsa/pcm-test.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index dc36f4099954..edb820fe2ee6 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -247,6 +247,7 @@ static void test_pcm_time1(struct pcm_data *data, bool pass = false, automatic = true; snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; + bool skip = false;
snd_pcm_hw_params_alloca(&hw_params); snd_pcm_sw_params_alloca(&sw_params); @@ -321,7 +322,8 @@ static void test_pcm_time1(struct pcm_data *data, goto __close; } if (rrate != rate) { - snprintf(msg, sizeof(msg), "rate mismatch %ld != %ld", rate, rrate); + snprintf(msg, sizeof(msg), "rate unsupported %ld != %ld", rate, rrate); + skip = true; goto __close; } rperiod_size = period_size; @@ -417,11 +419,20 @@ static void test_pcm_time1(struct pcm_data *data, msg[0] = '\0'; pass = true; __close: - ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n", - test->cfg_prefix, - data->card, data->device, data->subdevice, - snd_pcm_stream_name(data->stream), - msg[0] ? " " : "", msg); + if (!skip) { + ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n", + test->cfg_prefix, + data->card, data->device, data->subdevice, + snd_pcm_stream_name(data->stream), + msg[0] ? " " : "", msg); + } else { + ksft_test_result_skip("%s.%d.%d.%d.%s%s%s\n", + test->cfg_prefix, + data->card, data->device, + data->subdevice, + snd_pcm_stream_name(data->stream), + msg[0] ? " " : "", msg); + } free(samples); if (handle) snd_pcm_close(handle);
If constraint selection gives us a number of channels other than the one that we asked for that isn't a failure, that is the device implementing constraints and advertising that it can't support whatever we asked for. Report such cases as a test skip rather than failure so we don't have false positives.
Signed-off-by: Mark Brown broonie@kernel.org --- tools/testing/selftests/alsa/pcm-test.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index edb820fe2ee6..c701cf507a95 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -241,6 +241,7 @@ static void test_pcm_time1(struct pcm_data *data, snd_pcm_sframes_t frames; long long ms; long rate, channels, period_size, buffer_size; + unsigned int rchannels; unsigned int rrate; snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold; timestamp_t tstamp; @@ -310,11 +311,17 @@ static void test_pcm_time1(struct pcm_data *data, snd_pcm_format_name(format), snd_strerror(err)); goto __close; } - err = snd_pcm_hw_params_set_channels(handle, hw_params, channels); + rchannels = channels; + err = snd_pcm_hw_params_set_channels_near(handle, hw_params, &rchannels); if (err < 0) { snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_channels %ld: %s", channels, snd_strerror(err)); goto __close; } + if (rchannels != channels) { + snprintf(msg, sizeof(msg), "channels unsupported %ld != %ld", channels, rchannels); + skip = true; + goto __close; + } rrate = rate; err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0); if (err < 0) {
The values in the one example configuration file we currently have are the default values for the two tests we have so there's no need to actually set them. Comment them out as examples, with a rename for the tests so that we can update the tests in the code more easily.
Signed-off-by: Mark Brown broonie@kernel.org --- .../alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf b/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf index 0a83f35d43eb..9eca985e0c08 100644 --- a/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf +++ b/tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf @@ -39,22 +39,25 @@ card.hda { # pcm.0.0 { PLAYBACK { - test.time1 { - access RW_INTERLEAVED # can be omitted - default - format S16_LE # can be omitted - default - rate 48000 # can be omitted - default - channels 2 # can be omitted - default - period_size 512 - buffer_size 4096 - } - test.time2 { - access RW_INTERLEAVED - format S16_LE - rate 48000 - channels 2 - period_size 24000 - buffer_size 192000 - } + # + # Uncomment to override values for specific tests + # + #test_name1 { + # access RW_INTERLEAVED + # format S16_LE + # rate 48000 + # channels 2 + # period_size 512 + # buffer_size 4096 + #} + #test_name2 { + # access RW_INTERLEAVED + # format S16_LE + # rate 48000 + # channels 2 + # period_size 24000 + # buffer_size 192000 + #} } CAPTURE { # use default tests, check for the presence
Rather than just numbering the tests try to provide semi descriptive names for what the tests are trying to cover. This also has the advantage of meaning we can add more tests without having to keep the list of tests ordered by existing number which should make it easier to understand what we're testing and why.
Signed-off-by: Mark Brown broonie@kernel.org --- tools/testing/selftests/alsa/pcm-test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index c701cf507a95..afa13377481d 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -446,9 +446,9 @@ static void test_pcm_time1(struct pcm_data *data, }
static const struct time_test_def time_tests[] = { - /* name format rate chan period buffer */ - { "test.time1", "S16_LE", 48000, 2, 512, 4096 }, - { "test.time2", "S16_LE", 48000, 2, 24000, 192000 }, + /* name format rate chan period buffer */ + { "S16.48k.2.small", "S16_LE", 48000, 2, 512, 4096 }, + { "S16.48k.2.big", "S16_LE", 48000, 2, 24000, 192000 }, };
int main(void)
Now that we can skip unsupported configurations add some more test cases using that, cover 8kHz, 44.1kHz and 96kHz plus 8kHz mono and 48kHz 6 channel.
44.1kHz is a different clock base to the existing 48kHz tests and may therefore show problems with the clock configuration if only 8kHz based rates are really available (or help diagnose if bad clocking is due to only 44.1kHz based rates being supported). 8kHz mono and 48Hz 6 channel are real world formats and should show if clocking does not account for channel count properly.
Signed-off-by: Mark Brown broonie@kernel.org --- tools/testing/selftests/alsa/pcm-test.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index afa13377481d..f293c7d81009 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -446,9 +446,14 @@ static void test_pcm_time1(struct pcm_data *data, }
static const struct time_test_def time_tests[] = { - /* name format rate chan period buffer */ - { "S16.48k.2.small", "S16_LE", 48000, 2, 512, 4096 }, - { "S16.48k.2.big", "S16_LE", 48000, 2, 24000, 192000 }, + /* name format rate chan period buffer */ + { "8k.1.big", "S16_LE", 8000, 2, 8000, 32000 }, + { "8k.2.big", "S16_LE", 8000, 2, 8000, 32000 }, + { "44k1.2.big", "S16_LE", 44100, 2, 22050, 192000 }, + { "48k.2.small", "S16_LE", 48000, 2, 512, 4096 }, + { "48k.2.big", "S16_LE", 48000, 2, 24000, 192000 }, + { "48k.6.big", "S16_LE", 48000, 6, 48000, 576000 }, + { "96k.2.big", "S16_LE", 96000, 2, 48000, 192000 }, };
int main(void)
On Thu, 01 Dec 2022 18:07:39 +0100, Mark Brown wrote:
This series provides a bunch of quick updates which should make the coverage from pcm-test a bit more useful, it adds some support for skipping tests when the hardware/driver is unable to support the requested configuration and then expands the set of cases we cover to include more sample rates and channel counts. This should exercise switching between 8kHz and 44.1kHz based rates and ensure that clocking doesn't get confused by non-stereo channel counts, both of which are I expect common real world errors, at least for embedded cards.
v2:
- Rebase onto Takashi's current tree.
- Tweak the buffer sizes for the newly added cases, don't be quite so ambitious in how big a buffer we request for 96kHz and don't go quite so small for 8kHz since some devices start hitting lower limits on period size and struggle to deliver accurate timing.
Applied now. Thanks.
Takashi
linux-kselftest-mirror@lists.linaro.org