Metal GPU Trace

io.github.partprogramming09由 GitHub 账号 partprogramming09 发布v0.22.0更新于 Nov 7, 2026

Measure Wine and macOS programs' GPU use on Apple silicon with Metal System Trace

已验证STDIO仅桌面开发者工具数据与分析

概览

AI 生成的概览

在 Apple 芯片上用 Metal System Trace 录制并分析 Wine 与 macOS 程序的 GPU 性能,Windows 上则借助 PresentMon 采集帧数据。

可以做什么
  • 录制程序的 GPU 使用情况,返回 FPS、每帧 GPU 毫秒、帧节奏与内存
  • 建立基准、比较两次录制、判定性能回退、检查预算并跟踪多次运行的走势
  • 诊断转译层是否把 GPU 工作拆成过多短编码器,并对单个变量做扫描
  • 读取保留的 .trace 数据表,以及无需 Xcode 读取 Metal .gputrace 捕获
  • 下载并录制内置测试程序,查询 Apple GPU 家族资料
适用场景
适合在 Apple 芯片 Mac 上对游戏或应用的 GPU 性能做剖析与回归测试,尤其是在 Wine 或 DXMT、Mullion、MoltenVK 等转译层下运行,或需要比较原生 Metal 与转译层的表现时。
运行要求
通过 PyPI 的 uvx 在本机运行(需 Python 3.9 及以上),并需安装 zsh 与 Xcode(提供 xctrace)。环境变量可设置输出目录(METAL_TRACE_OUT)、Wine 目录(METAL_TRACE_WINE)、Wine 前缀、额外可读目录及是否保留 trace。Windows 录制需要 Intel 的 PresentMon,可用工具安装或自行放置。无需账号或 API 密钥。
安装前请注意
录制结束时它会停止该 Wine 前缀下的所有程序,或所有与原生程序同名的进程。录制需要大量可用磁盘空间(约每秒 0.8 GB),读回耗时也较长。测试程序与 PresentMon 工具会从 GitHub 下载二进制文件,并以固定哈希校验。可选的 HTTP 模式需要令牌,且只监听本机。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Metal GPU Trace,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

metal-gpu-trace

[test]

Measure how a Wine or macOS program uses the GPU on an Apple silicon Mac, from the command line or through an AI coding agent: GPU time per frame, frame pacing, FPS and memory, recorded with Instruments' Metal System Trace; whether a translation layer (DXMT, Mullion, MoltenVK) splits the work into too many short encoders; Metal .gputrace captures read without Xcode; and Apple's published facts on each GPU family to read the numbers against. Python 3.9+ standard library, zsh, and Xcode (for xctrace). MIT license. Español.

FileWhat it does
perf_record.shRecords a program for N seconds with Metal System Trace and writes <label>_<date>.json (GPU ms per frame, frame intervals, FPS, Metal and resident memory) plus per-frame and memory CSVs. Deletes the .trace afterwards unless KEEP_TRACE=1.
perf_report.pySummarizes an existing .trace the same way.
gputrace_read.pyReads a Metal .gputrace capture without Xcode: command buffers, encoders, draws, debug groups. Call names marked probable are not confirmed.
data/apple-gpu-families.jsonApple7 to Apple10: chips, what each family adds, limits that differ, with Apple's sources.
metal_trace_mcp.pyAn MCP server over all of the above.
test_metal_trace_mcp.pySelf-check without Instruments: python3 -I test_metal_trace_mcp.py prints ok; pytest runs the same tests.

Recording

sh
PERF_OUT=~/perf-runs zsh perf_record.sh game-d3d12 30 /path/to/wine ~/.wine /path/to/game game.exePERF_OUT=~/perf-runs zsh perf_record.sh app-metal 30 native - /path/to/app ./app

Arguments: label, seconds, a Wine directory holding bin/wine (or native), the Wine prefix, the working directory, the program and its arguments. Without PERF_OUT, runs go to ./perf-runs. Reading the trace afterwards takes about a minute on an M1 Pro (87 s for a 10 s recording); through the MCP server the whole call times out after 10 s per recorded second plus 120 s, and an overrun recording leaves no files behind. One recording runs at a time; keep other GPU work off the Mac while it records.

Under Wine, give it 30 s: Wine's start-up takes part of the recording. A recording with under 100 frames is too short to compare.

Disk use

Each recording keeps a JSON summary and three CSVs, about 2 MB for 10 s (most of it the Metal memory samples). The .trace (tens to hundreds of MB) is deleted unless KEEP_TRACE=1. KEEP_RUNS=N keeps only the newest N recordings. PERF_MEMORY=0 skips the Metal memory table, the slowest to read: the summary then has no metal_memory_mib and there is no memory CSV (41 % faster to summarize a 626 MB trace). The MCP tools perf_record and perf_baseline_record offer the same as memory=false.

MCP server

Install

The server runs with uvx from PyPI, with nothing to clone (brew install uv installs it). Recording also needs Xcode installed (xcrun xctrace version prints a version).

sh
uvx metal-gpu-trace

This is the command each client below runs. Desktop apps do not see Homebrew's PATH: give them the full path that which uvx prints (/opt/homebrew/bin/uvx on Apple silicon). uvx keeps the version it first downloaded; run the command once with --refresh after uvx to get the latest. uvx [email protected] pins a version.

The server reads these environment variables:

VariableWhat it sets
METAL_TRACE_OUTWhere recordings go. Give an absolute path: the default, ./perf-runs, depends on the client's working directory.
METAL_TRACE_WINEThe Wine directory (holding bin/wine) that perf_record uses when the call names none.
WINEPREFIXThe Wine prefix used when the call names none; ~/.wine otherwise.
METAL_TRACE_READMore directories the tools may read, separated by :.
METAL_TRACE_LOGoff silences the one-line stderr log per call.
KEEP_TRACE1 keeps each recording's .trace, for trace_tables, trace_query or Instruments.
KEEP_RUNSKeeps only the newest N recordings.
PERF_ENVNAME=VALUE pairs, separated by spaces, set for the recorded program.
PERF_INSTRUMENTSInstruments added to the Metal System Trace template, separated by ; (xcrun xctrace list instruments names them); their tables need the .trace, so pair it with KEEP_TRACE=1.

Claude Code

sh
claude mcp add --scope user metal-trace -e METAL_TRACE_OUT=$HOME/perf-runs -e METAL_TRACE_WINE=/path/to/wine \  -- uvx metal-gpu-traceclaude mcp list

claude mcp list shows metal-trace as connected. --scope user makes it available in every project; leave it out to add it to the current project only.

Windows

On Windows the server records native programs (perf_record_windows.py); no Wine and no Metal. METAL_TRACE_WINE is not needed: perf_record and perf_attach use native. METAL_TRACE_READ is separated by ;.

Frames come from Intel's PresentMon console application (MIT): one row per Present() of the process, with MsBetweenPresents and the GPU time MsGPUTime. Download PresentMon-<version>-x64.exe from its releases, check its SHA-256 against the one GitHub shows, and call the presentmon_install tool, or put it in %LOCALAPPDATA%\metal-gpu-trace or on PATH, or point PRESENTMON_EXE at it. The user must be an administrator or in the "Performance Log Users" group. Without PresentMon the summary falls back to DWM composition intervals (gpu.source is dwm-composition): they cover the whole desktop, miss games in exclusive full screen, and carry no GPU time. With neither a frame log, PresentMon nor DWM samples, a recording fails; it never invents frames.

What cannot be measured is null, not zero: the 1% low needs 100 frames and the 0.1% low 1000; stutter rate and jitter need two frames; thermal_throttling_detected needs GPU times; a drawstress log holds one mean per line, so its summary (gpu.frame_times) has no frame-level percentiles, stutter or jitter. DWM keeps only intervals between consecutive composed frames and drops a jump of several frames. perf_diagnose calls a large working set with uneven frame times MEMORY_PRESSURE_SUSPECTED: a suspicion, since memory bandwidth is not measured.

powershell
winget install --id=astral-sh.uv -eclaude mcp add --scope user metal-trace -e METAL_TRACE_OUT=%USERPROFILE%\perf-runs -- uvx metal-gpu-traceclaude mcp list

To run from a clone instead of PyPI (needs Python 3.9 or newer):

powershell
claude mcp add --scope user metal-trace -e METAL_TRACE_OUT=%USERPROFILE%\perf-runs -- python C:\path\to\metal-gpu-trace\metal_trace_mcp.py

In JSON clients use "command": "uvx" (or the full path where uvx prints) and Windows paths with doubled backslashes. Claude Desktop reads %APPDATA%\Claude\claude_desktop_config.json. Run the Windows tests with python -m pytest test_perf_record_windows.py.

Claude Desktop, Cursor and other JSON clients

These apps do not expand ~ or $HOME: write absolute paths.

json
{  "mcpServers": {    "metal-trace": {      "command": "/opt/homebrew/bin/uvx",      "args": ["metal-gpu-trace"],      "env": {        "METAL_TRACE_OUT": "/absolute/path/to/perf-runs",        "METAL_TRACE_WINE": "/absolute/path/to/wine"      }    }  }}
ClientFile
Claude Desktop~/Library/Application Support/Claude/claude_desktop_config.json (Settings, Developer, Edit Config); restart the app
Cursor~/.cursor/mcp.json
VS Code.vscode/mcp.json in the project; the top key is servers instead of mcpServers, and the server adds "type": "stdio"

Codex CLI

In ~/.codex/config.toml:

toml
[mcp_servers.metal-trace]command = "/opt/homebrew/bin/uvx"args = ["metal-gpu-trace"]env = { METAL_TRACE_OUT = "/absolute/path/to/perf-runs", METAL_TRACE_WINE = "/absolute/path/to/wine" }

Tools

ToolReads or records
perf_recordRecords a program and returns its summary; when it ends it stops every program of its Wine prefix, or every process named like a native program. counters=true also records Metal GPU Counters: gpu_counters (the limiters, utilization, occupancy and memory bandwidth of the GPU, with the main limiter) in the summary, at about 40 s of read-back per recorded second; not under Windows
perf_attachRecords a program that is already running, by pid or name, and leaves it running
perf_runsLists recordings, newest first, one page at a time, whether each kept its .trace, and the translation layer it ran on (a fingerprint of its Direct3D DLLs, and its Wine)
perf_compareCompares two recordings: headline numbers, encoders, GPU idle time and each encoder label's GPU ms per frame, largest change first; flags those under 100 frames. markdown=true adds the numbers as Markdown tables for a PR comment; skip_s leaves out the first seconds of each recording (start-up) and recomputes the GPU numbers, hitches and Metal memory without them. perf_gate and perf_panel take skip_s too
perf_baselineSaves several equal recordings as a named reference and returns the range each number spans across them and spread_pct, how much equal runs differ (the noise a change must beat); alone, lists the references. skip_s saves each run without its first seconds and perf_check applies the same cut to the run it judges
perf_baseline_recordRecords the same program count times (default 3) with perf_record's arguments and saves the runs as a reference in one call. skip_s as in perf_baseline
perf_cold_warmRecords the same program twice in a row and says how many more shader-compile hitches the first run has than the second (first_seen_hitches), with each run's hitches, hitches per minute and graphics compiler time; the Metal shader cache is not cleared between them
perf_abRecords the same program with two environments (env_a, env_b: NAME=VALUE pairs) in the order A B B A and says per metric (FPS, 1 % low, GPU ms, stutter) whether B is better, worse or the same: better or worse only when every B value is outside A's range
perf_sweepRecords the same program once per value of one variable (dim, size, example, api or env:NAME), 2 to 8 values, rounds times (every other round in reverse order), and returns per value the median FPS, 1 % low, GPU ms per frame and stutter; with 3 or more numeric values it fits GPU ms per frame on the value (fixed ms and ms per draw for dim) with its r2
perf_checkJudges a recording against a reference: regressed when FPS falls under the range by more than margin_pct (default 3), GPU ms per frame rises over it, or encoders or command buffers per frame exceed it; improved or same otherwise, with the reasons and the full comparison
perf_gateChecks a recording against budgets you set (FPS and 1% low floors; stutter, p95 GPU ms, hitch and Metal MiB ceilings) and returns pass or fail with each limit and value; a missing number fails
perf_historyFollows FPS, 1% low, GPU ms, stutter, hitches and Metal MiB across the runs whose name starts with a prefix, oldest first, with the change from first to last
perf_panelWrites <name>.panel.html: a page with GPU time per frame and its hitches, the numbers, Metal memory and, for two runs, A against B. It has no server and loads nothing from the network; the viewer hides or reorders widgets and exports the layout as JSON. With --http, /panel#token=...&runs=a,b shows it live, refreshed every 10 s. layout (tab ids in order) saves panel.json in the runs directory as the default tabs of every panel, the live one included; the GPU counters tab shows when a run has them
perf_export_traceWrites a recording's GPU frames as <run>.chrome-trace, one slice per frame, for ui.perfetto.dev or chrome://tracing
perf_diagnoseSays whether a recording splits its GPU work into too many short encoders, as translation layers do, with encoders and command buffers per frame, the labels with the most GPU time and the GPU's idle time
trace_tablesLists the tables of a kept .trace, named by its run or its path
trace_countCounts the rows of several tables of a kept .trace, in all and per process; by default the tables that matter for a translation layer (GPU intervals, encoders, compiler spills, compiled shaders, allocations, counters, Time Profiler), so an empty one shows before reading it
trace_queryOne page of rows of one table, optionally one process
capture_summarySummarizes a .gputrace; lists its 100 most frequent calls out of calls_total
capture_recordsOne page of a .gputrace's records
gpu_familyApple's facts for a family or chip (Apple7, M1 Pro, M3 Max)
presentmon_installWindows only: downloads PresentMon, checks its pinned SHA-256 and keeps it in %LOCALAPPDATA%\metal-gpu-trace, where perf_record and perf_attach find it; Claude Code asks before every call
workload_listLists the test programs workload_fetch can download; for bgfx-examples, example_traits gives each example's class and its encoders per frame in native Metal
workload_fetchDownloads a test program once, checks its SHA-256 and keeps it in ~/Library/Caches/metal-gpu-trace; Claude Code asks before every call

perf_record takes workload, api (mtl, mtl-x64, vk, d3d11 or d3d12), dim, size and example instead of program, to record a fetched test program (workload_list says what each has). mtl-x64 is native Metal built for x86_64 and run under Rosetta, like Wine's programs; size ("1920x1080") sets drawstress's window. The first workload is bgfx's 17-drawstress (BSD-2, 9.3 MB), built from source by .github/workflows/workloads.yml: a grid of cubes, dim³ draws per frame, with its shaders inside the program. The compare-layer prompt (/metal-trace:compare-layer drawstress d3d12 in Claude Code) records it in native Metal and under the Wine in METAL_TRACE_WINE, then runs perf_diagnose and perf_compare.

The second workload, bgfx-examples (55 MiB), holds thirty bgfx examples, each a different load (many cubes, textures, render-target chains, a G-buffer, compute, reflective shadow maps, post-processing, draws the GPU decides, text and interface, shadows, transparency, GPU read-back, virtual textures, upscaling, texture formats, occlusion queries, tessellation, multiple windows, off-screen rendering; the last twenty-one measured in native Metal and Wine D3D12 only, example_traits in workload_list gives each one's class and encoders per frame in both, and 40-svt writes a 370 MB tile cache to temp/ in the workload's folder on its first run): perf_record(workload="bgfx-examples", api="d3d12", example="21-deferred"). Two macOS levers change the Mac under a recording: memory_free_pct (20 to 60) holds the whole Mac at that percentage of RAM free (memory_pressure), and background runs the program under taskpolicy -b, a hard throttle. A small GPU-bound program does not feel the first (drawstress stayed at 728 FPS and its resident memory fell); the second slows it several times over. Repeat a run that uses either.

The third workload, godot, is a lit 3D scene a real engine builds from code (Godot 4.7.2, Forward+): 400 meshes, 8 lights, a shadowed sun, api="mtl" for Godot's Metal driver and api="d3d12" under Wine for its Direct3D 12 driver, with args="-- meshes=800 lights=16" to change it. workload_fetch("godot") keeps the 10 KB project from this repository's release and downloads Godot's official macOS (171 MB) and Windows (86 MB) builds from godotengine/godot-builds, checking the SHA-512 this package pins; it needs about 257 MB and some seconds. The scene has no imported assets, so Godot does not import anything. Godot compiles its pipelines on every start, which makes it a case for perf_cold_warm: its shader-compile hitches came back unchanged in the second run.

Reading the numbers across runs

  • A summary says where it ran and what the GPU did: machine (chip, cores, RAM, macOS, screen_locked), gpu_activity (utilization of the device, renderer and tiler, split scenes, GPU recoveries: it covers the whole GPU, not only the program), resource_allocations (allocation events per frame, by type; a running total, not memory in use) and command_buffer_errors.
  • A locked Mac session leaves native Metal windows unpaced: 3 000 to 4 000 FPS against 120 with vsync, on the same examples. Record with the Mac unlocked; perf_compare returns screen when one run was recorded locked and the other not.
  • GPU ms per frame follow the GPU's performance state: a run paced at 120 FPS sits in Minimum and takes more ms for the same work (21-deferred: 1.75 ms paced, 0.27 ms unpaced). perf_compare returns gpu_state when two runs sat in different states, and perf_diagnose returns display_synced_hz when the FPS sits on a display rate. Compare runs paced alike: native Metal and D3D12 under Wine with Mullion, both at 120 FPS, do compare.
  • With counters=true, each listed hitch also has top_limiter: the Limiter counter with the highest mean over the interval before it (window_ms, read in whole 10 ms bins; null when no sample falls in it), which can differ from the whole run's main limiter.

api=vk runs the same program through Vulkan on MoltenVK. MoltenVK is not shipped: set METAL_TRACE_MOLTENVK to a directory (no spaces) holding an arm64 libMoltenVK.dylib, such as the one in a Vulkan SDK or brew install molten-vk. The run's layer names MoltenVK with the library's SHA-256, so perf_compare against a native Metal run says it compares two layers. In one measurement at dim=20, 10 s each: native Metal 2 encoders per frame; MoltenVK 13, 91 % of them short, and the GPU idle 89 % of the time (perf_diagnose: too_many_short_encoders true). One pair of runs, not a benchmark.

api=vk is native only. drawstress.exe --vk under Wine needs a Wine built with Vulkan: the Wine of DXMT and Apple's Game Porting Toolkit were tried and both log Wine was built without Vulkan support, so the recording holds no GPU frames. CrossOver's Wine has Vulkan but runs only inside one of its bottles, which was not tried.

The same facts are MCP resources: metal-trace://gpu-families (all) and metal-trace://gpu-families/apple7 to Each saved run is a resource too: metal-trace://runs/<run> reads its summary. apple10. They restate Apple's Metal Feature Set Tables of 21 May 2026, MTLGPUFamily and the M3 tech talk; check a device with supportsFamily.

How it follows the MCP specification and Claude Code's limits:

  • stdout carries only MCP messages; each tool call logs one line to stderr (METAL_TRACE_LOG=off silences it), with no arguments or paths.
  • Lists come in pages (offset, limit, default 50, at most 500) with total and next_offset; a result over 40 000 characters is refused with a hint to ask for a smaller page.
  • Files are read only inside METAL_TRACE_OUT and the directories in METAL_TRACE_READ (separated by :).
  • Failures come back as isError results that say what to do, without stack traces or local paths. Summaries cut absolute paths to file names, so they can be shared.
  • Every xctrace call has a timeout.

HTTP

METAL_TRACE_TOKEN=<secret of 16+ characters> metal-gpu-trace --http [--port N] serves the same tools at POST http://127.0.0.1:8765/mcp (Streamable HTTP, one JSON reply per request), for a client on the same Mac that cannot start a stdio server. Every request needs Authorization: Bearer <token>. It listens on 127.0.0.1 only, refuses a request whose Host or Origin is not localhost or 127.0.0.1 (DNS rebinding), and does not start without the token. Cancel a running call with notifications/cancelled from another connection. There is no progress stream over HTTP, and no remote access: reach another Mac through an SSH tunnel (ssh -L 8765:127.0.0.1:8765 mac), not by opening the port.

Windows tests on a real machine

GitHub's windows-latest has no GPU and no desktop session, so PresentMon and DWM recordings are only tested on a real Windows machine. windows/winbridge-run-tests.ps1 updates a checkout there and runs test_perf_record_windows.py; it is written as a WinBridge task (fixed name, script pinned by SHA-256, no arguments). To register it, copy it to the laptop, set $repo to the checkout's path, take its hash there with Get-FileHash <file> -Algorithm SHA256 (Git may have changed the line endings, so the hash of the copy in this repo is not the one to use), and add a [tasks.<name>] table with script and sha256 to the agent's TOML.

CI gate

metal-gpu-trace check RUN BASELINE [--margin-pct N] runs perf_check without a client and prints one JSON line (verdict, reasons, hints). Exit code 0: same or improved; 1: regressed; 2: could not be judged (no such run or reference, or under 100 frames). Runs are read from METAL_TRACE_OUT. Recording needs Instruments, so the job runs on a self-hosted macOS runner:

yaml
jobs:  perf:    runs-on: [self-hosted, macOS, ARM64]    steps:      - run: zsh perf_record.sh pr native - . ./app      - run: metal-gpu-trace check "$(ls -t ~/perf-runs/pr_*.json | head -1 | xargs basename -s .json)" main-ref

Credits

  • The record layout of a .gputrace command stream follows tmc/gputrace (MIT); no code is copied. The call ids were matched against Xcode's command list on macOS 27.0.1.
  • GPU family facts: Apple's documents linked above, restated, not quoted.

来源:README.md,提交 aed7acf

工具

24

perf_record

Record a program

Records `program` (an .exe under Wine, or a macOS binary with wine="native"), or a test program fetched with workload_fetch (workload, api, dim), for `seconds` with Metal System Trace and returns its summary: GPU ms per frame, frame intervals, FPS, Metal and resident memory (memory=false skips the Metal memory table, the slowest to read). When it ends it stops every program of that Wine prefix (wineserver -k), or every process named like the program with native. counters=true also records Metal GPU Counters (`gpu_counters` in the summary: the units the GPU waited on, its utilization, occupancy and memory bandwidth); it adds about 40 s of read-back per recorded second.

输入参数apidimenvargssizewinelabel必填memoryprefixexampleprogramseconds另有 5 个

perf_baseline_record

Record a reference

Records the same program `count` times in a row with perf_record's arguments and saves the runs as the reference `name` for perf_check, returning the range each number spans across them. Runs are named `name`-1, `name`-2, ... Each recording takes its seconds plus about a minute to read back. skip_s as in perf_baseline: the reference leaves out each run's start-up.

输入参数apidimenvargsname必填sizewinecountmemoryprefixskip_sexample另有 7 个

perf_sweep

Record one run per value of a variable

Records the same program once per value of one variable (dim, example, api, size, or env:NAME for an environment variable) and returns, per value, the median of FPS, 1 % low, GPU ms per frame and stutter, and with 3 or more numeric values the straight line GPU ms per frame follows (fixed ms plus ms per draw for dim, per unit otherwise) with its r2. With rounds above 1 the values run in opposite order every other round, so drift hits all alike. Runs are named `name`-<value number>-r<round>; each takes its seconds plus about a minute to read back.

输入参数apidimenvargsname必填sizewinememoryprefixroundsskip_svalues必填另有 9 个

perf_ab

Record two settings in A B B A order

Records the same program with two environments in the order A B B A (repeated `rounds` times, so drift hits both sides equally) and says per metric whether B is better, worse or the same as A, with every value behind it. env_a and env_b are NAME=VALUE pairs separated by spaces; empty means none. Runs are named `name`-a1, `name`-b1, ... Each recording takes its seconds plus about a minute to read back. skip_s leaves out the first seconds of every recording (the start-up) when the verdicts are drawn, as perf_compare does; the recordings are whole.

输入参数apidimargsname必填sizewineenv_a必填env_b必填memoryprefixroundsskip_s另有 8 个

perf_cold_warm

Record a run twice to find first-seen shader stutter

Records the same program twice in a row and says what the first run suffers that the second does not: hitches whose cause is a shader compile (first-seen pipelines: the first run's count minus the second's, never below 0), with each run's hitch count and graphics compiler time. macOS only. Runs are named `name`-first and `name`-second; each recording takes its seconds plus about a minute to read back.

输入参数apidimenvargsname必填sizewinememoryprefixexampleprogramseconds另有 5 个

perf_attach

Record a running program

Records a program that is already running, by pid or by a name in its command line (Game.exe under Wine), for `seconds` and returns the same summary as perf_record; the program keeps running. For games started by Steam, CrossOver, NotProton or any launcher: start the game or its benchmark there first.

输入参数label必填process必填seconds

perf_runs

List recordings

Lists the saved recordings, newest first, with frames, FPS, GPU ms per frame, memory peaks and the translation layer each ran on (fingerprint and Wine, or native).

输入参数limitoffset

perf_compare

Compare two recordings

Compares two saved recordings (names from perf_runs), a the reference and b the run after a change: the headline numbers (FPS, GPU ms, frame pacing, memory), then what changed in the GPU work and where: encoders and command buffers per frame, the share of encoders under short_us, the GPU's idle time, and each encoder label's count and GPU ms per frame, largest change first. layer says whether both ran on the same translation layer: with different layers it compares layers, not one change. A Windows run against a Metal run has `measure`: the GPU ms and Metal memory differ in kind and the encoders exist only in Metal, so use FPS, its lows, stutter and jitter. Recordings with under 100 frames are flagged: too short to compare. With markdown true the result also has `markdown`: the same numbers as tables for a PR comment. skip_s leaves out the first seconds of each recording, where shaders compile and resources load: the GPU numbers, hitches and Metal memory are recomputed from the per-frame files without them, and `skipped_s` says it; thermal state, process memory and encoders stay whole-run. `screen` appears when one run was recorded with the screen locked and the other not: FPS is then not comparable.

输入参数a必填b必填skip_smarkdownshort_us

perf_baseline

Name a reference

Names a reference for perf_check, or lists them. With name and runs (names from perf_runs, several runs of the same program recorded with no change between them), it saves copies of their summaries as the reference `name`, replacing a previous one, and returns the range each number spans across them: that range, not one run, is what perf_check judges against, since repeated runs differ by a few percent, and `spread_pct`, each range's width in % of its midpoint: the noise of this program on this machine, which a change must exceed. With name alone it shows that reference; with nothing it lists them. With skip_s the reference keeps each run without its first skip_s seconds (the start-up, as perf_compare's skip_s) and perf_check applies the same cut to the run it judges, so both are steady-state; the runs need their per-frame files for that.

输入参数namerunsskip_s

perf_check

Check a run against a reference

Judges a recording against a reference saved with perf_baseline: regressed when FPS falls under the reference's lowest FPS by more than margin_pct, GPU ms per frame rises over its highest by more than margin_pct, or encoders or command buffers per frame exceed its highest; improved when a number leaves the range the other way and none regressed; same otherwise. Frame pacing, short encoders and GPU idle time are reported by the comparison but do not decide: they vary too much between equal runs. A run from Windows against a Metal reference (or the reverse) is judged on FPS alone. A reference saved with skip_s judges the run without its first skip_s seconds too (`skipped_s` says so). Returns the reasons and perf_compare's full comparison against the reference's first run.

输入参数run必填baseline必填margin_pct

perf_export_trace

Export frames to Perfetto

Writes a recording's GPU frames as a Chrome trace file, `<run>.chrome-trace` in the runs directory, that ui.perfetto.dev and chrome://tracing open: one slice per GPU frame, from its start for its GPU time (the sum of its encoders' time, so a frame with parallel encoders can show shorter than it took), with the compute, fragment and vertex split as arguments. Returns the file name and the number of frames.

输入参数run必填

perf_gate

Check a run against budgets

Checks a recording against budgets and says pass or fail: a floor for FPS and the 1% low, a ceiling for the stutter rate, the p95 GPU ms per frame, the hitch count and the peak Metal MiB. Give at least one. A number the recording lacks fails its budget (value null): a gate must not pass on missing data. Returns each budget with its limit, the value and whether it held. Use it as a bar a change must clear, where perf_check judges against equal runs. skip_s leaves out the first seconds of the recording (the start-up), as perf_compare does.

输入参数run必填skip_sfps_minhitches_maxmetal_mib_maxgpu_ms_p95_maxfps_1pct_low_minstutter_rate_pct_max

perf_history

Follow a number across runs

Lists the recordings whose name starts with `prefix`, oldest first, with their FPS, 1% low, GPU ms, stutter, hitches and peak Metal MiB, and the change from the first to the last: how a number moved over a series of runs, such as one recording per version of a translation layer. Read a trend as real only when it exceeds the spread_pct that perf_baseline reports for equal runs. Runs from Windows and Metal in one series are flagged: their GPU ms and memory do not compare. skip_s leaves out the first seconds of each recording (the start-up), as perf_compare does.

输入参数limitprefix必填skip_s

perf_panel

Write an HTML panel

Writes one HTML file, `<name>.panel.html` in the runs directory, that shows one or two recordings in a browser without a server: GPU time per frame with the hitches marked, the numbers (FPS and its lows, frame time, jitter, stutter, memory, thermal state), Metal memory over time and, for two runs, A against B. The file holds the data itself, no path, and loads nothing from the network; the viewer can hide and reorder the widgets and export the layout as JSON. preset `fps` is the timeline, numbers and memory; `compare` (two runs) puts A against B first. skip_s leaves out the first seconds of each recording (the start-up), as perf_compare does. layout (tab ids in the order to show) is saved as panel.json in the runs directory and becomes the default tab order of every panel, the live one too, until the viewer changes it in the browser; ids left out are hidden but can be switched back on; tabs are summary, ab, frames, encoders, counters, memory and data, and a panel.json you wrote yourself, or copied from the panel's Layout JSON, works the same. Returns the file name, the runs, the frames shown and the file's bytes.

输入参数name必填runs必填layoutpresetskip_s

perf_diagnose

Diagnose encoder use

Says whether a saved recording splits its GPU work into too many short encoders, the pattern of translation layers such as DXMT, Mullion or MoltenVK, with the numbers behind it: encoders and command buffers per frame, the share of short encoders, the labels with the most GPU time and the GPU's idle time. Read the idle time together with the FPS: a program waiting for vsync idles too. Defaults come from bgfx 17-drawstress on an M1 Pro: 7 encoders per frame and 50% under 25 us under Mullion, 2 and 2% in native Metal.

输入参数run必填short_usshort_sharemin_encoders

trace_tables

List a trace's tables

Lists the data tables (schemas) a .trace recording holds; recordings keep their .trace only with KEEP_TRACE=1.

输入参数trace必填

trace_count

Count a trace's rows

Counts the rows of several tables of a kept .trace, in all and per process, so a recording's useful tables show before reading them: a table with 0 rows needs another instrument or Xcode, not a bigger page.

输入参数trace必填tables

trace_query

Read a trace table

Returns one page of rows of one table of a .trace as {column: value}, optionally only one process's rows.

输入参数pidlimittrace必填offsetschema必填

capture_summary

Summarize a capture

Reads a Metal .gputrace capture without Xcode: command buffers, encoders, draws, debug groups, and the 100 most frequent call ids out of calls_total.

输入参数capture必填

capture_records

Read a capture's records

Returns one page of the records of a .gputrace command stream, with their Metal call names when known.

输入参数limitoffsetcapture必填

gpu_family

Apple GPU family facts

Apple's published facts for one GPU family, by family ("Apple7") or chip ("M1 Pro"): its chips, what it adds, its limits, plus the limits shared by all families and the footnotes. Source URLs are in the result.

输入参数name必填

workload_list

List test programs

Lists the test programs workload_fetch can download, such as bgfx's drawstress: what each measures, its size, license and APIs, and whether it is already downloaded.

无需输入参数。

workload_fetch

Download a test program

Downloads a test program from this project's GitHub releases once, checks its SHA-256 against the one this package pins, and keeps it in ~/Library/Caches/metal-gpu-trace; later calls reuse it. The programs are built from source by the project's workloads workflow. A workload with `downloads` (Godot) also fetches each of those zip files from its own publisher, checks its SHA-512 against the one data/workloads.json pins and unzips it into the workload's folder.

输入参数name必填

presentmon_install

Install PresentMon (Windows)

Windows only: downloads Intel's PresentMon console application (MIT) from its GitHub release, checks its SHA-256 against the one this package pins, and keeps it in %LOCALAPPDATA%\metal-gpu-trace, where perf_record and perf_attach find it; later calls reuse it. It needs administrator rights or the Performance Log Users group to run.

无需输入参数。

版本历史

7
  1. v0.22.0最新Nov 6, 2026
  2. v0.21.0Nov 6, 2026
  3. v0.19.0Nov 5, 2026
  4. v0.16.0Nov 3, 2026
  5. v0.8.3Nov 1, 2026
  6. v0.7.1Oct 18, 2026
  7. v0.5.0Oct 18, 2026

评分

已满足适用检查项的 90%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分
  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分