|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Environment |
| 6 | + |
| 7 | +- Python 3.13+ required. Dependencies managed by [`uv`](https://docs.astral.sh/uv/); `uv sync` creates `.venv` and installs dev deps (pytest). |
| 8 | +- Runtime dependencies list is empty (stdlib only); pytest is the sole dev dependency. |
| 9 | + |
| 10 | +## Common commands |
| 11 | + |
| 12 | +```bash |
| 13 | +uv sync # create venv, install deps |
| 14 | +uv run main.py --help # list registered tools |
| 15 | +uv run main.py converter <csv> [-o out.json | --output-dir dir/] |
| 16 | +uv run main.py split-renderstage <input.pftrace> <output.pftrace> |
| 17 | +uv run main.py split-renderstage --debug <input.pftrace> |
| 18 | + |
| 19 | +uv run python -m tools.converter.convert_sdp_csv_to_perfetto_json <csv> # bypass dispatcher |
| 20 | +uv run python -m tools.converter.split_renderstage_by_process <input.pftrace> <output.pftrace> |
| 21 | +uv run split-renderstage-by-process <input.pftrace> <output.pftrace> # console script |
| 22 | + |
| 23 | +uv run pytest # full suite |
| 24 | +uv run pytest -v |
| 25 | +uv run pytest tests/test_convert_sdp_csv_to_perfetto_json.py::TestExampleCSV -v |
| 26 | +``` |
| 27 | + |
| 28 | +Commits must be DCO-signed (`git commit -s`). External PRs are scanned by Semgrep in CI. |
| 29 | + |
| 30 | +On Windows, if `uv run` fails while trying to remove `.venv\lib64` with `Access is denied`, close terminals/processes using `.venv`, remove and recreate `.venv` with `uv sync`, or use direct `python ...` invocation as a stdlib-only workaround for tools without runtime dependencies. |
| 31 | + |
| 32 | +## Architecture |
| 33 | + |
| 34 | +**Dispatcher pattern.** `main.py` is a thin CLI dispatcher. `TOOLS_REGISTRY` maps a tool name (e.g. `converter`) to a dotted module path; the dispatcher imports the module, rewrites `sys.argv` to hide its own name, then calls the module's `main()`. To add a new tool: create `tools/<name>/<module>.py` exposing `main()` that uses argparse, then add one line to `TOOLS_REGISTRY`. Each tool is independently invokable via `python -m ...` and is also registered as a console script in `pyproject.toml` (`[project.scripts]`). |
| 35 | + |
| 36 | +**Converter (`tools/converter/convert_sdp_csv_to_perfetto_json.py`).** The SDP CSV → Perfetto JSON pipeline auto-detects the CSV variant by inspecting the header row: |
| 37 | + |
| 38 | +- **Realtime** header has `Category`, `Metric`, `Timestamp` → `convert_realtime()`. Emits only counter events (`ph: "C"`). Synthesizes PIDs starting at `800000`, one per `(Process, Category)` pair. |
| 39 | +- **Trace** header has `Group`, `Track`, `TimestampStart` → `convert_trace()`. Emits duration slices (`ph: "X"`) and counters (`ph: "C"`). Uses *real* PIDs from the CSV for `Process` rows and synthesizes PIDs starting at `900000` for `System` rows (one per `Group`). Trace-mode conversion does a two-pass read: pass 1 finds main-thread names (rows where `TID == PID`) to label processes; pass 2 emits events. |
| 40 | + |
| 41 | +Counter vs slice disambiguation in trace mode is driven by the `Track` column: tracks containing `CounterValue` are explicit counters; rows with both `TimestampStart` and `TimestampEnd` are slices; rows with only one timestamp are treated as implicit counters. |
| 42 | + |
| 43 | +Output always wraps events as `{"traceEvents": [...]}` with metadata events (`ph: "M"`, `process_name`/`thread_name`) prepended. `_write_perfetto()` is the single write path; `_metadata_events()` is the single metadata builder — reuse these when adding new event sources rather than open-coding JSON structure. |
| 44 | + |
| 45 | +**Batch / glob handling.** `resolve_input_files()` expands glob patterns and deduplicates by normalized path. When multiple inputs are given, `-o` is ignored (warned) and each input is written next to itself (or into `--output-dir`) with the basename + `.json`. |
| 46 | + |
| 47 | +**RenderStage splitter (`tools/converter/split_renderstage_by_process.py`).** This tool reads binary Perfetto `.pftrace` files using stdlib-only protobuf decode/encode helpers. It extracts `GpuRenderStageEvent` packets, resolves each event to a process, groups slices by process, then appends new process-scoped RenderStage tracks to the output trace while preserving the original trace content. |
| 48 | + |
| 49 | +Process ownership resolution is prioritized as: packet `trusted_pid`, stage-spec descriptions like `Process <name> [<pid>]`, Vulkan queue submission IDs, Vulkan debug-utils device context, then GPU context fallback. Debug mode (`--debug <input.pftrace>`) scans packet fields, trusted PIDs, track descriptors, interned names, and sample RenderStage events without writing an output file. |
| 50 | + |
| 51 | +## Tests |
| 52 | + |
| 53 | +- Live in `tests/test_convert_sdp_csv_to_perfetto_json.py`. `test_main.py` is a backward-compat shim that re-exports the same tests so `pytest test_main.py` still works. |
| 54 | +- `tests/__init__.py` and `tools/__init__.py` exist so tests can import `tools.converter...` directly — keep them. |
0 commit comments