Description: Parallelize suite_driver with xargs -P
 The vests suite is still sequential since it doesn't seem to go through
 suite_driver which is still limiting the speedup.
 .
 Retrieved from upstream git, where it was added after the 2.0 release.
Author: Daniel Gröber <dxld@darkboxed.org>
Origin: upstream, https://github.com/ghdl/ghdl/commit/8d9af3c5b52ba0ac814f2a5f4cda99ea306e813a
Last-Update: 2022-11-27
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
diff --git a/testsuite/suite_driver.sh b/testsuite/suite_driver.sh
index d3d7cf7c1..29c6e7d5f 100755
--- a/testsuite/suite_driver.sh
+++ b/testsuite/suite_driver.sh
@@ -9,31 +9,35 @@ ANSI_GREEN="\033[32m"
 ANSI_RED="\033[31m"
 ANSI_NOCOLOR="\033[0m"
 
-_suite="$1"
-shift
-
-# This is the only place where test dirs are specified.
-#Do not duplicate this line
-dirs="*[0-9]*"
-
-failures=""
-full=n
-
-for opt; do
-  case "$opt" in
-  -k | --keep-going)  full=y ;;
-  --dir=*) dirs="$(echo "$opt" | sed -e 's/--dir=//')" ;;
-  --skip=*) d="$(echo "$opt" | sed -e 's/--skip=//')"
-            dirs="$(echo "" "$dirs" | sed -e "s/ $d//")" ;;
-  --start-at=*) d="$(echo "$opt" | sed -e 's/--start-at=//')"
-            dirs="$(echo "" "$dirs" | sed -e "s/^.* $d//")"
-            dirs="$d $dirs" ;;
-  --list-tests) echo "$dirs"; exit 0;;
-  *) echo "Unknown option $opt"
-     exit 2
-     ;;
-  esac
-done
+parse_cmdline () {
+  _suite="$1"
+  shift
+
+  # This is the only place where test dirs are specified.
+  #Do not duplicate this line
+  dirs="*[0-9]*"
+
+  full=n
+
+  for opt; do
+    case "$opt" in
+    -k | --keep-going)  full=y ;;
+    -j*) NPROC=${opt#-j} ;;
+    --dir=*) dirs="$(echo "$opt" | sed -e 's/--dir=//')" ;;
+    --skip=*) d="$(echo "$opt" | sed -e 's/--skip=//')"
+              dirs="$(echo "" "$dirs" | sed -e "s/ $d//")" ;;
+    --start-at=*) d="$(echo "$opt" | sed -e 's/--start-at=//')"
+		  dirs="$(echo "" "$dirs" | sed -e "s/^.* $d//")"
+		  dirs="$d $dirs" ;;
+    --list-tests) echo "$dirs"; exit 0;;
+    *) echo "Unknown option $opt"
+       exit 2
+       ;;
+    esac
+  done
+
+  NPROC=${NPROC:-$(nproc || echo 1)}
+}
 
 singlerun() {
   cd "$1"
@@ -41,21 +45,49 @@ singlerun() {
     printf "$_suite $1: ${ANSI_GREEN}ok${ANSI_NOCOLOR}\n"
     # Don't disp log
   else
-    printf "$_suite $1: ${ANSI_RED}failed${ANSI_NOCOLOR}\n"
-    cat test.log
-    if [ x"$2" = x"y" ]; then
-      failures="$failures $1"
-    else
+    printf '%s ' "$1" >> ../failures.log
+    if [ x"$2" = x"n" ]; then
       exit 1;
     fi
   fi
   cd ..
 }
 
-for i in $dirs; do singlerun "$i" "$full"; done
+allrun () {
+  printf '' > failures.log
+
+  if command -v xargs >/dev/null 2>&1 && [ "$NPROC" != 1 ]; then
+    echo "..Running with $NPROC test workers.">&2
+    ndirs=$(printf '%s\n' $dirs | wc -l)
+    echo $dirs | DO_ALLRUN=0 xargs -P"$NPROC" -n$((1 + ndirs / NPROC)) sh -c \
+      's=$1; _suite=$2 full=$3; shift 3; . "$s";
+       for i in "$@"; do singlerun "$i" "$full" || true; done' \
+      \
+      sh "$0" "$_suite" "$full" || true
+  else
+    for i in $dirs; do singlerun "$i" "$full"; done
+  fi
 
-if [ x"$failures" = x"" ]; then
+  if [ ! -e failures.log ]; then
+    echo "error: Couldn't find test driver generated failures.log!">&2
+    exit 1
+  fi
+
+  failures="$(cat failures.log)"
+  if [ x"$failures" = x"" ]; then
     echo "$_suite tests are successful" && exit 0
-else
+  else
+    for failed in $failures; do
+      printf "$_suite $failed: ${ANSI_RED}failed${ANSI_NOCOLOR}\n"
+      cat "$failed"/test.log
+      printf '\n\n'
+    done
+
     echo "$_suite test failed ($failures)" && exit 1
+  fi
+}
+
+if [ "$DO_ALLRUN" != 0 ]; then
+  parse_cmdline "$@"
+  allrun
 fi
