Skip to content

Commit 4ca7c03

Browse files
test: benchmark long-lived sessions and inventory scale (Fixes #533) (#563)
Add deterministic session and scale workloads alongside the installed-manager performance benchmark, establishing evidence before concurrency and ownership changes. - Separate first-process/empty-cache, new-process/after-refresh, and same-process warm refresh measurements with full fixture identity assertions. - Prove real persisted-cache reuse separately: matching cold/disk-warm/same-process resolves with interpreter probe counts 1/0/0 and a nonempty owned cache. - Exercise inventory churn and barrier-proven concurrent resolves while configure, refresh, and info remain responsive, retaining the originally configured cache. - Record receipt-based latency, process-specific resource samples, subprocess counts, and honest cache-use measurements. - Add fast three-platform PR checks, weekly/manual stress runs, and validated privacy-safe artifacts with explicit failure status. - Validate request deadlines, graceful shutdown, and metrics integrity. Final follow-up Windows fast/stress and exact CI lint pass; native Linux cache control passed before the final cache-stability assertion. Hosted final-head Linux/macOS validation remains pending. Fixes #533 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7e8391d commit 4ca7c03

8 files changed

Lines changed: 2771 additions & 24 deletions

File tree

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: Session Benchmarks
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
- release*
8+
- release/*
9+
- release-*
10+
schedule:
11+
- cron: "23 7 * * 2"
12+
workflow_dispatch:
13+
inputs:
14+
mode:
15+
description: Workload size
16+
required: true
17+
default: stress
18+
type: choice
19+
options:
20+
- fast
21+
- stress
22+
23+
permissions:
24+
contents: read
25+
26+
jobs:
27+
session:
28+
name: ${{ github.event_name == 'pull_request' && 'Fast' || inputs.mode || 'Stress' }} (${{ matrix.os }})
29+
runs-on: ${{ matrix.os }}
30+
timeout-minutes: 45
31+
strategy:
32+
fail-fast: false
33+
matrix:
34+
os:
35+
- ubuntu-latest
36+
- windows-latest
37+
- macos-latest
38+
env:
39+
CARGO_TARGET_DIR: ${{ github.workspace }}/.target-session-benchmarks
40+
PET_SESSION_STRESS: ${{ (github.event_name == 'schedule' || inputs.mode == 'stress') && '1' || '' }}
41+
RUST_BACKTRACE: 1
42+
RUST_LOG: warn
43+
steps:
44+
- name: Checkout
45+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
46+
with:
47+
persist-credentials: false
48+
49+
- name: Set up Python fixture
50+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
51+
with:
52+
python-version: "3.12"
53+
54+
- name: Set up Rust
55+
uses: dtolnay/rust-toolchain@stable
56+
with:
57+
toolchain: stable
58+
59+
- name: Test session metrics parser
60+
run: python -B -m unittest scripts.tests.test_session_metrics -v
61+
62+
- name: Run session benchmark
63+
id: benchmark
64+
timeout-minutes: 35
65+
run: |
66+
mode=fast
67+
if [ "${PET_SESSION_STRESS}" = "1" ]; then
68+
mode=stress
69+
fi
70+
71+
set +e
72+
cargo test --release --features ci-perf -p pet --test session_performance long_lived_session_benchmark -- --nocapture 2>&1 | tee session-output.txt
73+
benchmark_status=${PIPESTATUS[0]}
74+
python -B scripts/session_metrics.py extract \
75+
--input session-output.txt \
76+
--output session-metrics.json \
77+
--benchmark-status "$benchmark_status" \
78+
--mode "$mode"
79+
metrics_status=$?
80+
set -e
81+
rm -f session-output.txt
82+
if [ "$benchmark_status" -ne 0 ]; then
83+
exit "$benchmark_status"
84+
fi
85+
exit "$metrics_status"
86+
shell: bash
87+
88+
- name: Ensure failure metrics
89+
if: always()
90+
run: |
91+
mode=fast
92+
if [ "${PET_SESSION_STRESS}" = "1" ]; then
93+
mode=stress
94+
fi
95+
python -B scripts/session_metrics.py ensure-failure \
96+
--output session-metrics.json \
97+
--mode "$mode" \
98+
--reason benchmark-timeout-or-interruption
99+
rm -f session-output.txt
100+
shell: bash
101+
102+
- name: Upload session metrics
103+
if: always()
104+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
105+
with:
106+
name: session-metrics-${{ matrix.os }}
107+
path: session-metrics.json
108+
if-no-files-found: error
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
import os
5+
from pathlib import Path
6+
import sys
7+
import time
8+
9+
10+
barrier = os.environ.get("PET_SESSION_RESOLVE_BARRIER")
11+
resolve_root = os.environ.get("PET_SESSION_RESOLVE_ROOT")
12+
if barrier and resolve_root:
13+
prefix = os.path.normcase(os.path.realpath(sys.prefix))
14+
root_prefix = os.path.normcase(os.path.realpath(resolve_root)) + os.sep
15+
if not prefix.startswith(root_prefix):
16+
barrier = None
17+
else:
18+
barrier = None
19+
20+
if barrier:
21+
root = Path(barrier)
22+
(root / f"entered-{os.getpid()}").write_text("entered", encoding="ascii")
23+
deadline = time.monotonic() + 20
24+
release = root / "release"
25+
while not release.exists():
26+
if time.monotonic() >= deadline:
27+
(root / f"failed-{os.getpid()}").write_text("timeout", encoding="ascii")
28+
os._exit(86)
29+
time.sleep(0.005)
30+
(root / f"released-{os.getpid()}").write_text("released", encoding="ascii")

0 commit comments

Comments
 (0)