#!/bin/bash
|
# Round01 performance gate. Runs the interactive-cost PoC metrics and the
|
# 100-cycle overlay lifecycle leak check as one QA entry point.
|
|
set -euo pipefail
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
OUTPUT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
# shellcheck source=build-output-paths.sh
|
source "$SCRIPT_DIR/build-output-paths.sh"
|
SOURCE_ROOT="$OUTPUT_ROOT/C1.source"
|
APP="$BUILD_CURRENT_APP"
|
POC_REPORT="$BUILD_REPORT_ROOT/round01-performance-poc-report.json"
|
LIFECYCLE_REPORT="$BUILD_REPORT_ROOT/round01-performance-lifecycle-report.json"
|
LIFECYCLE_CYCLES="${ALIGNER_ROUND1_POC_LIFECYCLE_CYCLES:-100}"
|
LIFECYCLE_INTERVAL="${ALIGNER_ROUND1_POC_LIFECYCLE_INTERVAL:-0.01}"
|
LIFECYCLE_VISIBLE_DURATION="${ALIGNER_ROUND1_POC_LIFECYCLE_VISIBLE_DURATION:-0.24}"
|
|
validate_positive_integer() {
|
local name="$1"
|
local value="$2"
|
if ! [[ "$value" =~ ^[1-9][0-9]*$ ]]; then
|
echo "$name must be a positive integer, got: $value" >&2
|
exit 1
|
fi
|
}
|
|
validate_nonnegative_number() {
|
local name="$1"
|
local value="$2"
|
if ! /usr/bin/python3 - "$name" "$value" <<'PY'
|
import sys
|
|
name, value = sys.argv[1:3]
|
try:
|
parsed = float(value)
|
except ValueError:
|
print(f"{name} must be a non-negative number, got: {value}", file=sys.stderr)
|
sys.exit(1)
|
|
if parsed < 0:
|
print(f"{name} must be a non-negative number, got: {value}", file=sys.stderr)
|
sys.exit(1)
|
PY
|
then
|
exit 1
|
fi
|
}
|
|
validate_positive_integer "ALIGNER_ROUND1_POC_LIFECYCLE_CYCLES" "$LIFECYCLE_CYCLES"
|
validate_nonnegative_number "ALIGNER_ROUND1_POC_LIFECYCLE_INTERVAL" "$LIFECYCLE_INTERVAL"
|
validate_nonnegative_number "ALIGNER_ROUND1_POC_LIFECYCLE_VISIBLE_DURATION" "$LIFECYCLE_VISIBLE_DURATION"
|
|
require_json_value() {
|
local report="$1"
|
local key="$2"
|
local expected="$3"
|
if ! /usr/bin/python3 - "$report" "$key" "$expected" <<'PY'
|
import json
|
import sys
|
|
path, key, expected = sys.argv[1:4]
|
with open(path, "r", encoding="utf-8") as handle:
|
data = json.load(handle)
|
|
actual = data.get(key)
|
if expected == "true":
|
ok = actual is True
|
elif expected == "false":
|
ok = actual is False
|
else:
|
ok = str(actual) == expected
|
|
if not ok:
|
print(f"{path}: {key}: expected {expected}, got {actual}", file=sys.stderr)
|
sys.exit(1)
|
PY
|
then
|
exit 1
|
fi
|
}
|
|
require_json_number_at_most() {
|
local report="$1"
|
local key="$2"
|
local maximum="$3"
|
if ! /usr/bin/python3 - "$report" "$key" "$maximum" <<'PY'
|
import json
|
import sys
|
|
path, key, maximum = sys.argv[1:4]
|
with open(path, "r", encoding="utf-8") as handle:
|
data = json.load(handle)
|
|
actual = data.get(key)
|
if actual is None or float(actual) > float(maximum):
|
print(f"{path}: {key}: expected <= {maximum}, got {actual}", file=sys.stderr)
|
sys.exit(1)
|
PY
|
then
|
exit 1
|
fi
|
}
|
|
"$SCRIPT_DIR/round1-performance-poc.sh" >&2
|
|
cd "$SOURCE_ROOT"
|
swift build >&2
|
"$SCRIPT_DIR/package-app.sh" >&2
|
|
rm -f "$LIFECYCLE_REPORT"
|
|
"$APP/Contents/MacOS/Aligner" \
|
--round0-skip-permissions \
|
--round01-performance-poc \
|
--round01-poc-lifecycle-cycles="$LIFECYCLE_CYCLES" \
|
--round01-poc-lifecycle-interval="$LIFECYCLE_INTERVAL" \
|
--round01-poc-lifecycle-visible-duration="$LIFECYCLE_VISIBLE_DURATION" \
|
--round01-poc-report="$LIFECYCLE_REPORT"
|
|
if [[ ! -f "$LIFECYCLE_REPORT" ]]; then
|
echo "Round01 performance lifecycle report was not created: $LIFECYCLE_REPORT" >&2
|
exit 1
|
fi
|
|
require_json_value "$LIFECYCLE_REPORT" lifecycleTargetCycles "$LIFECYCLE_CYCLES"
|
require_json_value "$LIFECYCLE_REPORT" lifecycleCompletedCycles "$LIFECYCLE_CYCLES"
|
require_json_value "$LIFECYCLE_REPORT" lifecycleGatePassed true
|
require_json_value "$LIFECYCLE_REPORT" firstFrameLatencySampleCount "$LIFECYCLE_CYCLES"
|
require_json_number_at_most "$LIFECYCLE_REPORT" firstFrameLatencyP95Milliseconds 150
|
require_json_number_at_most "$LIFECYCLE_REPORT" lifecycleMaximumOverlayWindows 1
|
require_json_value "$LIFECYCLE_REPORT" lifecycleResidualVisibleOverlayWindows 0
|
require_json_number_at_most "$LIFECYCLE_REPORT" lifecycleResidualOverlayWindows 1
|
require_json_number_at_most "$LIFECYCLE_REPORT" lifecycleMaximumVisibleOverlayWindows 1
|
require_json_value "$LIFECYCLE_REPORT" overlayVisible false
|
require_json_value "$LIFECYCLE_REPORT" visibleOverlayWindowCount 0
|
require_json_number_at_most "$LIFECYCLE_REPORT" overlayWindowCount 1
|
require_json_value "$LIFECYCLE_REPORT" cardLayerCount 200
|
require_json_value "$LIFECYCLE_REPORT" appLayerCount 20
|
require_json_value "$LIFECYCLE_REPORT" thumbnailLayerCount 200
|
require_json_value "$LIFECYCLE_REPORT" simulatedScreenshotRefillCount 200
|
|
cat <<EOF
|
{
|
"pocReport": "$POC_REPORT",
|
"lifecycleReport": "$LIFECYCLE_REPORT",
|
"lifecycleCycles": $LIFECYCLE_CYCLES
|
}
|
EOF
|