Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
084b99c
Add reproducible compiler-source performance measurements
invalid-email-address Sep 18, 2026
320639c
Validate compiler performance evidence before comparison
invalid-email-address Sep 18, 2026
c1a51e3
Reject incomplete and instrumented compiler performance evidence
invalid-email-address Sep 18, 2026
b318623
Bind performance collection to executing tools and reject diagnostic …
invalid-email-address Sep 18, 2026
1eb9c2c
Cover valid workload mismatches and compiler capture guards
invalid-email-address Sep 18, 2026
cb04809
Terminate compiler performance command descendants on cancellation
invalid-email-address Sep 18, 2026
ccac787
Add process-targeted compiler profiling evidence
invalid-email-address Sep 19, 2026
81c51ef
Enforce artifact-backed compiler profiling validation
invalid-email-address Sep 19, 2026
cd9f423
Fix dump profile artifact verification and cleanup exit race
invalid-email-address Sep 19, 2026
09ad68a
Preserve trace input when reduction output collides
invalid-email-address Sep 19, 2026
f3b8d8e
Contain profiling descendants and redact quoted credentials
invalid-email-address Sep 19, 2026
82931bc
Preserve profiling process identity and diagnostic flags
invalid-email-address Sep 19, 2026
370b4b3
Fix observed allocation counter subtotal in compiler profiling
invalid-email-address Sep 19, 2026
9cdc9cd
Add versioned compiler performance experiment memory
invalid-email-address Sep 19, 2026
8b45c07
Merge saved compiler profiling checkpoint for recovery
invalid-email-address Sep 19, 2026
9248216
Preserve owned Windows process trees across wrapper exit
invalid-email-address Sep 19, 2026
8015f0b
Add isolated compiler performance experiment controller
invalid-email-address Sep 19, 2026
d2e72c8
Repair independent compiler experiment acceptance and rollback
invalid-email-address Sep 19, 2026
27cdd38
Bound compiler experiment evidence and protect report capture
invalid-email-address Sep 19, 2026
a735da8
Cover omitted compiler experiment correctness requirements
invalid-email-address Sep 19, 2026
847a54c
Preserve frozen SDK mappings in compatibility experiments
invalid-email-address Sep 19, 2026
943346c
Preserve producer paths when loading experiment history
invalid-email-address Sep 19, 2026
1397d59
Cover pinned MTP experiment completion and report forgeries
invalid-email-address Sep 19, 2026
d1de7d5
Sanitize Git environment in pinned runner fixture bootstrap
invalid-email-address Sep 19, 2026
8f7cb92
Expose decoy-completion approval gap in pinned runner regression
invalid-email-address Sep 19, 2026
9bc93af
Document pinned runner attestation boundary
invalid-email-address Sep 19, 2026
bb82f34
Assert each experiment approval boundary independently
invalid-email-address Sep 19, 2026
848f250
Reconcile compiler perf checks with runner-reported results
invalid-email-address Sep 19, 2026
5f723ac
Preserve user work and bind experiment resume checkpoints
invalid-email-address Sep 20, 2026
e623ab6
Exercise rollback beside an approved unpublished candidate
invalid-email-address Sep 20, 2026
45405dc
Reject unbound checkpoints during no-finding completion
invalid-email-address Sep 20, 2026
129122d
Guard checkpoint entries and interrupted resume authentication
invalid-email-address Sep 20, 2026
2eee1f2
Restore interrupted compiler performance lifecycle integration
invalid-email-address Sep 20, 2026
31c4e4c
Repair lifecycle receipts and preserve restart publication state
invalid-email-address Sep 20, 2026
e60d1f0
Isolate lifecycle fixture Git setup from ambient configuration
invalid-email-address Sep 20, 2026
9abe8c1
Merge current main into the verified lifecycle checkpoint
invalid-email-address Sep 20, 2026
c591342
Record completed portable lifecycle verification and remaining replay…
invalid-email-address Sep 20, 2026
9e81ec7
Connect compiler profiling to bounded agent investigations
invalid-email-address Sep 20, 2026
b915376
Repair compiler investigation clocks, source export and legacy retries
invalid-email-address Sep 20, 2026
dd40865
Revalidate retained compiler profiling inputs and fix Windows artifac…
invalid-email-address Sep 22, 2026
744cec1
Restore artifact change detection across Windows timestamp APIs
invalid-email-address Sep 22, 2026
9a486d8
Retain bounded encrypted compiler profiling evidence
invalid-email-address Sep 22, 2026
70283bb
Preserve encrypted evidence across retention recovery
invalid-email-address Oct 20, 2026
25ca521
Keep owned dump custody through cleanup
invalid-email-address Oct 20, 2026
202c5f9
Connect protected profiling to the pinned GH AW runtime
invalid-email-address Oct 20, 2026
3139b2d
Repair protected runtime startup and finalization contracts
invalid-email-address Oct 20, 2026
a1dd3b2
Close protected runtime startup and unhealthy publication gaps
invalid-email-address Oct 20, 2026
51c5c22
Preserve runner identity across protected runtime launches
invalid-email-address Oct 20, 2026
6d3c802
Isolate trusted runtime configuration and close early-exit cleanup
invalid-email-address Oct 20, 2026
dcadcbb
Honor sealed deadlines while monitoring owned worker finalization
invalid-email-address Oct 21, 2026
900df74
Separate protected interpreter fixture paths from host temporary storage
invalid-email-address Oct 21, 2026
16fa5b5
Install weekly compiler self-profile workflow
invalid-email-address Oct 21, 2026
7a674cc
Fix profiler artifact retention clock and verify trusted adapter exec…
invalid-email-address Oct 21, 2026
6ce20fc
Fix Linux compiler profiler runtime boundaries
invalid-email-address Oct 21, 2026
7162212
Wait for owned Linux diagnostics startup
invalid-email-address Oct 21, 2026
07fdf8d
Stabilize live compiler profiler heap fixture
invalid-email-address Oct 21, 2026
aafedc9
Exercise protected publishing after isolated profiler fixtures
invalid-email-address Oct 21, 2026
0060071
Fix compiler profiler provisioning and shutdown recovery
invalid-email-address Oct 21, 2026
3cbc706
Cover profiler handoff ownership rejection
invalid-email-address Oct 22, 2026
ee12164
Add release notes
invalid-email-address Oct 22, 2026
a230f65
Merge main to unblock compiler profiler CI
invalid-email-address Oct 22, 2026
45ea51e
Address review feedback
invalid-email-address Oct 23, 2026
775e469
Merge remote-tracking branch 'origin/main' into idea/dm-910
Copilot Oct 23, 2026
b331137
Fix compiler profiler dump analysis on .NET 11
T-Gro Nov 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,107 changes: 1,107 additions & 0 deletions .github/workflows/compiler-self-profile.lock.yml

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions .github/workflows/compiler-self-profile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
---
name: Compiler Self Profile
description: Weekly controller-owned compiler-source profiling and independently gated draft optimization.

models:
gpt-5.6-sol: [copilot/gpt-5.6-sol, openai/gpt-5.6-sol]

engine:
id: copilot
model: ${{ (github.job == 'detection' && vars.GH_AW_MODEL_DETECTION_COPILOT) || vars.GH_AW_MODEL_AGENT_COPILOT || 'gpt-5.6-sol' }}
env:
GH_AW_REASONING_EFFORT: ${{ (github.job == 'detection' && vars.GH_AW_REASONING_EFFORT_DETECTION) || vars.GH_AW_REASONING_EFFORT || 'high' }}
COMPILER_PERF_EXECUTION_DEADLINE_MS: ${{ steps.controller.outputs.execution_deadline_ms }}
args: ["--reasoning-effort", "${{ env.GH_AW_REASONING_EFFORT }}", "--deny-tool", "shell", "--deny-tool", "safeoutputs", "--deny-tool", "write", "--deny-tool", "task"]
version: "1.0.52"
bare: true
harness: compiler_perf_harness.cjs
mcp:
tool-timeout: 5m

on:
schedule:
- cron: "17 3 * * 1"
workflow_dispatch:

if: github.repository == 'dotnet/fsharp' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name != 'workflow_dispatch' || inputs.aw_context == '')
concurrency:
group: compiler-self-profile
cancel-in-progress: false

runs-on: ubuntu-24.04
timeout-minutes: 250
permissions:
actions: read
contents: read
pull-requests: read
checkout: false

network:
allowed:
- defaults

tools:
github: false
bash: false
edit: false

# The pin injects an issue writer without a non-builtin output. Staging and a
# read-only token disable native effects; only sealed host output is published.
safe-outputs:
staged: true
github-token: ${{ secrets.GITHUB_TOKEN }}
threat-detection: false
report-failure-as-issue: false
noop:
report-as-issue: false
create-pull-request:
max: 1
draft: true
patch-format: am
fallback-as-issue: false
preserve-branch-name: true
missing-tool:
create-issue: false
missing-data:
create-issue: false

mcp-servers:
controller:
type: http
url: http://127.0.0.1:8765/mcp
headers:
Authorization: "Bearer ${{ steps.controller.outputs.token }}"
allowed: [investigate]

pre-steps:
- name: Provision protected controller and reserve canonical discovery
id: provision
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
GH_TOKEN: ${{ secrets.COMPILER_PERF_OWNER_TOKEN }}
COMPILER_PERF_OWNER_LOGIN: ${{ vars.COMPILER_PERF_OWNER_LOGIN }}
COMPILER_PERF_AGE_RECIPIENT: ${{ vars.COMPILER_PERF_AGE_RECIPIENT }}
with:
script: |
const {execFileSync} = require('node:child_process');
const fs = require('node:fs');
if (!process.env.GH_TOKEN) throw new Error('blocked_setup: COMPILER_PERF_OWNER_TOKEN is required');
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRunAttempt, {
...context.repo, run_id: context.runId, attempt_number: Number(process.env.GITHUB_RUN_ATTEMPT), per_page: 100
});
const owned = jobs.filter(j => j.name === process.env.GITHUB_JOB &&
j.runner_name === process.env.RUNNER_NAME && j.status === 'in_progress');
if (owned.length !== 1 || !owned[0].started_at) throw new Error('blocked_setup: actual job start unavailable');
const deadline = Date.parse(owned[0].started_at) + 3600000;
function run(file, args) {
const remaining = deadline - Date.now();
if (!(remaining > 0)) throw new Error('blocked_setup: setup admission deadline');
execFileSync(file, args, {stdio: 'inherit', timeout: remaining});
}
const root = `/var/lib/compiler-perf/${context.runId}-${process.env.GITHUB_RUN_ATTEMPT}`;
if (fs.existsSync(root)) throw new Error('blocked_setup: existing owner requires reconciliation');
run('/usr/bin/sudo', ['-n', '/usr/bin/install', '-d', '-m', '0700', '-o', String(process.getuid()), root]);
run('/usr/bin/git', ['clone', '--quiet', '--no-checkout', '--template=', 'https://github.com/dotnet/fsharp.git', `${root}/source`]);
run('/usr/bin/git', ['-C', `${root}/source`, 'checkout', '--quiet', '--detach', process.env.GITHUB_SHA]);
run('/usr/bin/python3', ['-I', `${root}/source/eng/scripts/compiler_perf/actions_adapter.py`,
'provision', '--base', root, '--job-started-at', owned[0].started_at]);

pre-agent-steps:
- name: Prepare frozen compiler inputs and start authenticated controller
id: controller
env:
GH_TOKEN: ${{ secrets.COMPILER_PERF_OWNER_TOKEN }}
run: |
set -eu
base="/var/lib/compiler-perf/$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
"$base/python/bin/python3" -I "$base/source/eng/scripts/compiler_perf/runtime.py" start-service --root "$base/controller" --repository "$base/source" --journal "$base/journal.git" --workspace "$GITHUB_WORKSPACE"

post-steps:
- name: Checkpoint, stop owned work and export sealed publisher inventory
id: handoff
if: always() && github.repository == 'dotnet/fsharp' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name != 'workflow_dispatch' || inputs.aw_context == '')
env:
GH_TOKEN: ${{ secrets.COMPILER_PERF_OWNER_TOKEN }}
PERF_ENGINE_OUTCOME: ${{ steps.agentic_execution.outcome }}
run: |
set -eu
base="/var/lib/compiler-perf/$GITHUB_RUN_ID-$GITHUB_RUN_ATTEMPT"
"$base/python/bin/python3" -I "$base/source/eng/scripts/compiler_perf/runtime.py" handoff --root "$base/controller" --repository "$base/source" --journal "$base/journal.git" --workspace "$GITHUB_WORKSPACE" --destination "$base/publisher" --engine-outcome "$PERF_ENGINE_OUTCOME"
- name: Acknowledge checked evidence and publish at most one sealed draft
id: publisher
if: always() && github.repository == 'dotnet/fsharp' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name != 'workflow_dispatch' || inputs.aw_context == '')
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
GH_TOKEN: ${{ secrets.COMPILER_PERF_OWNER_TOKEN }}
with:
script: |
const {spawnSync} = require('node:child_process');
const fs = require('node:fs');
const base = `/var/lib/compiler-perf/${context.runId}-${process.env.GITHUB_RUN_ATTEMPT}`;
if (!fs.existsSync(`${base}/controller/key`)) throw new Error('blocked_setup: no authenticated controller custody');
const result = spawnSync(`${base}/python/bin/python3`, ['-I',
`${base}/source/eng/scripts/compiler_perf/runtime.py`, 'finalize',
'--root', `${base}/controller`, '--repository', `${base}/source`,
'--journal', `${base}/journal.git`, '--workspace', process.env.GITHUB_WORKSPACE,
'--destination', `${base}/publisher`], {stdio: 'inherit', timeout: 2400000});
if (result.error || result.status !== 0) throw new Error('Finalization blocked; outstanding work preserved');
- name: Quarantine untrusted stock logs before stock artifact collection
id: quarantine
if: always() && github.repository == 'dotnet/fsharp' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) && (github.event_name != 'workflow_dispatch' || inputs.aw_context == '')
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
script: |
const {execFileSync} = require('node:child_process');
const fs = require('node:fs');
const base = `/var/lib/compiler-perf/${context.runId}-${process.env.GITHUB_RUN_ATTEMPT}`;
const source = '/tmp/gh-aw';
execFileSync('/usr/bin/sudo', ['-n', '/usr/bin/install', '-d', '-m', '0700', '-o', String(process.getuid()), base], {timeout: 60000});
if (fs.existsSync(source)) {
if (fs.lstatSync(source).isSymbolicLink() || !fs.lstatSync(source).isDirectory()) throw new Error('Unsafe stock log root');
const destination = `${base}/stock-logs`;
if (fs.existsSync(destination)) throw new Error('Existing stock quarantine preserved');
execFileSync('/usr/bin/sudo', ['-n', '/usr/bin/mv', '--', source, destination], {timeout: 60000});
}
fs.mkdirSync(source, {mode: 0o700});
// Native staged consumers receive no agent decision or patch.
fs.writeFileSync(`${source}/agent_output.json`, '{"items":[]}\n', {flag: 'wx', mode: 0o600});
core.info('quarantine: stock transport contains only the fixed empty envelope');
---

# Weekly compiler-source investigation

Use only `controller.investigate`, the authenticated data endpoint. Send JSON text
with exactly `schema_version: 1`, a unique `id`, `operation`, and `data`.
Begin with `status`, then `start_profile` (`data: {}`); poll `status` while the
owned worker runs. All waits, revisions and workers share the controller's full
240-minute active allowance, starting at authenticated readiness, not tool dispatch.
Do not run shell commands, delegate an optimizer or use GitHub writers.

Develop insights from CPU stacks, sampled allocations, GC/heap/RSS distinctions
and compiler binlog timings. This is the pinned Release compiler-source workload,
not FSharp.Core or generated-code runtime benchmarks. Keep `global.json` intact.
Consult retained hypotheses, negative results and explicit retry dependencies.
Do not repeat an unchanged rejected scope or claim missing/expired evidence exists.

Select one observed hot operation using `select_hypothesis`: `compiler_paths`,
`regressions` (`path` and exact `method`), `hypothesis`, `complexity`, and the
displayed integer `hot_operation`. Explain the smallest focused compiler change.
Submit bounded UTF-8 Git diff bytes with `submit_patch` (`data: {patch: ...}`),
then `start_validation` (`data: {}`). The host applies the patch, checks actual
paths/modes/tree, runs its required regression/area/compatibility plan, and obtains
fresh independent unprofiled A/A and A/B measurements. Neither a passing timing
nor your own assertion authorizes publication.

For a specific retention/heap-growth/unexplained-RSS hypothesis, `request_dump`
accepts only `reason` and `hypothesis`. Interpret the returned bounded evidence.
Use `finish_rejected` for a tested negative/inconclusive result, `finish_no_finding`
only for completed untested discovery, or `cancel` for incomplete work; each takes
`data: {reason: ...}`. Preserve a short measured conclusion or material blocker.
The host alone retains canonical memory, acknowledges encrypted Actions evidence,
and may publish one independently approved draft using a sealed `am` patch.
Do not create issues, comments, alternate branches or output files, request
ready-for-review, approve, merge, or change tools, policy, SDK or permissions.
2 changes: 2 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/11.0.200.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### Added

* Add a read-only repository review agent for performance-improvement PRs to assess measurement quality, behavior preservation, and implementation risk using source-attributed review precedents. ([PR #20619](https://github.com/dotnet/fsharp/pull/20619))
* Add weekly compiler-source self-profiling with reproducible performance experiments and independently validated draft optimization PRs. ([PR #20842](https://github.com/dotnet/fsharp/pull/20842))
* Completion: respect EditorBrowsableAttribute ([PR #20729](https://github.com/dotnet/fsharp/pull/20729))
* Runtime-async sequences allow awaits inside `try/with` bodies, filters and handlers, and reject overlapping `MoveNextAsync` calls. ([PR #20655](https://github.com/dotnet/fsharp/pull/20655))
* F# Interactive gains a JSON-RPC server mode, `--fsi-server-jsonrpc:<pipe name>`, in which a host submits interactions over a named pipe and receives structured results — diagnostics with positions, escaping exceptions, the values each interaction bound, and the session's own process id — instead of recovering them by looking for a `SERVER-PROMPT>` marker in the output text. Program output continues to flow through the redirected console streams. The pipe admits only the user running the session; `--fsi-server-client-pid:<pid>` names the host process whose exit ends the session. `FsiEvaluationSession` exposes both options as `JsonRpcServerPipeName` and `JsonRpcClientProcessId`. The mode is part of the .NET fsi only. ([PR #20396](https://github.com/dotnet/fsharp/pull/20396))
Expand All @@ -12,6 +13,7 @@
* Capture diagnostics emitted when transparent project checking finishes a project, including FS0247 for namespace-module name collisions. ([Issue #6036](https://github.com/dotnet/fsharp/issues/6036), [PR #20706](https://github.com/dotnet/fsharp/pull/20706))
* Fix false IDE type-mismatch diagnostics for interpolated strings with multiple formatted holes. ([Issue #20752](https://github.com/dotnet/fsharp/issues/20752), [PR #20775](https://github.com/dotnet/fsharp/pull/20775))
* Checker: report Bind resolution failures at the bound expression ([PR #20747](https://github.com/dotnet/fsharp/pull/20747))
* Fix compiler self-profiling service startup racing endpoint-key creation, and keep command supervision responsive while a child delays reading stdin. ([PR #20842](https://github.com/dotnet/fsharp/pull/20842))
* A project reusing cached framework imports is checked with its own `--pathmap` instead of the map of the project that filled the cache, so the ranges of its in-memory reference data name its real files. ([Issue #20474](https://github.com/dotnet/fsharp/issues/20474), [PR #20476](https://github.com/dotnet/fsharp/pull/20476))
* Split Linux CoreCLR CI into two parallel test batches to reduce test turnaround time. ([PR #20587](https://github.com/dotnet/fsharp/pull/20587))
* Fix wrong results or non-terminating loops in optimized code when an integer `for` loop's start or end expression binds a local. ([Issue #20732](https://github.com/dotnet/fsharp/issues/20732), [PR #20733](https://github.com/dotnet/fsharp/pull/20733))
Expand Down
13 changes: 13 additions & 0 deletions eng/scripts/compiler_perf/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-dump": {
"version": "10.0.750501",
"commands": [
"dotnet-dump"
],
"rollForward": true
}
}
}
1 change: 1 addition & 0 deletions eng/scripts/compiler_perf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__pycache__/
Loading
Loading