diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..6858a9a --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,72 @@ +@Library('xmos_jenkins_shared_library@v0.28.0') _ + +def runningOn(machine) { + println "Stage running on:" + println machine +} + +getApproval() + +pipeline { + agent { + label 'linux&&x86_64' + } + + options { + skipDefaultCheckout() + timestamps() + buildDiscarder(xmosDiscardBuildSettings(onlyArtifacts=true)) + } + + parameters { + string( + name: 'TOOLS_VERSION', + defaultValue: '15.2.1', + description: 'The XTC tools version' + ) + } // parameters + + environment { + XMOSDOC_VERSION = "v5.1.1" + } // environment + + stages { + stage('Setup') { + steps { + runningOn(env.NODE_NAME) + dir("fwk_io") { + checkout scm + sh 'git submodule update --init --recursive' + } + createVenv("fwk_io/test/requirements.txt") + dir("fwk_io/test") { + // build everything + withVenv { + withTools(params.TOOLS_VERSION) { + sh "pip install -Ur requirements.txt" + } + } + } + } //steps + } // stage + + stage('Build HIL tests') { + steps { + dir("fwk_io/test") { + // build everything + withVenv { + withTools(params.TOOLS_VERSION) { + sh "sh ./build_hil_tests.sh" + } + } + } + } // steps + post { + cleanup { + xcoreCleanSandbox() + } + } // post + } // stage + } // stages +} + diff --git a/test/build_hil_tests.sh b/test/build_hil_tests.sh index 7bb0786..7d20598 100755 --- a/test/build_hil_tests.sh +++ b/test/build_hil_tests.sh @@ -1,9 +1,9 @@ -#!/bin/bash +#!/bin/sh set -e FRAMEWORK_IO_ROOT=`git rev-parse --show-toplevel` -source ${FRAMEWORK_IO_ROOT}/tools/ci/helper_functions.sh +. ${FRAMEWORK_IO_ROOT}/tools/ci/helper_functions.sh # perform builds ## TODO replace with build and running tests diff --git a/test/build_lib_i2s_tests.sh b/test/build_lib_i2s_tests.sh index ecc5678..de3aa19 100755 --- a/test/build_lib_i2s_tests.sh +++ b/test/build_lib_i2s_tests.sh @@ -9,18 +9,6 @@ source ${FRAMEWORK_IO_ROOT}/tools/ci/helper_functions.sh # row format is: "make_target BOARD toolchain" declare -a applications=( - "test_hil_backpressure_test_32_768000_4_5_5" - "test_hil_backpressure_test_32_768000_4_0_10" - "test_hil_backpressure_test_32_768000_4_10_0" - "test_hil_backpressure_test_32_768000_3_5_5" - "test_hil_backpressure_test_32_768000_3_0_10" - "test_hil_backpressure_test_32_768000_3_10_0" - "test_hil_backpressure_test_32_768000_2_5_5" - "test_hil_backpressure_test_32_768000_2_0_10" - "test_hil_backpressure_test_32_768000_2_10_0" - "test_hil_backpressure_test_32_768000_1_5_5" - "test_hil_backpressure_test_32_768000_1_0_10" - "test_hil_backpressure_test_32_768000_1_10_0" "test_hil_backpressure_test_32_384000_4_5_5" "test_hil_backpressure_test_32_384000_4_0_10" "test_hil_backpressure_test_32_384000_4_10_0" @@ -81,18 +69,6 @@ declare -a applications=( "test_hil_i2s_slave_test_32_1_4_0_inv" "test_hil_i2s_slave_test_32_1_0_4_inv" "test_hil_i2s_slave_test_32_1_2_2_inv" - "test_hil_backpressure_test_16_768000_4_5_5" - "test_hil_backpressure_test_16_768000_4_0_10" - "test_hil_backpressure_test_16_768000_4_10_0" - "test_hil_backpressure_test_16_768000_3_5_5" - "test_hil_backpressure_test_16_768000_3_0_10" - "test_hil_backpressure_test_16_768000_3_10_0" - "test_hil_backpressure_test_16_768000_2_5_5" - "test_hil_backpressure_test_16_768000_2_0_10" - "test_hil_backpressure_test_16_768000_2_10_0" - "test_hil_backpressure_test_16_768000_1_5_5" - "test_hil_backpressure_test_16_768000_1_0_10" - "test_hil_backpressure_test_16_768000_1_10_0" "test_hil_backpressure_test_16_384000_4_5_5" "test_hil_backpressure_test_16_384000_4_0_10" "test_hil_backpressure_test_16_384000_4_10_0" diff --git a/test/lib_i2s/backpressure_test/backpressure_test.cmake b/test/lib_i2s/backpressure_test/backpressure_test.cmake index 554780d..4a14538 100644 --- a/test/lib_i2s/backpressure_test/backpressure_test.cmake +++ b/test/lib_i2s/backpressure_test/backpressure_test.cmake @@ -24,7 +24,7 @@ set(APP_LINK_OPTIONS # Tile Targets #********************** if(NOT DEFINED ENV{SAMPLE_RATES}) - set(SAMPLE_RATES 768000 384000 192000) + set(SAMPLE_RATES 384000 192000) else() set(SAMPLE_RATES $ENV{SAMPLE_RATES}) endif() diff --git a/test/lib_i2s/backpressure_test/src/main.c b/test/lib_i2s/backpressure_test/src/main.c index d28db53..d53e8d9 100644 --- a/test/lib_i2s/backpressure_test/src/main.c +++ b/test/lib_i2s/backpressure_test/src/main.c @@ -14,7 +14,7 @@ #define BURN_THREADS 6 #endif #ifndef SAMPLE_FREQUENCY -#define SAMPLE_FREQUENCY 768000 +#define SAMPLE_FREQUENCY 192000 #endif #ifndef TEST_LEN #define TEST_LEN 1000 @@ -44,6 +44,127 @@ #define SETSR(c) asm volatile("setsr %0" : : "n"(c)); +enum { + SAMPLE_RATE_192000, + SAMPLE_RATE_384000, + NUM_SAMPLE_RATES +}e_sample_rates; + +enum { + BITDEPTH_16, + BITDEPTH_32, + NUM_BIT_DEPTHS +}e_bit_depth; + +enum { + NUM_I2S_LINES_1, + NUM_I2S_LINES_2, + NUM_I2S_LINES_3, + NUM_I2S_LINES_4, +}e_channel_config; + +static int acceptable_receive_delay = 0, acceptable_send_delay = 0; +static int acceptable_delay_ticks[NUM_SAMPLE_RATES][NUM_I2S_LINES_4+1][NUM_BIT_DEPTHS]; + +static inline void populate_acceptable_delay_ticks() +{ + // These numbers are logged by running the test and logging the delay at the last passing iteration + // before the backpressure test starts failing. So, on top of the bare minimum code in the i2s_send() + // and i2s_receive() functions in this file plus their calling overheads, we have acceptable_delay_ticks number + // of cycles per send and receive callback function call to add any extra processing. + + // 192 KHz + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_1][BITDEPTH_16] = 170; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_1][BITDEPTH_32] = 185; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_2][BITDEPTH_16] = 140; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_2][BITDEPTH_32] = 155; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_3][BITDEPTH_16] = 105; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_3][BITDEPTH_32] = 125; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_4][BITDEPTH_16] = 70; + acceptable_delay_ticks[SAMPLE_RATE_192000][NUM_I2S_LINES_4][BITDEPTH_32] = 90; + + // 384 KHz + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_1][BITDEPTH_16] = 50; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_1][BITDEPTH_32] = 55; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_2][BITDEPTH_16] = 15; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_2][BITDEPTH_32] = 25; + // For 384 KHz, we have non-zero backpressure only up to 2 channels + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_3][BITDEPTH_16] = 0; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_3][BITDEPTH_32] = 0; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_4][BITDEPTH_16] = 0; + acceptable_delay_ticks[SAMPLE_RATE_384000][NUM_I2S_LINES_4][BITDEPTH_32] = 0; +} + +void get_acceptable_delay() +{ + int sample_rate; + if(SAMPLE_FREQUENCY == 192000) + { + sample_rate = SAMPLE_RATE_192000; + } + else if(SAMPLE_FREQUENCY == 384000) + { + sample_rate = SAMPLE_RATE_384000; + } + else + { + printf("ERROR: Invalid sample rate %d\n", SAMPLE_FREQUENCY); + _Exit(1); + } + + int bit_depth; + if(DATA_BITS == 16) + { + bit_depth = BITDEPTH_16; + } + else if(DATA_BITS == 32) + { + bit_depth = BITDEPTH_32; + } + else + { + printf("ERROR: Invalid bit_depth %d\n", DATA_BITS); + _Exit(1); + } + if((NUM_I2S_LINES < 1) || (NUM_I2S_LINES > 4)) + { + printf("ERROR: Invalid NUM_I2S_LINES %d\n", NUM_I2S_LINES); + _Exit(1); + } + int delay = acceptable_delay_ticks[sample_rate][NUM_I2S_LINES-1][bit_depth]; + + if(delay <= 0) + { + printf("ERROR: Invalid delay %d. Check if testing an unsupported configuration\n", delay); + _Exit(1); + } + + // get the send and receive delay based on the + if((RECEIVE_DELAY_INCREMENT == 5) && (SEND_DELAY_INCREMENT == 5)) + { + // Backpressure passes at delay, so add another increment number of ticks to get to the first fail instance + acceptable_receive_delay = delay + 5; + acceptable_send_delay = delay + 5; + } + else if((RECEIVE_DELAY_INCREMENT == 0) && (SEND_DELAY_INCREMENT == 10)) + { + // Backpressure passes at 2*delay, so add another increment number of ticks to get to the first fail instance + acceptable_receive_delay = 0; + acceptable_send_delay = 2*delay + 10; + } + else if((RECEIVE_DELAY_INCREMENT == 10) && (SEND_DELAY_INCREMENT == 0)) + { + // Backpressure passes at 2*delay, so add another increment number of ticks to get to the first fail instance + acceptable_receive_delay = 2*delay + 10; + acceptable_send_delay = 0; + } + else + { + printf("ERROR: Unsupported receive (%d) and send (%d) delay increment combination\n", RECEIVE_DELAY_INCREMENT, SEND_DELAY_INCREMENT); + _Exit(1); + } +} + /* Ports and clocks used by the application */ port_t p_lrclk = XS1_PORT_1G; port_t p_bclk = XS1_PORT_1H; @@ -54,8 +175,9 @@ port_t p_din [4] = {XS1_PORT_1I, XS1_PORT_1J, XS1_PORT_1K, XS1_PORT_1L}; xclock_t mclk = XS1_CLKBLK_1; xclock_t bclk = XS1_CLKBLK_2; -static volatile int receive_delay = 5000; +static volatile int receive_delay = 0; static volatile int send_delay = 0; +static volatile int32_t receive_data_store[8]; void i2s_init(void *app_data, i2s_config_t *i2s_config) { @@ -75,6 +197,9 @@ void i2s_send(void *app_data, size_t n, int32_t *send_data) void i2s_receive(void *app_data, size_t n, int32_t *receive_data) { + for (size_t c = 0; c < n; c++) { + receive_data_store[c] = receive_data[c]; + } if (receive_delay) { delay_ticks(receive_delay); } @@ -85,11 +210,6 @@ i2s_restart_t i2s_restart_check(void *app_data) return I2S_NO_RESTART; } -#if DATA_BITS == 32 -#define OVERHEAD_TICKS 185 // Some of the period needs to be allowed for the callbacks -#else -#define OVERHEAD_TICKS 185 // Non-32b data widths take longer to process -#endif #define JITTER 1 //Allow for rounding so does not break when diff = period + 1 #define N_CYCLES_AT_DELAY 1 //How many LR clock cycles to measure at each backpressure delay value #define DIFF_WRAP_16(new, old) (new > old ? new - old : new + 0x10000 - old) @@ -121,28 +241,40 @@ void test_lr_period() { port_set_trigger_in_equal(p_lr_test, 0); (void) port_in(p_lr_test); counter++; - if (counter == N_CYCLES_AT_DELAY) { - receive_delay += RECEIVE_DELAY_INCREMENT; - send_delay += SEND_DELAY_INCREMENT; - if ((receive_delay + send_delay) > (period - OVERHEAD_TICKS)) { - printf("PASS\n"); - _Exit(0); - } - counter = 0; - } + port_set_trigger_in_equal(p_lr_test, 1); (void) port_in(p_lr_test); time = port_get_trigger_time(p_lr_test); int diff = DIFF_WRAP_16(time, time_old); if (diff > (period + JITTER)) { - printf("Backpressure breaks at receive delay ticks=%d, send delay ticks=%d\n", - receive_delay, send_delay); - printf("actual diff: %d, maximum (period + Jitter): %d\n", - diff, (period + JITTER)); - _Exit(1); + // The delay we're able to add in the i2s_receive() function should be acceptable_receive_delay ticks or more + if(receive_delay < acceptable_receive_delay) + { + printf("Backpressure breaks at receive delay ticks = %d, acceptable receive delay = %d\n", + receive_delay, acceptable_receive_delay); + printf("actual diff: %d, maximum (period + Jitter): %d\n", diff, (period + JITTER)); + _Exit(1); + } + + // The delay we're able to add in the i2s_send() function should be acceptable_send_delay ticks or more + if(send_delay < acceptable_send_delay) + { + printf("Backpressure breaks at send delay ticks = %d, acceptable send delay = %d\n", + send_delay, acceptable_send_delay); + printf("actual diff: %d, maximum (period + Jitter): %d\n", diff, (period + JITTER)); + _Exit(1); + } + printf("PASS\n"); + _Exit(0); + } + + if (counter == N_CYCLES_AT_DELAY) { + receive_delay += RECEIVE_DELAY_INCREMENT; + send_delay += SEND_DELAY_INCREMENT; + counter = 0; } - time_old = time; + time_old = time; } } @@ -153,6 +285,9 @@ void burn(void) { } int main() { + populate_acceptable_delay_ticks(); + get_acceptable_delay(); + i2s_callback_group_t i_i2s = { .init = (i2s_init_t) i2s_init, .restart_check = (i2s_restart_check_t) i2s_restart_check, diff --git a/test/lib_i2s/test_backpressure.py b/test/lib_i2s/test_backpressure.py index 020da02..e31ceab 100644 --- a/test/lib_i2s/test_backpressure.py +++ b/test/lib_i2s/test_backpressure.py @@ -5,7 +5,7 @@ import subprocess from pathlib import Path -sample_rate_args = {"768kbps": 768000, "384kbps": 384000, "192kbps": 192000} +sample_rate_args = {"384kbps": 384000, "192kbps": 192000} num_channels_args = {"1ch": 1, "2ch": 2, "3ch": 3, "4ch": 4} @@ -17,7 +17,12 @@ bitdepth_args = {"16b": 16, "32b": 32} +# 384000 has a non-zero backpressure only upto 2 channels +def uncollect_if(bitdepth, sample_rate, num_channels, receive_increment, send_increment): + if sample_rate == 384000 and num_channels > 2: + return True +@pytest.mark.uncollect_if(func=uncollect_if) @pytest.mark.parametrize("bitdepth", bitdepth_args.values(), ids=bitdepth_args.keys()) @pytest.mark.parametrize( "sample_rate", sample_rate_args.values(), ids=sample_rate_args.keys() @@ -41,9 +46,6 @@ def test_i2s_backpressure( send_increment, bitdepth, ): - if (num_channels != 4) and not nightly: - pytest.skip("Only run 4 channel tests unless it is a nightly") - id_string = ( f"{bitdepth}_{sample_rate}_{num_channels}_{receive_increment}_{send_increment}" ) diff --git a/tools/ci/helper_functions.sh b/tools/ci/helper_functions.sh index c07c11b..34ecc6d 100644 --- a/tools/ci/helper_functions.sh +++ b/tools/ci/helper_functions.sh @@ -5,11 +5,11 @@ # A small utility to run a command and only print logs if the command fails. # On success, all logs are hidden. -function log_errors { +log_errors() { if log=$("$@" 2>&1); then echo "'$@' completed successfully!" else echo "$log" return 1 - fi -} \ No newline at end of file + fi +}