mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[CI, Android] (Disaggregated): run full inproc trace acceptance beside monolith controls
This commit is contained in:
+64
-16
@@ -44,6 +44,9 @@ jobs:
|
||||
distribution: zulu
|
||||
java-version: '17'
|
||||
|
||||
- name: Android replay lifecycle regression
|
||||
run: python3 tools/trace_replay/test_android_lifecycle.py
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v6
|
||||
with:
|
||||
@@ -275,6 +278,8 @@ jobs:
|
||||
name: trace case matrix
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
env:
|
||||
MOBILEGL_CI_DISAGGREGATED: ${{ (github.ref_name == 'feat/disaggregated' || github.ref_name == 'codex/fix-github-ci') && 'ON' || 'OFF' }}
|
||||
outputs:
|
||||
android: ${{ steps.trace-cases.outputs.android }}
|
||||
names: ${{ steps.trace-cases.outputs.names }}
|
||||
@@ -285,7 +290,12 @@ jobs:
|
||||
- name: Load trace cases
|
||||
id: trace-cases
|
||||
run: |
|
||||
echo "android=$(python3 tools/trace_replay/trace_cases.py --ci --format github-apk-matrix)" >> "$GITHUB_OUTPUT"
|
||||
python3 tools/trace_replay/trace_cases.py --self-test-transport-matrices
|
||||
matrix_format=github-apk-matrix
|
||||
if [ "${MOBILEGL_CI_DISAGGREGATED}" = "ON" ]; then
|
||||
matrix_format=github-apk-transport-matrix
|
||||
fi
|
||||
echo "android=$(python3 tools/trace_replay/trace_cases.py --ci --format "${matrix_format}")" >> "$GITHUB_OUTPUT"
|
||||
echo "names=$(python3 tools/trace_replay/trace_cases.py --ci --format names)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
trace-fixtures:
|
||||
@@ -398,7 +408,7 @@ jobs:
|
||||
--avd-name "${AVD_NAME}"
|
||||
|
||||
retrace:
|
||||
name: retrace (${{ matrix.backend.name }}, ${{ matrix.case.name }})
|
||||
name: retrace (${{ matrix.backend.name }} / ${{ matrix.lane || 'monolith-control' }} / ${{ matrix.transport || 'monolith' }}, ${{ matrix.case.name }})
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
@@ -408,7 +418,8 @@ jobs:
|
||||
if: ${{ always() && needs.build.result == 'success' && needs.android-avd.result == 'success' && needs.trace-cases.result == 'success' }}
|
||||
timeout-minutes: 75
|
||||
env:
|
||||
MOBILEGL_CI_DISAGGREGATED: ${{ (github.ref_name == 'feat/disaggregated' || github.ref_name == 'codex/fix-github-ci') && 'ON' || 'OFF' }}
|
||||
MOBILEGL_CI_TRANSPORT: ${{ matrix.transport || 'monolith' }}
|
||||
MOBILEGL_CI_LANE: ${{ matrix.lane || 'monolith-control' }}
|
||||
AVD_NAME: mobilegl-ci
|
||||
ANDROID_AVD_HOME: ${{ github.workspace }}/.android/avd
|
||||
ANDROID_HOME: ${{ github.workspace }}/.android/sdk
|
||||
@@ -508,11 +519,13 @@ jobs:
|
||||
apk_file="android-retrace-apks/MobileGL-plugin-trace-release-${GITHUB_SHA}.apk"
|
||||
test -f "${apk_file}"
|
||||
extra_retrace_args=()
|
||||
if [ "${MOBILEGL_CI_DISAGGREGATED}" = "ON" ]; then
|
||||
if [ "${MOBILEGL_CI_TRANSPORT}" = "inproc" ]; then
|
||||
extra_retrace_args+=(
|
||||
--env "MOBILEGL_TRANSPORT=inproc;MOBILEGL_IPC_ROLE_SPLIT_STATE=1;MOBILEGL_IPC_STRICT_ERRORS=1;MOBILEGL_IPC_RUN_AHEAD=1"
|
||||
--require-inproc
|
||||
)
|
||||
else
|
||||
extra_retrace_args+=(--env "MOBILEGL_TRANSPORT=monolith")
|
||||
fi
|
||||
# Bliss needs the newer signed ANGLE variant plus sampler mipmap
|
||||
# min-filter downgrading on ANGLE llvmpipe.
|
||||
@@ -595,6 +608,12 @@ jobs:
|
||||
safe_case="$(printf '%s' '${{ matrix.case.name }}' | sed 's/[^A-Za-z0-9._-]/_/g')"
|
||||
result_dir="android-retrace-result/${safe_case}-${{ matrix.backend.name }}"
|
||||
mkdir -p "${result_dir}"
|
||||
python3 - "${result_dir}/lane.json" <<'PY'
|
||||
import json, os, sys
|
||||
from pathlib import Path
|
||||
Path(sys.argv[1]).write_text(json.dumps({"lane": os.environ["MOBILEGL_CI_LANE"],
|
||||
"transport": os.environ["MOBILEGL_CI_TRANSPORT"]}, indent=2))
|
||||
PY
|
||||
if [ -s "${{ matrix.case.golden }}" ]; then
|
||||
cp "${{ matrix.case.golden }}" "${result_dir}/${safe_case}-${{ matrix.backend.name }}-golden.png"
|
||||
fi
|
||||
@@ -631,7 +650,7 @@ jobs:
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: MobileGL-android-retrace-result-${{ env.date_today }}-${{ github.sha }}-${{ matrix.backend.name }}-${{ matrix.case.name }}
|
||||
name: MobileGL-android-retrace-result-${{ matrix.lane || 'monolith-control' }}-${{ matrix.transport || 'monolith' }}-${{ env.date_today }}-${{ github.sha }}-${{ matrix.backend.name }}-${{ matrix.case.name }}
|
||||
path: android-retrace-result/**
|
||||
if-no-files-found: warn
|
||||
|
||||
@@ -640,6 +659,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: retrace
|
||||
if: always()
|
||||
env:
|
||||
MOBILEGL_CI_DISAGGREGATED: ${{ (github.ref_name == 'feat/disaggregated' || github.ref_name == 'codex/fix-github-ci') && 'ON' || 'OFF' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
@@ -654,25 +675,52 @@ jobs:
|
||||
with:
|
||||
node-version: '22'
|
||||
|
||||
- name: Download Android retrace results
|
||||
- name: Download Android monolith control results
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: MobileGL-android-retrace-result-*
|
||||
path: retrace-artifacts
|
||||
pattern: MobileGL-android-retrace-result-monolith-control-monolith-*
|
||||
path: retrace-artifacts/monolith-control
|
||||
|
||||
- name: Render retrace summary
|
||||
- name: Download Android inproc acceptance results
|
||||
if: env.MOBILEGL_CI_DISAGGREGATED == 'ON'
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: MobileGL-android-retrace-result-inproc-acceptance-inproc-*
|
||||
path: retrace-artifacts/inproc-acceptance
|
||||
|
||||
- name: Render monolith control summary
|
||||
run: |
|
||||
node tools/trace_replay/render_retrace_summary.mjs \
|
||||
--input retrace-artifacts \
|
||||
--output-dir android-retrace-summary \
|
||||
--title "MobileGL Android retrace overview" \
|
||||
--group-label "Android Emulator" \
|
||||
--html mobilegl-android-retrace-overview.html
|
||||
--input retrace-artifacts/monolith-control \
|
||||
--output-dir android-retrace-summary/monolith-control \
|
||||
--title "MobileGL Android monolith control" \
|
||||
--group-label "Android Emulator / monolith control" \
|
||||
--html mobilegl-android-monolith-control.html
|
||||
|
||||
- name: Upload Android retrace summary
|
||||
- name: Render inproc acceptance summary
|
||||
if: env.MOBILEGL_CI_DISAGGREGATED == 'ON'
|
||||
run: |
|
||||
node tools/trace_replay/render_retrace_summary.mjs \
|
||||
--input retrace-artifacts/inproc-acceptance \
|
||||
--output-dir android-retrace-summary/inproc-acceptance \
|
||||
--title "MobileGL Android inproc acceptance" \
|
||||
--group-label "Android Emulator / inproc acceptance" \
|
||||
--html mobilegl-android-inproc-acceptance.html
|
||||
|
||||
- name: Upload Android monolith control summary
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
path: android-retrace-summary/mobilegl-android-retrace-overview.html
|
||||
name: MobileGL-android-monolith-control-summary-${{ github.sha }}
|
||||
path: android-retrace-summary/monolith-control/mobilegl-android-monolith-control.html
|
||||
archive: false
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload Android inproc acceptance summary
|
||||
if: env.MOBILEGL_CI_DISAGGREGATED == 'ON'
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: MobileGL-android-inproc-acceptance-summary-${{ github.sha }}
|
||||
path: android-retrace-summary/inproc-acceptance/mobilegl-android-inproc-acceptance.html
|
||||
archive: false
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
@@ -5,6 +5,14 @@ def mobileGlLogActiveLevel = {
|
||||
}
|
||||
def standalonePluginBuild = rootProject.name == 'MobileGLPlugin'
|
||||
|
||||
// Match the standalone app's declared ABI set. The library module otherwise
|
||||
// configures unrelated NDK ABIs even when the app only packages these two.
|
||||
// Embedded FCL builds retain their own ABI policy.
|
||||
def mobileGlAbiFilters = {
|
||||
def value = (rootProject.findProperty('mobilegl.abis') ?: System.getenv('MOBILEGL_ABIS') ?: 'arm64-v8a') as String
|
||||
value.equalsIgnoreCase('all') ? ['arm64-v8a', 'x86_64'] : value.split(',').collect { it.trim() }.findAll { it }
|
||||
}
|
||||
|
||||
// P0 spike A opt-in. OFF by default: the spike binary is dead weight in every trace APK
|
||||
// that is not running the spike, and a flavour that silently carries an extra executable
|
||||
// is exactly the kind of thing nobody notices until it ships. Turn it on for the spike
|
||||
@@ -34,6 +42,12 @@ android {
|
||||
defaultConfig {
|
||||
minSdk 26
|
||||
|
||||
if (standalonePluginBuild) {
|
||||
ndk {
|
||||
abiFilters.addAll(mobileGlAbiFilters())
|
||||
}
|
||||
}
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
externalNativeBuild {
|
||||
|
||||
@@ -217,6 +217,58 @@ def github_apk_matrix(cases):
|
||||
}
|
||||
|
||||
|
||||
def github_transport_matrix(cases, *, apk=False):
|
||||
"""Run the entire original matrix as both control and inproc acceptance.
|
||||
|
||||
The two transports use the same D/P artifact and each case's existing backend
|
||||
list. The legacy split:true subset does not limit this main acceptance matrix.
|
||||
Nested APK case/backend metadata is deliberately left untouched.
|
||||
"""
|
||||
build = github_apk_matrix if apk else github_test_matrix
|
||||
if not cases:
|
||||
raise ValueError("transport matrix needs at least one trace case")
|
||||
return {"include": [
|
||||
{**row, "lane": lane, "transport": transport}
|
||||
for selected, lane, transport in (
|
||||
(cases, "monolith-control", "monolith"),
|
||||
(cases, "inproc-acceptance", "inproc"),
|
||||
)
|
||||
for row in build(selected)["include"]
|
||||
]}
|
||||
|
||||
|
||||
def self_test_transport_matrices():
|
||||
cases = ci_trace_cases(load_trace_cases())
|
||||
for apk in (False, True):
|
||||
build = github_apk_matrix if apk else github_test_matrix
|
||||
original = build(cases)["include"]
|
||||
mixed = github_transport_matrix(cases, apk=apk)["include"]
|
||||
controls = [row for row in mixed if row["transport"] == "monolith"]
|
||||
acceptance = [row for row in mixed if row["transport"] == "inproc"]
|
||||
strip_lane = lambda rows: [{key: value for key, value in row.items()
|
||||
if key not in ("lane", "transport")} for row in rows]
|
||||
assert strip_lane(controls) == original, "control lost original case/backend/parameters"
|
||||
assert strip_lane(acceptance) == original, "acceptance lost original case/backend/parameters"
|
||||
assert all(row["lane"] == "monolith-control" for row in controls)
|
||||
assert all(row["lane"] == "inproc-acceptance" for row in acceptance)
|
||||
identities = [(row["case"]["name"] if apk else row["case"],
|
||||
row["backend"]["name"] if apk else row["backend"], row["transport"])
|
||||
for row in mixed]
|
||||
assert len(identities) == len(set(identities)), "duplicate lane identity"
|
||||
# A restricted case keeps exactly its original backend and golden data.
|
||||
restricted = [{**cases[0], "split": False, "ci_backends": ["DirectGLES"]}]
|
||||
rows = github_transport_matrix(restricted, apk=apk)["include"]
|
||||
assert len(rows) == 2 and strip_lane(rows[:1]) == strip_lane(rows[1:])
|
||||
try:
|
||||
github_transport_matrix([], apk=apk)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("an empty acceptance lane silently passed")
|
||||
print(f"transport matrix {'APK' if apk else 'Linux'}: {len(controls)} unchanged controls, "
|
||||
f"{len(acceptance)} full acceptance entries; exact metadata and negative controls OK")
|
||||
|
||||
|
||||
def cmake_quote(value):
|
||||
return '"' + str(value).replace("\\", "/").replace('"', '\\"') + '"'
|
||||
|
||||
@@ -265,16 +317,19 @@ def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--case", dest="case_name", help="Trace case name.")
|
||||
parser.add_argument("--ci", action="store_true", help="Only include cases enabled for CI.")
|
||||
parser.add_argument("--self-test-transport-matrices", action="store_true")
|
||||
parser.add_argument("--fixture-root", default="tools/trace_replay/fixtures")
|
||||
parser.add_argument(
|
||||
"--format",
|
||||
choices=(
|
||||
"names",
|
||||
"github-test-matrix",
|
||||
"github-test-transport-matrix",
|
||||
"github-verify-matrix",
|
||||
"github-split-matrix",
|
||||
"github-apk",
|
||||
"github-apk-matrix",
|
||||
"github-apk-transport-matrix",
|
||||
"fixture-files",
|
||||
"cmake",
|
||||
),
|
||||
@@ -285,6 +340,9 @@ def parse_args():
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
if args.self_test_transport_matrices:
|
||||
self_test_transport_matrices()
|
||||
return 0
|
||||
cases = load_trace_cases()
|
||||
if args.ci:
|
||||
cases = ci_trace_cases(cases)
|
||||
@@ -292,6 +350,8 @@ def main():
|
||||
print(json.dumps([case["name"] for case in cases], separators=(",", ":")))
|
||||
elif args.format == "github-test-matrix":
|
||||
print(json.dumps(github_test_matrix(cases), separators=(",", ":")))
|
||||
elif args.format == "github-test-transport-matrix":
|
||||
print(json.dumps(github_transport_matrix(cases), separators=(",", ":")))
|
||||
elif args.format == "github-verify-matrix":
|
||||
print(json.dumps(github_verify_matrix(cases), separators=(",", ":")))
|
||||
elif args.format == "github-split-matrix":
|
||||
@@ -300,6 +360,8 @@ def main():
|
||||
print(json.dumps([github_apk_case(case) for case in cases], separators=(",", ":")))
|
||||
elif args.format == "github-apk-matrix":
|
||||
print(json.dumps(github_apk_matrix(cases), separators=(",", ":")))
|
||||
elif args.format == "github-apk-transport-matrix":
|
||||
print(json.dumps(github_transport_matrix(cases, apk=True), separators=(",", ":")))
|
||||
elif args.format == "fixture-files":
|
||||
if not args.case_name:
|
||||
print("--case is required for --format fixture-files", file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user