Add compare_bootperf Script

Adds a script that compares the contents of two different cbmem files.
To be used by QA testers when generating bugs for bootperf failures.

BUG=b:452114019
TEST=./compare_bootperf.sh test_data/cbmem_slow test_data/cbmem_fast 1000

Change-Id: Ie1d631c8a24e5a3aaa5525666d0a38dab16522f4
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crostestutils/+/7068937
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
Tested-by: Sean Carpenter <seancarpenter@google.com>
Commit-Queue: Sean Carpenter <seancarpenter@google.com>
diff --git a/base_os_engprod/bash/compare_bootperf.sh b/base_os_engprod/bash/compare_bootperf.sh
new file mode 100755
index 0000000..65f15bb
--- /dev/null
+++ b/base_os_engprod/bash/compare_bootperf.sh
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+# Copyright 2025 The ChromiumOS Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script compares two "cbmem -t" output files and points out stages
+# during boot that differ by more than the passed in delta number of uSeconds,
+# A delta of 10000 is a good starting point
+
+# Check for the correct number of arguments
+if [ "$#" -lt 3 ]; then
+  echo "Usage: compare_bootperf.sh <input_file1> <input_file2> <max_delta>"
+  echo "  <input_file1>: Path to the first input file."
+  echo "  <input_file2>: Path to the second input file."
+  echo "  <max_delta>: The maximum absolute delta in microseconds"
+  echo "    between the boot times of the two files allowed before"
+  echo "    discrepency is logged."
+  echo ""
+  echo "Example: compare_bootperf.sh last_qual_cbmem_output.txt"
+  echo "    this_qual_cbmem_output.txt 10000"
+  echo "  This example command will display any stages between the two"
+  echo "  quals that differ by more than 10 miliseconds."
+  exit 1
+fi
+
+file1="$1"
+file2="$2"
+max_delta_threshold="$3"
+
+# Validate max_delta_threshold is a positive integer
+if ! [[ "${max_delta_threshold}" =~ ^[0-9]+$ ]] || \
+   [ "${max_delta_threshold}" -lt 0 ]; then
+  echo "Error: <max_delta> must be a non-negative integer."
+  exit 1
+fi
+
+# Check if both input files exist
+if [ ! -f "${file1}" ]; then
+  echo "Error: File '${file1}' not found."
+  exit 1
+fi
+
+if [ ! -f "${file2}" ]; then
+  echo "Error: File '${file2}' not found."
+  exit 1
+fi
+
+echo "Comparing bootperf from 'cbmem -t' output files:"
+echo "File 1: ${file1}"
+echo "File 2: ${file2}"
+echo "Filter for deltas >= ${max_delta_threshold} uS"
+echo "---------------------------------------------------"
+
+# Use grep to filter each file, ensuring only lines with timestamps are
+# read. This prevents the loop from getting out of sync if there are
+# differing header/footer lines.
+while IFS= read -r line1 <&3 && IFS= read -r line2 <&4; do
+  # First, check that we are comparing the same boot stages.
+  # Use sed to remove both timestamps from the end of the line for a more
+  # reliable comparison of the stage description.
+  stage1=$(echo "${line1}" | \
+    sed -E 's/ +[0-9,]+ +\([0-9,]+\) *$//')
+  stage2=$(echo "${line2}" | \
+    sed -E 's/ +[0-9,]+ +\([0-9,]+\) *$//')
+
+  echo_warning=0
+  if [ "${stage1}" != "${stage2}" ]; then
+    if ! echo "${stage1}" | grep "device enumeration" > /dev/null; then
+      echo "Error: Mismatched boot stages detected."
+      echo "Unable to compare ${file1} and ${file2}."
+      echo "Difference found at:"
+      echo "${file1}: ${line1}"
+      echo "${file2}: ${line2}"
+      exit 1
+    else
+      echo_warning=1
+    fi
+  fi
+
+  num1=""
+  num2=""
+
+  # Extract number from line1
+  if [[ ${line1} =~ \(([0-9,]+)\)[[:space:]]*$ ]]; then
+    num1=$(echo "${BASH_REMATCH[1]}" | tr -d ',')
+  fi
+
+  # Extract number from line2
+  if [[ ${line2} =~ \(([0-9,]+)\)[[:space:]]*$ ]]; then
+    num2=$(echo "${BASH_REMATCH[1]}" | tr -d ',')
+  fi
+
+  # Perform comparison if both numbers were found
+  if [[ -n "${num1}" ]] && [[ -n "${num2}" ]]; then
+    delta=$((num2 - num1))
+    absolute_delta=${delta#-}
+
+    # Check if the absolute delta meets the threshold
+    if (( absolute_delta >= max_delta_threshold )); then
+      if [ "${delta}" -eq "${absolute_delta}" ]; then
+        speedStr="SLOWER"
+      else
+        speedStr="FASTER"
+      fi
+
+      if [ "${echo_warning}" -eq 1 ]; then
+        echo "NOTE: The following stage strings are different:"
+      fi
+
+      echo "File 1: ${line1}"
+      echo "File 2: ${line2}"
+      echo "File 2 Delta : ${absolute_delta} uS ${speedStr}"
+      echo ""
+    fi
+  fi
+
+done 3< <(grep -E '\([0-9,]+\) *$' "${file1}") \
+     4< <(grep -E '\([0-9,]+\) *$' "${file2}")
diff --git a/base_os_engprod/bash/test_data/cbmem_fast b/base_os_engprod/bash/test_data/cbmem_fast
new file mode 100644
index 0000000..167e188
--- /dev/null
+++ b/base_os_engprod/bash/test_data/cbmem_fast
@@ -0,0 +1,7 @@
+  49 entries total:
+
+  0:1st timestamp                                     9,983 (0)
+  5:start of verified boot                            29,421 (19,438)
+503:starting to initialize TPM                        30,006 (584)
+
+Total Time: 30,006
\ No newline at end of file
diff --git a/base_os_engprod/bash/test_data/cbmem_missing b/base_os_engprod/bash/test_data/cbmem_missing
new file mode 100644
index 0000000..048e702
--- /dev/null
+++ b/base_os_engprod/bash/test_data/cbmem_missing
@@ -0,0 +1,5 @@
+  49 entries total:
+
+  5:some new stage                           29,421 (19,438)
+
+Total Time: 29,421
\ No newline at end of file
diff --git a/base_os_engprod/bash/test_data/cbmem_slow b/base_os_engprod/bash/test_data/cbmem_slow
new file mode 100644
index 0000000..18c331c
--- /dev/null
+++ b/base_os_engprod/bash/test_data/cbmem_slow
@@ -0,0 +1,7 @@
+  49 entries total:
+
+  0:1st timestamp                                     9,983 (0)
+  5:start of verified boot                            31,421 (21,438)
+503:starting to initialize TPM                        34,006 (2,584)
+
+Total Time: 34,006
\ No newline at end of file