Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
537 commits
Select commit Hold shift + click to select a range
cbad10e
perfettoviewer: serve local trace UI
tmc Aug 13, 2026
c0dafab
timeline: export native Perfetto traces
tmc Aug 13, 2026
a5bf7bf
perfetto: bound native trace output
tmc Aug 13, 2026
859dbc3
environment: define comparison projection
tmc Aug 13, 2026
a1bce46
perfetto: retain execution boundaries under budget
tmc Aug 13, 2026
95d4dc3
timeline: keep APS aggregates off counter tracks
tmc Aug 13, 2026
2ff8f47
timeline: report MLX semantic coverage
tmc Aug 13, 2026
1763bae
mlxsemantic: distinguish receipts from sidecars
tmc Aug 13, 2026
27ad29e
perfetto: stream preflighted packets
tmc Aug 13, 2026
2f3cd49
timeline: export stable PerfettoSQL views
tmc Aug 13, 2026
0bdb615
diff: fail closed on environment evidence
tmc Aug 13, 2026
d1c8cd2
timeline: focus Perfetto viewer precisely
tmc Aug 13, 2026
9ce57ff
perfetto: annotate every timed event
tmc Aug 13, 2026
51cb6d1
perfetto: complete evidence manifest
tmc Aug 13, 2026
c577a92
perfetto: report loss by evidence class
tmc Aug 13, 2026
8194122
skill: document native timeline workflow
tmc Aug 13, 2026
5d808e3
timeline: consolidate Perfetto workflow
tmc Aug 13, 2026
f1591cb
perfettoviewer: pin local UI revisions
tmc Aug 13, 2026
8608792
timeline: report unavailable manifest evidence
tmc Aug 13, 2026
6baf1b3
timeline: close viewer listener on cancellation
tmc Aug 13, 2026
1a00860
perfetto: order track descriptors by hierarchy
tmc Aug 13, 2026
71857a9
timeline: retain untimed MLX semantic nodes
tmc Aug 13, 2026
fdc2181
timeline: break out dispatch detail by encoder
tmc Aug 13, 2026
05ada2e
timeline: omit untimed dispatch detail tracks
tmc Aug 13, 2026
168bf3b
trace: attribute capture dispatches to pipelines
tmc Aug 13, 2026
085e20a
timeline: separate untimed capture launches
tmc Aug 13, 2026
720eb48
skill: explain capture-only Perfetto evidence
tmc Aug 13, 2026
11be423
timeline: export all pipeline compiler facts
tmc Aug 13, 2026
1882682
perfettosql: normalize recorded dispatches
tmc Aug 13, 2026
05cac11
docs: describe Perfetto compiler facts
tmc Aug 13, 2026
b5333d7
docs: specify shader source attribution
tmc Aug 13, 2026
6ae06c2
perfettosql: expose dispatch evidence
tmc Aug 13, 2026
77b370d
docs: describe canonical dispatch evidence
tmc Aug 13, 2026
dd0669e
perfettosql: normalize dispatch identifier types
tmc Aug 13, 2026
a00c64a
timeline: retain measured dispatch geometry
tmc Aug 13, 2026
2250671
timeline: retain dispatch capture structure
tmc Aug 13, 2026
fafc2f0
docs: explain dispatch capture membership
tmc Aug 13, 2026
375cda0
perfettosql: report real dispatch sample coverage
tmc Aug 13, 2026
9347cc6
docs: qualify dispatch sample attribution
tmc Aug 13, 2026
3c98514
capture: preserve target standard input
tmc Aug 13, 2026
9d35ad7
hostcorrelation: refuse unproven clock joins
tmc Aug 13, 2026
85bf559
perfettosql: separate dispatch and function work
tmc Aug 13, 2026
d8c3ea6
docs: describe function-level Perfetto view
tmc Aug 13, 2026
a9ac076
hostcorrelation: project bounded host events
tmc Aug 13, 2026
0a8ffbc
perfettosql: expose encoder aggregate evidence
tmc Aug 13, 2026
b639a98
docs: describe encoder Perfetto evidence
tmc Aug 13, 2026
70f860d
timeline: attach verified host correlations
tmc Aug 13, 2026
33fc8e3
perfettosql: expose command buffer evidence
tmc Aug 13, 2026
15132ff
timeline: order encoder tracks chronologically
tmc Aug 13, 2026
d1f12ac
docs: describe command buffer evidence
tmc Aug 13, 2026
5ad3724
hostcorrelation: derive clock bridge from samples
tmc Aug 13, 2026
6c58b64
perfettosql: expose capture manifest evidence
tmc Aug 13, 2026
12f5f28
docs: describe manifest SQL views
tmc Aug 13, 2026
9ce9d44
timeline: expose raw profiler evidence
tmc Aug 13, 2026
e3a2c45
docs: describe raw profiler evidence
tmc Aug 13, 2026
e3f82e9
capture: retain live GPU command timing
tmc Aug 13, 2026
cbdf049
perfettosql: retain function provenance
tmc Aug 13, 2026
d408fdd
docs: explain function evidence provenance
tmc Aug 13, 2026
a82f04e
capture: observe all command buffer constructors
tmc Aug 13, 2026
6b28680
perfettosql: expose verified timing receipts
tmc Aug 13, 2026
9cb9863
docs: describe verified timing views
tmc Aug 13, 2026
19dfd4e
hostcorrelation: bind measured host intervals
tmc Aug 13, 2026
ff518c6
perfettosql: retain MLX semantic evidence
tmc Aug 13, 2026
53fa825
docs: describe semantic evidence views
tmc Aug 13, 2026
e3071e6
perfetto: mark live timing as measured
tmc Aug 13, 2026
1166ad5
perfettosql: retain unattributed counter evidence
tmc Aug 13, 2026
40cfd37
docs: describe untimed Perfetto evidence
tmc Aug 13, 2026
319980f
metallib: decode embedded source archives
tmc Aug 13, 2026
65fc70a
metallib: inventory debug source records
tmc Aug 13, 2026
36c0724
metallib: bind metadata to declared sections
tmc Aug 13, 2026
10fc364
metallib: bind function debug metadata
tmc Aug 13, 2026
dea6607
perfettosql: expose complete event arguments
tmc Aug 13, 2026
876c94f
docs: describe lossless event argument views
tmc Aug 13, 2026
c6736c7
shader: use metallib source declarations
tmc Aug 13, 2026
daa9119
shader: stop estimating source line cost
tmc Aug 13, 2026
6f3d5b4
perfettosql: expose timing summary evidence
tmc Aug 13, 2026
fa33724
docs: distinguish native timing summaries
tmc Aug 13, 2026
b089994
shader: suppress advice without dispatch shape
tmc Aug 13, 2026
9f205e3
perfettosql: separate source and projected counts
tmc Aug 13, 2026
b80d897
docs: explain cross-domain evidence counts
tmc Aug 13, 2026
fb40c29
perfettosql: retain raw record identity
tmc Aug 13, 2026
4256cc8
docs: explain track event argument identity
tmc Aug 13, 2026
ec5d8c1
docs: define Perfetto release ownership
tmc Aug 13, 2026
0aaa126
xcodebindings: report source cost readiness
tmc Aug 13, 2026
eb057c8
docs: record instruction cost boundary
tmc Aug 13, 2026
90fa3f9
perfettosql: expose wall clock conversion
tmc Aug 13, 2026
adbea68
docs: explain wall clock conversion fields
tmc Aug 13, 2026
c76f9d2
perfettosql: retain pipeline identity
tmc Aug 13, 2026
8968fcb
docs: define pipeline identity scope
tmc Aug 13, 2026
8d92344
perfettosql: retain continuous time evidence
tmc Aug 13, 2026
6c408fa
docs: bound continuous time evidence
tmc Aug 13, 2026
2b64434
perfettosql: retain replay performance state
tmc Aug 13, 2026
e6d24bf
docs: bound performance state evidence
tmc Aug 13, 2026
cd23894
perfettosql: retain replay restore intervals
tmc Aug 13, 2026
ef5b95e
docs: define replay restore interval scope
tmc Aug 13, 2026
e6fc8d5
perfettosql: retain Metal device identity
tmc Aug 13, 2026
ce7a1b6
docs: define stream device identity evidence
tmc Aug 13, 2026
0193f1e
perfettosql: retain stream archive metadata
tmc Aug 13, 2026
5ff3539
docs: define stream archive metadata scope
tmc Aug 13, 2026
57331c0
perfettosql: report stream table integrity
tmc Aug 13, 2026
a3e9723
docs: define stream table integrity evidence
tmc Aug 13, 2026
af0aa1a
perfettosql: inventory stream archive families
tmc Aug 13, 2026
d10d33a
docs: define archive family inventory semantics
tmc Aug 13, 2026
a0d19dc
perfettosql: reconcile archive family blobs
tmc Aug 13, 2026
8bfff05
docs: define decoded archive family counts
tmc Aug 13, 2026
c6bee5b
tools: validate untimed Perfetto dispatches
tmc Aug 13, 2026
59823c0
perfettosql: expose counter decode coverage
tmc Aug 13, 2026
1900d35
docs: define counter decode coverage
tmc Aug 13, 2026
26d9e92
perfettosql: inventory APSData dictionaries
tmc Aug 13, 2026
ee8b287
docs: define APSData dictionary inventory
tmc Aug 13, 2026
f9ed279
perfettosql: identify raw profiler artifacts
tmc Aug 13, 2026
1eb30a3
docs: define raw profiler artifact identity
tmc Aug 13, 2026
734223f
perfettosql: expose raw timeline headers
tmc Aug 13, 2026
960cfdf
docs: define raw timeline header evidence
tmc Aug 13, 2026
660398a
capture: retain timing without trace commands
tmc Aug 13, 2026
038a751
perfetto: expose live kernel timing
tmc Aug 13, 2026
9fefd02
perfetto: decode fixed GPRWCNTR fields
tmc Aug 13, 2026
f79883d
perfetto: retain raw counter payloads
tmc Aug 13, 2026
8c79a04
perfetto: expose counter batch identity
tmc Aug 14, 2026
e3af023
perfetto: retain counter pass catalog
tmc Aug 14, 2026
48ffba3
timeline: use exact profiler sample carriers
tmc Aug 14, 2026
536ca1c
perfetto: retain counter trace identities
tmc Aug 14, 2026
6eaec7f
perfetto: preserve unsigned counter trace IDs
tmc Aug 14, 2026
98198f7
perfetto: retain fixed streamData tables
tmc Aug 14, 2026
817d644
perfetto: distinguish malformed streamData tables
tmc Aug 14, 2026
35adb0a
perfetto: retain streamData strings
tmc Aug 14, 2026
a2266ac
perfetto: retain pipeline compiler diagnostics
tmc Aug 14, 2026
0651fd9
perfetto: preserve pipeline statistic presence
tmc Aug 14, 2026
3393cfc
capture: finalize traces when Go exits
tmc Aug 14, 2026
b1bf3f7
perfetto: structure pipeline compiler remarks
tmc Aug 14, 2026
659fee8
perfetto: retain compiler remark arguments
tmc Aug 14, 2026
741e9c8
perfetto: retain counter encoder aggregates
tmc Aug 14, 2026
fa4d9c7
perfetto: retain attributed counter samples
tmc Aug 14, 2026
866467a
perfetto: identify APSData blobs
tmc Aug 14, 2026
45e38bd
perfetto: inventory streamData archives
tmc Aug 14, 2026
ebf1513
perfetto: retain archive value descriptors
tmc Aug 14, 2026
3c2dd54
perfetto: project nested archive values
tmc Aug 14, 2026
e0e3643
perfetto: expose shader address mappings
tmc Aug 14, 2026
9a254e8
perfetto: relate mappings to encoders
tmc Aug 14, 2026
e78871d
perfetto: expose recorded profiler configuration
tmc Aug 14, 2026
35e0356
perfetto: expose recorded profiler setup
tmc Aug 14, 2026
ac413af
perfetto: inventory profiler carriers
tmc Aug 14, 2026
d449cea
perfetto: expose all root scalar values
tmc Aug 14, 2026
d075d3e
perfetto: audit root scalar equality
tmc Aug 14, 2026
f398478
perfetto: audit profiler carrier sequences
tmc Aug 14, 2026
e634cba
perfetto: audit shader binary content
tmc Aug 14, 2026
c27e839
perfetto: audit embedded payload content
tmc Aug 14, 2026
2f1ec51
perfetto: report native-label and sidecar name conflicts
tmc Aug 14, 2026
faa828f
perfetto: add fixture qualification and UI smoke gates
tmc Aug 14, 2026
26673e2
perfetto: freeze the v1 contract surface
tmc Aug 14, 2026
ffe9cdb
perfetto: add pipeline-first dispatch view
tmc Aug 14, 2026
0c769c7
perfetto: qualify pipeline-first rendering
tmc Aug 14, 2026
5ac48e2
build: gate darwin-only packages behind //go:build darwin
tmc Aug 23, 2026
4846541
test: skip darwin-behavior tests off darwin
tmc Aug 23, 2026
2d79f44
go.mod: depend on github.com/tmc/lib/nvidia
tmc Aug 23, 2026
4918437
cmd/gputrace: add nvidia command reporting GPU status via NVML
tmc Aug 23, 2026
8bf93dc
internal/cuptitrace: convert CUPTI activity captures to Perfetto traces
tmc Aug 23, 2026
f4bc8b1
cmd/gputrace: add cupti command for Linux kernel tracing
tmc Aug 23, 2026
5a4c8e8
docs: document the Linux/NVIDIA surface
tmc Aug 23, 2026
0a74e06
gpuevent: extract vendor-neutral activity model
tmc Aug 23, 2026
167e15c
cmd/gputrace: add devices command with backend capability registry
tmc Aug 23, 2026
1486d82
gpuevent: derive per-kernel metrics and optimization findings
tmc Aug 23, 2026
fcce09e
cmd/gputrace: add analyze command reporting optimization findings
tmc Aug 23, 2026
4aeaf09
optimize: add reproducible workload run harness
tmc Aug 23, 2026
6bc6f41
optimize: compare runs with noise-aware verdicts
tmc Aug 23, 2026
36a4609
optimize: add findings-to-actions playbook
tmc Aug 23, 2026
aac2e18
cmd/gputrace: add --suggest to analyze for playbook actions
tmc Aug 23, 2026
65605c0
docs: document the agentic optimization loop and NVIDIA skill reference
tmc Aug 23, 2026
5b40707
cmd/gputrace: native Linux CUPTI capture via preloaded shim
tmc Aug 23, 2026
13debdc
cmd/gputrace: run the NVML sampler during capture --samples
tmc Aug 23, 2026
82e9238
docs: point agents at native capture and bundle inputs
tmc Aug 23, 2026
74ea4ee
optimize: compare kernel activity between captures
tmc Aug 23, 2026
8aec656
capture: fix nvml_sampler invocation; add extended sampler source
tmc Aug 26, 2026
934bedb
cupticapture: concurrent-first kernel activity and latency timestamps
tmc Aug 26, 2026
feced95
gpuevent: decode API, clock-sync, and capture-meta records
tmc Aug 26, 2026
6a26940
tools: host nvml_sampler in-tree
tmc Aug 26, 2026
db5ce95
cupticapture: record hardware provenance in meta.json
tmc Aug 26, 2026
513f990
cmd/gputrace: surface launch overhead in analyze with --api capture
tmc Aug 26, 2026
d40d9a8
cupticapture: per-PID event shards for multi-process targets
tmc Aug 26, 2026
38a0173
cupti: pprof export and richer Perfetto projection for CUDA captures
tmc Aug 26, 2026
6f5e96f
tools: relocate nvml_sampler source to its own package
tmc Aug 26, 2026
f33a2d2
cupticapture: memcpy memory kinds, guarded exit flush, shim cleanup
tmc Aug 26, 2026
151ef87
gpuevent: kernel richness, theoretical occupancy, stream tracks, new …
tmc Aug 26, 2026
ed9dab5
gitignore: exclude local capture artifacts
tmc Aug 27, 2026
55156f9
gpuevent: span attribution and per-span decomposition
tmc Aug 27, 2026
0afd0c8
docs: add CUPTI capture roadmap
tmc Aug 27, 2026
f551786
docs/research: GB10 findings and macOS counter-oracle notes
tmc Aug 27, 2026
fe6a1cc
gpuevent: translate unix-clock spans via clock_sync
tmc Aug 27, 2026
0ca9f6c
cmd/gputrace: register --api beside the other Linux-only flags
tmc Aug 27, 2026
bebf663
all: gofmt
tmc Aug 27, 2026
0ebbf7a
darwin: follow the regenerated apple bindings
tmc Aug 28, 2026
1e827d2
internal/replay: account for ICB executions in the flatten test
tmc Aug 28, 2026
0005775
gpuevent: clock-safe launch latency, idle budget, NVTX and graph attr…
tmc Aug 29, 2026
419a1c5
cmd/gputrace: add doctor to diagnose the profiling environment
tmc Aug 29, 2026
eb30549
cmd/gputrace: compare CUDA captures with diff
tmc Aug 29, 2026
bab68c0
cmd/gputrace: escalate hot kernels to ncu, measure the shim's own cost
tmc Aug 29, 2026
6aecf2d
docs: record the GB10 toolchain findings behind the new commands
tmc Aug 29, 2026
7fd4ecc
gpuevent: try every libcupti candidate when probing for tracing
tmc Aug 29, 2026
26354ec
docs/research: node-mode graph tracing fails on MLX, not on HES
tmc Aug 29, 2026
d43aa0b
cupticapture: flush CUPTI periodically so uninterposable targets capture
tmc Aug 30, 2026
c232fb1
cupticapture: flush with FlushAll, not FlushPeriod
tmc Aug 30, 2026
682c0d9
cmd/gputrace: stream the target's stderr during capture
tmc Aug 30, 2026
984463c
gpuevent: stack kernels under the spans that enclose them
tmc Aug 30, 2026
e5f1103
cudagraphdot: parse MLX CUDA-graph DOT dumps
tmc Aug 30, 2026
1808edc
perfetto: name the device from the trace, not the writer
tmc Aug 30, 2026
bc89089
cmd/gputrace: export CUDA captures and graph dumps as pprof
tmc Aug 30, 2026
6263dc4
cupticapture: query CUPTI's dropped-record count
tmc Aug 30, 2026
28ff4a4
gpuevent: measure whether a capture kept every record
tmc Aug 30, 2026
9537819
cmd/gputrace: state what a capture holds before reporting on it
tmc Aug 30, 2026
260e20f
gpuevent: keep the last clock_sync, not the first
tmc Aug 30, 2026
361053f
gpudoctor: tell a staged profiling setting from an absent one
tmc Aug 30, 2026
c84a18b
cmd/gputrace: profile each escalated kernel in its own ncu run
tmc Aug 30, 2026
29c8afa
cmd/gputrace, internal/gate: add gate command for capture validity
tmc Aug 30, 2026
33168bb
cmd/gputrace: make absence reporting explicit in analyze, summary, an…
tmc Aug 30, 2026
2dc5c76
cmd/gputrace, internal/gate, docs/research: refine gate output and do…
tmc Aug 30, 2026
3470514
docs/research, cmd/gputrace: add real mlx-lm decode invariant provena…
tmc Aug 30, 2026
14d80dd
docs/research, testdata: document CUDA workload invariants and add te…
tmc Aug 30, 2026
00d0ae8
testdata/harness: document nvcc build flags and usage modes
tmc Aug 30, 2026
bf36070
cmd/gputrace, internal/gate: add two-bundle gate --compare residency …
tmc Aug 30, 2026
abf3b85
gate: label replay-derived stationarity, add units and compare dispat…
tmc Aug 30, 2026
d52b8f7
gate: nested-range monotonicity check via --ranges
tmc Aug 30, 2026
e03c31f
capture, gate: host provenance sidecar and cross-session labeling
tmc Aug 30, 2026
8dddb1d
cmd/gputrace: label cross-host capture comparisons in diff paths
tmc Aug 30, 2026
7601de6
gate: live command-buffer stationarity from the timing sidecar
tmc Aug 30, 2026
72c027c
trace: decode MTLResourceOptions from buffer-creation records
tmc Aug 30, 2026
7565150
cmd/gputrace, counter: one decoder for Metal kernel display names
tmc Aug 30, 2026
dfb7d9e
docs: residency A/B observation, python mlx-lm vs mlx-go on Qwen3
tmc Aug 30, 2026
607022e
docs: record that unified-memory counters cannot work on GB10
tmc Aug 30, 2026
e64174a
gpuevent: stop calling the two completeness checks independent
tmc Aug 30, 2026
381f8df
gpuevent: an empty capture is never complete
tmc Aug 30, 2026
e8b5939
cmd/gputrace, gate: gofmt
tmc Aug 30, 2026
61fb831
gputrace: address mlx-swift audit findings
tmc Aug 30, 2026
c844d4a
gate: make block-size auto reachable and report the effective block
tmc Aug 30, 2026
b48563a
gputrace: report storage-mode footprint and residency together
tmc Aug 31, 2026
fecdf03
trace: count buffers across the whole capture
tmc Aug 31, 2026
40a3953
gputrace: say which buffer population each command counts
tmc Aug 31, 2026
b4b53e7
gate: an overshoot is not a shortfall
tmc Aug 31, 2026
db147ce
gpuevent: compare captures by launch geometry, not by symbol
tmc Aug 31, 2026
dedfdd8
cupti: anchor exported traces to CLOCK_REALTIME so two can be compared
tmc Aug 31, 2026
fca6ee1
profiler, shaders: report shader compilation time
tmc Aug 31, 2026
b543e94
profiler: say how much of the counter stream this capture owns
tmc Aug 31, 2026
044dcac
analysis: buffer bindings group by CS ordinal, not by encoder
tmc Aug 31, 2026
66a6185
cupti: share tracks for repeated spans
tmc Aug 31, 2026
418c4e8
profiler: name the absent compile records instead of implying a cache…
tmc Aug 31, 2026
3bef950
docs: record that Compile Performance measures no compiler phase
tmc Aug 31, 2026
2189499
cupti: expose pre-span API launches
tmc Aug 31, 2026
2693b61
gate: count the timing marks the sidecar could not supply
tmc Aug 31, 2026
7cb1361
timeline: keep the -1 compiler sentinel out of the duration columns
tmc Aug 31, 2026
2968d08
make: report the tests that did not run
tmc Aug 31, 2026
88def2c
docs: name the two perf fixtures and say not to commit them
tmc Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ jobs:
go-version-file: go.mod
check-latest: true

- name: Check formatting
run: |
unformatted=$(gofmt -l $(git ls-files '*.go'))
if [ -n "$unformatted" ]; then
echo "These files are not gofmt-formatted; run 'make fmt':"
echo "$unformatted"
exit 1
fi

- name: Vet
run: go vet ./...

Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ gputrace_bin
# Local watch/debug artifacts
watch_*
beads.svg
brain/

# Capture artifacts
*.pprof
*.pftrace
*.gpucapture/
.hermes/
39 changes: 37 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,51 @@ AXPERMS_BIN := $(HOME)/go/bin/axperms
BUNDLE_ID := com.tmc.gputrace
AXPERMS_BUNDLE_ID := com.github.tmc.gputrace.axperms

.PHONY: all build test vet install reinstall clean sign-bundle setup-permissions reset-permissions fullreinstall reset test-permissions axperms setup-axperms help
.PHONY: all build test vet fmt checkfmt check install reinstall clean sign-bundle setup-permissions reset-permissions fullreinstall reset test-permissions axperms setup-axperms help

GO_FILES = $(shell git ls-files '*.go')

all: build

build:
go install ./cmd/gputrace

# test reports how many cases it skipped, because "ok" and a skip are the same
# line in go test's default output. Most of the skips are opt-in integration
# tests waiting on an environment variable (see docs/TESTING.md); a suite that
# says ok while a third of it sat out is telling the truth and meaning less
# than it reads.
test:
go test ./...
@go test -json ./... | go run ./internal/cmd/testcensus

# test-gated reports which opt-in variables are set and which are not, so the
# skip count above is attributable rather than merely known.
test-gated:
@echo "Opt-in test variables (see docs/TESTING.md):"
@for v in TRACE_PROCESSOR_SHELL GPUTRACE_TEST_TRACE GPUTRACE_MIO_SETUP_DATA_PATH \
GPUTRACE_PERF_FIXTURE GPUTRACE_TEST_METALLIB GPUTRACE_PARITY_TRACE; do \
eval val=\$$$$v; \
if [ -n "$$val" ]; then echo " set $$v=$$val"; else echo " unset $$v"; fi; \
done
@echo "Unset variables leave their tests skipped; go test reports that as ok."

vet:
go vet ./...

fmt:
gofmt -w $(GO_FILES)

# checkfmt fails instead of rewriting, so CI and pre-push can use it.
checkfmt:
@unformatted=$$(gofmt -l $(GO_FILES)); \
if [ -n "$$unformatted" ]; then \
echo "These files are not gofmt-formatted; run 'make fmt':"; \
echo "$$unformatted"; \
exit 1; \
fi

check: checkfmt vet test

install: clean build setup-permissions
@echo "Reinstall complete with fresh permissions"

Expand Down Expand Up @@ -149,6 +181,9 @@ help:
@echo " build - Build gputrace"
@echo " test - Run Go tests"
@echo " vet - Run go vet"
@echo " fmt - Rewrite tracked Go files with gofmt"
@echo " checkfmt - Fail if any tracked Go file is unformatted"
@echo " check - checkfmt + vet + test"
@echo " reinstall - Rebuild binary and refresh signed app bundle"
@echo " fullreinstall - Clean + rebuild + fresh permissions (resets TCC)"
@echo " clean - Remove app bundle (forces macgo to recreate)"
Expand Down
600 changes: 597 additions & 3 deletions README.md

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions api_surface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ var (
_ func(*gputrace.Trace) ([]*gputrace.EncoderTiming, error) = gputrace.ExtractTimingData
_ func(*gputrace.Trace) (*timing.Store0TimingData, error) = gputrace.ExtractStore0Timing
_ func(*gputrace.Trace, *timing.Store0TimingData) []*gputrace.EncoderTiming = gputrace.ConvertStore0ToEncoderTimings
_ func(*gputrace.Trace) []*gputrace.EncoderTiming = gputrace.GenerateSyntheticTiming
_ func(*gputrace.Trace) (*gputrace.ShaderMetricsReport, error) = gputrace.ExtractShaderMetrics
_ func(...string) *gputrace.ShaderSourceMapper = gputrace.NewShaderSourceMapper
_ func(io.Writer, *gputrace.ShaderMetricsReport) error = gputrace.FormatShadersSimple
Expand Down Expand Up @@ -71,9 +70,6 @@ func TestFacadeCalls(t *testing.T) {
if _, err := gputrace.ExtractStatistics(trace); err != nil {
t.Fatalf("ExtractStatistics: %v", err)
}
if timings := gputrace.GenerateSyntheticTiming(trace); len(timings) == 0 {
t.Fatal("GenerateSyntheticTiming returned no timings")
}
if extractor := gputrace.NewTimingMetricsExtractor(trace); extractor == nil {
t.Fatal("NewTimingMetricsExtractor returned nil")
}
Expand Down
28 changes: 23 additions & 5 deletions api_timing.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ func ConvertStore0ToEncoderTimings(t *Trace, store0Data *timing.Store0TimingData
return timing.ConvertStore0ToEncoderTimings(t, store0Data)
}

// GenerateSyntheticTiming generates synthetic timing data for t.
func GenerateSyntheticTiming(t *Trace) []*EncoderTiming {
return timing.GenerateSyntheticTiming(t)
}

// NewTimingMetricsExtractor returns a timing metrics extractor for t.
func NewTimingMetricsExtractor(t *Trace) *TimingMetricsExtractor {
return timing.NewTimingMetricsExtractor(t)
Expand All @@ -36,6 +31,29 @@ func FormatTimingMetrics(metrics *TimingMetrics) string {
return timing.FormatTimingMetrics(metrics)
}

// LowSampleMarker follows a row measured from a single dispatch.
const LowSampleMarker = timing.LowSampleMarker

// TimingSourceUnavailable marks a trace that carries no timing measurement at
// all, as distinct from one measured approximately.
const TimingSourceUnavailable = timing.TimingSourceUnavailable

// LowSampleFootnote explains LowSampleMarker, or returns "" when unused.
func LowSampleFootnote(timings []*KernelTiming) string {
return timing.LowSampleFootnote(timings)
}

// FilterMinCalls keeps rows measured from at least min dispatches and reports
// how many it dropped.
func FilterMinCalls(timings []*KernelTiming, min int) ([]*KernelTiming, int) {
return timing.FilterMinCalls(timings, min)
}

// MinCallsNote states what a --min-calls filter removed.
func MinCallsNote(min, dropped, total int) string {
return timing.MinCallsNote(min, dropped, total)
}

// ExportTimingMetricsJSON writes timing metrics as JSON.
func ExportTimingMetricsJSON(w io.Writer, metrics *TimingMetrics) error {
return timing.ExportTimingMetricsJSON(w, metrics)
Expand Down
29 changes: 29 additions & 0 deletions api_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,42 @@ import (
"io"

"github.com/tmc/gputrace/internal/command"
"github.com/tmc/gputrace/internal/trace"
)

// IsLibraryUUID reports whether label identifies a Metal library rather than a
// function.
func IsLibraryUUID(label string) bool {
return trace.IsLibraryUUID(label)
}

// IsArchiveFunctionName reports whether name identifies a function only by the
// shader archive it came from. A capture records an archive's content id where
// it records a function name for a library the capture describes, so such a
// kernel has a distinct, stable identity but no readable name. Only the
// profiler's streamData carries the name.
func IsArchiveFunctionName(name string) bool {
return trace.IsArchiveFunctionName(name)
}

// ParseDetailedCommandBuffer parses command buffer cbIndex from t.
//
// It reads and rescans the whole capture file on every call. Use OpenCapture
// when walking more than one command buffer.
func ParseDetailedCommandBuffer(t *Trace, cbIndex int) (*command.DetailedCommandBuffer, error) {
return command.ParseDetailedCommandBuffer(t, cbIndex)
}

// Capture holds a capture file and its command-buffer index for repeated
// detailed parses.
type Capture = command.Capture

// OpenCapture reads t's capture file and command-buffer index once, so that
// walking every command buffer does not reread the file per buffer.
func OpenCapture(t *Trace) (*Capture, error) {
return command.OpenCapture(t)
}

// DumpCommandBuffer writes command buffer cbIndex from t to w.
func DumpCommandBuffer(t *Trace, w io.Writer, cbIndex int) error {
return command.DumpCommandBuffer(t, w, cbIndex)
Expand Down
40 changes: 40 additions & 0 deletions capture/capture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Package capture runs a Metal workload under the GPUToolsCapture interposer.
package capture

import (
"context"
"io"

internal "github.com/tmc/gputrace/internal/capture"
)

// ErrNotInterposable reports that dyld will not load the capture interposer
// into the target executable.
var ErrNotInterposable = internal.ErrNotInterposable

// Options configure a capture run.
type Options struct {
// Output is the .gputrace bundle to create.
Output string
// Dir is the workload's working directory. Empty inherits the caller's.
Dir string
// Env adds environment entries in KEY=value form.
Env []string
// Stdout and Stderr receive workload output. Nil discards it.
Stdout io.Writer
Stderr io.Writer
}

// Eligible reports whether dyld will honor the capture interposer for path.
func Eligible(path string) error { return internal.Eligible(path) }

// Run executes argv under the capture interposer and returns the trace path.
func Run(ctx context.Context, opts Options, argv ...string) (string, error) {
return internal.Run(ctx, internal.Options{
Output: opts.Output,
Dir: opts.Dir,
Env: opts.Env,
Stdout: opts.Stdout,
Stderr: opts.Stderr,
}, argv...)
}
26 changes: 18 additions & 8 deletions cmd/axperms/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ import (

//

// openSettingsPane opens a System Settings pane with `open`. A failure is not
// fatal: every caller also prints instructions or falls back to polling. It
// must not be silent though, or a headless run sleeps and then reports a
// confusing downstream error instead of the actual cause.
func openSettingsPane(url string) {
if err := exec.Command("open", url).Run(); err != nil {
fmt.Fprintf(os.Stderr, "warning: could not open %s: %v\n", url, err)
}
}

var (
axIsProcessTrusted func() bool
axIsProcessTrustedWithOptions func(uintptr) bool
Expand Down Expand Up @@ -172,17 +182,17 @@ func main() {
}

if *openSettings {
exec.Command("open", paneURLs[PaneAccessibility]).Run()
openSettingsPane(paneURLs[PaneAccessibility])
return
}

if *openScreenRecording {
exec.Command("open", paneURLs[PaneScreenRecording]).Run()
openSettingsPane(paneURLs[PaneScreenRecording])
return
}

if *openFDA {
exec.Command("open", paneURLs[PaneFullDiskAccess]).Run()
openSettingsPane(paneURLs[PaneFullDiskAccess])
return
}

Expand Down Expand Up @@ -261,7 +271,7 @@ func main() {
if !axIsProcessTrusted() {
fmt.Fprintf(os.Stderr, "\nPlease grant Accessibility permission to axperms in System Settings,\n")
fmt.Fprintf(os.Stderr, "then run this command again.\n")
exec.Command("open", paneURLs[PaneAccessibility]).Run()
openSettingsPane(paneURLs[PaneAccessibility])
os.Exit(1)
}
}
Expand Down Expand Up @@ -438,7 +448,7 @@ func findAppInPrivacyList(appName string, paneURL string) (found bool, enabled b
if debugMode {
fmt.Printf("[DEBUG] Opening pane: %s\n", paneURL)
}
exec.Command("open", paneURL).Run()
openSettingsPane(paneURL)
time.Sleep(1 * time.Second)

pid := findSystemSettingsPID()
Expand Down Expand Up @@ -559,7 +569,7 @@ func listPrivacyApps(paneName string, paneURL string) {
pid := findSystemSettingsPID()
if pid == 0 {
fmt.Println("System Settings not running. Opening...")
exec.Command("open", paneURL).Run()
openSettingsPane(paneURL)
time.Sleep(2 * time.Second)
pid = findSystemSettingsPID()
if pid == 0 {
Expand Down Expand Up @@ -759,7 +769,7 @@ func findRowForApp(appName string, paneURL string) (found bool, row uintptr) {
pid := findSystemSettingsPID()
if pid == 0 {
fmt.Println("System Settings not running. Opening...")
exec.Command("open", paneURL).Run()
openSettingsPane(paneURL)
time.Sleep(2 * time.Second)
pid = findSystemSettingsPID()
if pid == 0 {
Expand Down Expand Up @@ -922,7 +932,7 @@ func watchPermission() {
fmt.Println("Please grant Accessibility permission in System Settings.")

// Open settings
exec.Command("open", "x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Accessibility").Run()
openSettingsPane("x-apple.systempreferences:com.apple.settings.PrivacySecurity.extension?Privacy_Accessibility")

// Trigger initial prompt
triggerPrompt()
Expand Down
Loading
Loading