After commit 5ef166838394 ("test: add file-prefix for all fast-tests on
Linux") each test within a suite has its own --file-prefix filled with
the test name to enable parallel execution. It brought a couple of
drawbacks though:
* Solution only applied to one test suite.
* Each working directory occupied ~25MB, with hundreds of tests this
  easily overfilled /run filesystems of small VMs. Currently executing
  fast-tests suite consumes 2.8GB of RAM, and adding more tests created
  problems for github CI.
* While it enabled parallel execution of tests within a single build
  directory, --file-prefix argument could no longer be specified
  externally (caused duplicate argument error). Specifying custom
  --file-prefix was necessary when multiple builds ran in the same
  environment, so the corresponding workflow became broken.

Move --file-prefix logic into a separate shell script, preserving
existing argument and cleaning the work directory after the test.
Apply it uniformly to all tests.

Signed-off-by: Marat Khalili <[email protected]>
---
 app/test/suites/meson.build                  | 34 ++++----
 app/test/suites/run_test_with_temp_prefix.sh | 82 ++++++++++++++++++++
 2 files changed, 102 insertions(+), 14 deletions(-)
 create mode 100755 app/test/suites/run_test_with_temp_prefix.sh

diff --git a/app/test/suites/meson.build b/app/test/suites/meson.build
index 786c459c24b3..3d75a8a66924 100644
--- a/app/test/suites/meson.build
+++ b/app/test/suites/meson.build
@@ -23,6 +23,16 @@ if not has_hugepage
     endif
 endif
 
+if is_linux
+    # use wrapper providing per-test work directories to allow parallel runs
+    test_args_prefix = [dpdk_test]
+    dpdk_test = find_program('run_test_with_temp_prefix.sh')
+    dpdk_test_as_arg = dpdk_test.full_path()
+else
+    test_args_prefix = []
+    dpdk_test_as_arg = dpdk_test
+endif
+
 # process source files to determine the different unit test suites
 # - fast_tests
 # - perf_tests
@@ -42,6 +52,7 @@ foreach suite:test_suites
                 warning('Test "@0@" is not defined in any test 
suite'.format(t))
             endif
             test(t, dpdk_test,
+                    args: test_args_prefix,
                     env: ['DPDK_TEST=' + t],
                     timeout: timeout_seconds,
                     is_parallel: false)
@@ -49,6 +60,7 @@ foreach suite:test_suites
     elif suite_name == 'stress-tests'
         foreach t: suite_tests
             test(t, dpdk_test,
+                    args: test_args_prefix,
                     env: ['DPDK_TEST=' + t],
                     timeout: timeout_seconds_stress,
                     is_parallel: false,
@@ -58,6 +70,7 @@ foreach suite:test_suites
         # simple cases - tests without parameters or special handling
         foreach t: suite_tests
             test(t, dpdk_test,
+                    args: test_args_prefix,
                     env: ['DPDK_TEST=' + t],
                     timeout: timeout_seconds,
                     is_parallel: false,
@@ -81,7 +94,7 @@ foreach suite:test_suites
             nohuge = params[1] == 'NOHUGE_OK'
             asan = params[2] == 'ASAN_OK'
 
-            test_args = []
+            test_args = test_args_prefix
             if nohuge
                 test_args += test_no_huge_args
             elif not has_hugepage
@@ -94,25 +107,17 @@ foreach suite:test_suites
                 test_args += ['-d', dpdk_drivers_build_dir]
             endif
 
-            # use unique file-prefix to allow parallel runs
-            file_prefix = []
-            trace_prefix = []
-            if is_linux
-                file_prefix = ['--file-prefix=' + test_name.underscorify()]
-                trace_prefix = [file_prefix[0] + '_with_traces']
-            endif
-
             test(test_name, dpdk_test,
-                args : test_args + file_prefix,
+                args: test_args,
                 env: ['DPDK_TEST=' + test_name],
                 timeout : timeout_seconds_fast,
                 is_parallel : false,
                 suite : 'fast-tests')
             if not is_windows and test_name == 'trace_autotest'
-                trace_extra = ['--trace=.*',
-                               
'--trace-dir=@0@'.format(meson.current_build_dir())]
+                test_args += ['--trace=.*']
+                test_args += 
['--trace-dir=@0@'.format(meson.current_build_dir())]
                 test(test_name + '_with_traces', dpdk_test,
-                    args : test_args + trace_extra + trace_prefix,
+                    args: test_args,
                     env: ['DPDK_TEST=' + test_name],
                     timeout : timeout_seconds_fast,
                     is_parallel : false,
@@ -124,7 +129,7 @@ endforeach
 
 # standalone test for telemetry
 if not is_windows and dpdk_conf.has('RTE_LIB_TELEMETRY')
-    test_args = [dpdk_test]
+    test_args = [dpdk_test_as_arg] + test_args_prefix
     test_args += test_no_huge_args
     if get_option('default_library') == 'shared'
         test_args += ['-d', dpdk_drivers_build_dir]
@@ -166,6 +171,7 @@ dump_test_names = [
 ]
 foreach arg : dump_test_names
     test(arg, dpdk_test,
+                args : test_args,
                 env : ['DPDK_TEST=' + arg],
                 timeout : timeout_seconds_fast,
                 is_parallel : false,
diff --git a/app/test/suites/run_test_with_temp_prefix.sh 
b/app/test/suites/run_test_with_temp_prefix.sh
new file mode 100755
index 000000000000..0c466ec25ea1
--- /dev/null
+++ b/app/test/suites/run_test_with_temp_prefix.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+# Run dpdk test with a temporary prefix and clean it up afterwards
+set -eEuo pipefail
+
+# Get value of the long option with name in the first argument, from the rest.
+get_arg_value() {
+       local arg_name="$1"
+       shift 1
+
+       local arg_value=''
+       local grab_next=false
+       local arg
+
+       for arg in "$@"; do
+               if $grab_next; then
+                       arg_value="$arg"
+                       grab_next=false
+               elif [[ "$arg" == "${arg_name}="* ]]; then
+                       arg_value="${arg#*=}"
+               elif [[ "$arg" == "$arg_name" ]]; then
+                       grab_next=true
+               fi
+       done
+
+       printf "%s\n" "$arg_value"
+}
+
+# Delete work directory passing through the return code
+delete_work_directory() {
+       local -r test_rc="$1"
+       [[ -z "${WORK_DIRECTORY:-}" ]] || rm -rf "$WORK_DIRECTORY"
+       return "$test_rc"
+}
+
+main() {
+       if [[ $# -eq 0 ]]; then
+               printf "Usage: %s <test_command> [arguments...]\n" "$0" >&2
+               printf "%s %s\n" \
+                       "Runs a DPDK test with a temporary file prefix" \
+                       "and cleans up the working directory." >&2
+               printf "Ensure the DPDK_TEST environment variable is set.\n" >&2
+               exit 1
+       fi
+       local test_command=("$@")
+
+       if [[ -z "${DPDK_TEST:-}" ]]; then
+               printf "Ensure the DPDK_TEST environment variable is set.\n" >&2
+               exit 1
+       fi
+       local -r dpdk_test="$DPDK_TEST"
+
+       # Make sure file prefix is determined and set in test args
+       local file_prefix="$(get_arg_value --file-prefix "${test_command[@]}")"
+       if [[ -z "$file_prefix" ]]; then
+               # If not yet specified, set --file-prefix to test name
+               file_prefix="$dpdk_test"
+               if [[ -n "$(get_arg_value --trace "${test_command[@]}")" ]]; 
then
+                       # Some tests runs twice, with and without traces
+                       file_prefix="${file_prefix}_with_traces"
+               fi
+               test_command+=("--file-prefix=$file_prefix")
+       fi
+
+       # Make sure runtime directory is determined and set in the environment
+       local runtime_directory="${RUNTIME_DIRECTORY:-}"
+       if [[ -z "$runtime_directory" ]]; then
+               # Follow the algorithm in eal_filesystem.c
+               if [[ "$EUID" -eq 0 ]]; then
+                   runtime_directory='/var/run'
+               else
+                   runtime_directory="${XDG_RUNTIME_DIR:-/tmp}"
+               fi
+               export RUNTIME_DIRECTORY="$runtime_directory"
+       fi
+
+       WORK_DIRECTORY="$runtime_directory/dpdk/$file_prefix"
+       trap 'delete_work_directory "$?"' EXIT
+
+       "${test_command[@]}"
+}
+
+main "$@"
-- 
2.43.0

Reply via email to