⚠️ Kernel CPU sampling requires an elevated (Administrator) shell. If the
current agent harness (Codex, Claude Code, etc.) or its terminal is not running
as Administrator, stop before ETL collection and tell the user to restart the
harness from an elevated terminal. Do not attempt a workaround.
⚠️ Do NOT use xperf / WPR / WPA to collect. Use the bundled PerfView run
flow below — it produces a merged, self-contained .etl that the
perf-sampling-parser skill can parse directly.
ETL Generator
Launch a program under PerfView's CPU sampler, wait for it to exit, and write a
merged .etl trace. This is the capture step that feeds the analysis
skills:
etl-generator → perf-sampling-parser → perf-optimizer
(this skill) (per-process CPU + (root-cause +
speedscope export) source optimization)
Path Conventions
<skill_dir>: directory containing this SKILL.md, derived from the path used
to read this file.
- Collection script:
<skill_dir>/scripts/collect_etl.py.
- PerfView is not shipped here: the script reuses the copy inside the
sibling
perf-sampling-parser/scripts/PerfView.exe. If that sibling is
absent, pass --perfview <path> explicitly.
Inputs
- Required: path to the program (
.exe) to run and profile.
- Optional: arguments to pass to the program (
--args).
- Optional: output
.etl path (--out, default <program_dir>/<stem>.etl).
- Optional: working directory for the program (
--cwd).
Output
- A merged
.etl file (default next to the program). This is a self-contained
trace ready for perf-sampling-parser.
Preconditions (check before running)
Elevated shell. Before collecting, confirm the current terminal is
Administrator. On Windows PowerShell, use:
([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
If it returns False, stop immediately. Tell the user to open an elevated
terminal (Start -> search PowerShell or Command Prompt -> Run as
administrator), start the agent harness from that elevated terminal
(codex, claude, or their normal command), and resume from profiling with
the same project/workload arguments. Do not continue to ETL collection,
parsing, optimization, or any later profiling-dependent step from the
non-elevated session.
Program exits on its own. PerfView run stops collecting when the target
process exits. For a long-running / server program, either give it a
workload that terminates, or warn the user that --timeout-sec will force a
stop (which may leave the program killed).
Steps
Step 1: Collect the ETL
python "<skill_dir>/scripts/collect_etl.py" "<program.exe>" --args "<program args>" --out "<etl_path>"
- Blocks until the target program exits (or
--timeout-sec, default 600s).
- Success marker: stdout contains
DONE ... OK and ends with
[collect_etl] DONE — ETL written to: <path>.
- On failure, the script prints the first 50 lines of
<etl_dir>/temp/pfv_collect_log.txt; relay them to the user.
Step 2: Hand off to analysis
Report the absolute .etl path. The natural next step is the
perf-sampling-parser skill (or perf-optimizer, which will invoke
perf-sampling-parser for you when given an .etl).
Notes
- Merged ETL: the script passes
/Merge:true so module and symbol-index
information is folded into the single .etl. This makes the trace portable
and lets the parser resolve modules without the original machine state.
- No zip:
/Zip:false keeps a raw .etl (the parser expects .etl/.etlx,
not .etl.zip).
- Buffer size:
/BufferSizeMB:256 reduces the chance of dropped CPU samples
on busy machines; raise it for very hot, many-core workloads.
- What is captured: CPU stacks (the kernel
PROFILE sampled-profile events)
plus image/process/thread events — enough for per-process CPU attribution and
call-stack flame graphs. It does not enable heap or context-switch tracing.
1---2name: etl-generator3description: Run a target program under a CPU-sampling profiler and produce an ETL trace file for later performance analysis. Keywords - collect ETL, profile a program, generate etl, capture CPU trace, record ETL.4---56> ⚠️ Kernel CPU sampling requires an **elevated (Administrator) shell**. If the7> current agent harness (Codex, Claude Code, etc.) or its terminal is not running8> as Administrator, stop before ETL collection and tell the user to restart the9> harness from an elevated terminal. Do not attempt a workaround.10>11> ⚠️ Do NOT use xperf / WPR / WPA to collect. Use the bundled PerfView `run`12> flow below — it produces a merged, self-contained `.etl` that the13> `perf-sampling-parser` skill can parse directly.1415# ETL Generator1617Launch a program under PerfView's CPU sampler, wait for it to exit, and write a18merged `.etl` trace. This is the **capture** step that feeds the analysis19skills:2021```22etl-generator → perf-sampling-parser → perf-optimizer23 (this skill) (per-process CPU + (root-cause +24 speedscope export) source optimization)25```2627## Path Conventions2829- `<skill_dir>`: directory containing this SKILL.md, derived from the path used30 to read this file.31- Collection script: `<skill_dir>/scripts/collect_etl.py`.32- PerfView is **not shipped here**: the script reuses the copy inside the33 sibling `perf-sampling-parser/scripts/PerfView.exe`. If that sibling is34 absent, pass `--perfview <path>` explicitly.3536## Inputs3738- **Required**: path to the program (`.exe`) to run and profile.39- **Optional**: arguments to pass to the program (`--args`).40- **Optional**: output `.etl` path (`--out`, default `<program_dir>/<stem>.etl`).41- **Optional**: working directory for the program (`--cwd`).4243## Output4445- A merged `.etl` file (default next to the program). This is a self-contained46 trace ready for `perf-sampling-parser`.4748## Preconditions (check before running)49501. **Elevated shell.** Before collecting, confirm the current terminal is51 Administrator. On Windows PowerShell, use:5253 ```powershell54 ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)55 ```5657 If it returns `False`, stop immediately. Tell the user to open an elevated58 terminal (`Start` -> search `PowerShell` or `Command Prompt` -> **Run as59 administrator**), start the agent harness from that elevated terminal60 (`codex`, `claude`, or their normal command), and resume from profiling with61 the same project/workload arguments. Do not continue to ETL collection,62 parsing, optimization, or any later profiling-dependent step from the63 non-elevated session.642. **Program exits on its own.** PerfView `run` stops collecting when the target65 process exits. For a long-running / server program, either give it a66 workload that terminates, or warn the user that `--timeout-sec` will force a67 stop (which may leave the program killed).6869## Steps7071### Step 1: Collect the ETL7273```bash74python "<skill_dir>/scripts/collect_etl.py" "<program.exe>" --args "<program args>" --out "<etl_path>"75```7677- Blocks until the target program exits (or `--timeout-sec`, default 600s).78- Success marker: stdout contains `DONE ... OK` and ends with79 `[collect_etl] DONE — ETL written to: <path>`.80- On failure, the script prints the first 50 lines of81 `<etl_dir>/temp/pfv_collect_log.txt`; relay them to the user.8283### Step 2: Hand off to analysis8485Report the absolute `.etl` path. The natural next step is the86`perf-sampling-parser` skill (or `perf-optimizer`, which will invoke87`perf-sampling-parser` for you when given an `.etl`).8889## Notes9091- **Merged ETL**: the script passes `/Merge:true` so module and symbol-index92 information is folded into the single `.etl`. This makes the trace portable93 and lets the parser resolve modules without the original machine state.94- **No zip**: `/Zip:false` keeps a raw `.etl` (the parser expects `.etl`/`.etlx`,95 not `.etl.zip`).96- **Buffer size**: `/BufferSizeMB:256` reduces the chance of dropped CPU samples97 on busy machines; raise it for very hot, many-core workloads.98- **What is captured**: CPU stacks (the kernel `PROFILE` sampled-profile events)99 plus image/process/thread events — enough for per-process CPU attribution and100 call-stack flame graphs. It does not enable heap or context-switch tracing.