Repository navigation
160 lines (153 loc) · 7.33 KB
/
Copy pathperformance.yml
File metadata and controls
160 lines (153 loc) · 7.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
name: TimeSeries correctness and performance
on:
push:
branches: [main]
paths:
- 'ManagedCode.TimeSeries*/**'
- 'Directory.*.props'
- '.github/workflows/performance.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: timeseries-performance-${{ github.ref }}
cancel-in-progress: false
env:
DOTNET_VERSION: '10.0.401'
DOTNET_CLI_TELEMETRY_OPTOUT: '1'
DOTNET_NOLOGO: '1'
jobs:
correctness:
name: Full tests and coverage
runs-on: ubuntu-24.04
timeout-minutes: 25
steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Retain source and runtime
run: |
mkdir -p artifacts/correctness
git rev-parse HEAD > artifacts/correctness/source.txt
dotnet --info > artifacts/correctness/runtime.txt
- name: Restore
run: dotnet restore ManagedCode.TimeSeries.slnx
- name: Build with warnings as errors
run: dotnet build ManagedCode.TimeSeries.slnx --configuration Release --no-restore -warnaserror
- name: Verify formatter
run: dotnet format ManagedCode.TimeSeries.slnx --verify-no-changes --no-restore
- name: Full xUnit tests and native coverage
run: bash scripts/coverage.sh artifacts/correctness
- name: Retain exact-source test and coverage evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: timeseries-correctness-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/correctness/
if-no-files-found: error
retention-days: 30
ingestion:
name: Ingestion ${{ matrix.mode }} repetition ${{ matrix.repetition }}
runs-on: ubuntu-24.04
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
mode: [normal, scalar]
repetition: [1, 2]
env:
PERF_MODE: ${{ matrix.mode }}
PERF_REPETITION: ${{ matrix.repetition }}
DOTNET_EnableHWIntrinsic: ${{ matrix.mode == 'scalar' && '0' || '1' }}
steps:
- uses: actions/checkout@v5
- uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Retain source workload and hardware identity
shell: bash
run: |
mkdir -p artifacts/ingestion
dotnet --info > artifacts/ingestion/runtime.txt
lscpu --json > artifacts/ingestion/cpu.json
git rev-parse HEAD > artifacts/ingestion/source.txt
node <<'MANIFEST'
const fs = require('node:fs');
const crypto = require('node:crypto');
const files = [
'ManagedCode.TimeSeries.Benchmark/Benchmarks/TimeSeriesIngressSummerBenchmark.cs',
'ManagedCode.TimeSeries.Benchmark/Benchmarks/TimeSeriesIngressCapacityBenchmark.cs',
'ManagedCode.TimeSeries.Benchmark/Benchmarks/TimeSeriesIngressEvidence.cs',
];
const hashes = Object.fromEntries(files.map(file => [file,
crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex')]));
const manifest = {
schema: 1, repository: process.env.GITHUB_REPOSITORY,
sourceRevision: process.env.GITHUB_SHA, runId: process.env.GITHUB_RUN_ID,
runAttempt: process.env.GITHUB_RUN_ATTEMPT, mode: process.env.PERF_MODE,
repetition: Number(process.env.PERF_REPETITION),
enableHardwareIntrinsics: process.env.DOTNET_EnableHWIntrinsic,
seedUtc: '2025-01-01T00:00:00+00:00', intervalTicks: 10000000,
operationsPerInvoke: 64, capacities: [64, 4096],
numberTypes: ['Int32', 'Int64', 'Double', 'Decimal'],
expectedCaseCount: 16, launchCount: 2, warmupCount: 3, iterationCount: 10,
outliers: 'DontRemove', fixtureSha256: hashes,
};
fs.writeFileSync('artifacts/ingestion/manifest.json', JSON.stringify(manifest, null, 2) + '\n');
MANIFEST
- name: Restore
run: dotnet restore ManagedCode.TimeSeries.slnx
- name: Build with warnings as errors
run: dotnet build ManagedCode.TimeSeries.slnx --configuration Release --no-restore -warnaserror
- name: Verify formatter
run: dotnet format ManagedCode.TimeSeries.slnx --verify-no-changes --no-restore
- name: Measure real ingestion and allocations
shell: bash
run: |
set -euo pipefail
dotnet run --project ManagedCode.TimeSeries.Benchmark --configuration Release --no-build --no-restore -- \
--filter '*TimeSeriesIngress*' --join --job short \
--launchCount 2 --warmupCount 3 --iterationCount 10 --outliers DontRemove \
--exporters FullJSON CSV GitHub --artifacts artifacts/ingestion/bdn \
--stopOnFirstError 2>&1 | tee artifacts/ingestion/console.log
- name: Verify native measurement completeness
run: |
node <<'VERIFY'
const fs = require('node:fs');
const crypto = require('node:crypto');
const path = require('node:path');
const root = 'artifacts/ingestion/bdn/results';
const names = fs.readdirSync(root).filter(name => name.endsWith('-report-full.json'));
if (names.length !== 1) throw new Error('Expected one joined native full report.');
const bytes = fs.readFileSync(path.join(root, names[0]));
const report = JSON.parse(bytes);
if (!Array.isArray(report.Benchmarks) || report.Benchmarks.length !== 16)
throw new Error('The native ingestion report is incomplete.');
for (const row of report.Benchmarks) {
const actual = row.Measurements?.filter(item =>
item.IterationMode === 'Workload' && item.IterationStage === 'Actual');
if (!Number.isFinite(row.Statistics?.Mean) || row.Statistics.Mean <= 0 ||
!Number.isFinite(row.Memory?.BytesAllocatedPerOperation) ||
row.Memory.BytesAllocatedPerOperation < 0 || actual?.length !== 20)
throw new Error('A native ingestion case has missing timing or allocation evidence.');
}
const lines = fs.readFileSync('artifacts/ingestion/console.log', 'utf8').split('\n');
const evidence = lines.filter(line => line.startsWith('TIMESERIES_INGRESS_EVIDENCE '))
.map(line => JSON.parse(line.slice('TIMESERIES_INGRESS_EVIDENCE '.length)));
if (evidence.length < 32) throw new Error('Post-run ingestion evidence is missing.');
fs.writeFileSync('artifacts/ingestion/ingestion-checksums.json', JSON.stringify(evidence, null, 2) + '\n');
fs.writeFileSync('artifacts/ingestion/native-report-receipt.json', JSON.stringify({
sourceRevision: process.env.GITHUB_SHA, file: names[0], bytes: bytes.length,
sha256: crypto.createHash('sha256').update(bytes).digest('hex'),
measuredCases: report.Benchmarks.length, checksumRecords: evidence.length,
}, null, 2) + '\n');
VERIFY
- name: Retain native reports logs checksums and provenance
if: always()
uses: actions/upload-artifact@v4
with:
name: timeseries-ingestion-${{ matrix.mode }}-${{ matrix.repetition }}-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/ingestion/
if-no-files-found: error
retention-days: 30