[PATCH 16/17] tools/arch/x86/pmtctl: Add README.md
From: David E. Box
Date: Mon May 25 2026 - 21:49:08 EST
Add the user-facing README documenting pmtctl usage, supported
metric sources, and command-line options.
Signed-off-by: David E. Box <david.e.box@xxxxxxxxxxxxxxx>
---
tools/arch/x86/pmtctl/README.md | 276 ++++++++++++++++++++++++++++++++
1 file changed, 276 insertions(+)
create mode 100644 tools/arch/x86/pmtctl/README.md
diff --git a/tools/arch/x86/pmtctl/README.md b/tools/arch/x86/pmtctl/README.md
new file mode 100644
index 000000000000..0827ff20fc86
--- /dev/null
+++ b/tools/arch/x86/pmtctl/README.md
@@ -0,0 +1,276 @@
+# pmtctl
+Intel Platform Monitoring Technology (PMT) command-line tool for Linux
+
+## Overview
+
+pmtctl is a small command-line utility to query Intel Platform Monitoring
+Technology (PMT) metrics via the telem telemetry interface. It can load
+metric definitions from JSON files or use built-in definitions.
+
+The project is split into a CLI frontend and a reusable library:
+
+- `src/`: CLI frontend (`pmtctl`, commands, formatting, pager)
+- `lib/`: reusable PMT library implementation (`libpmtctl_core.a`)
+ - transport/enumeration/binding core
+ - metric DB container operations
+ - built-in and runtime-JSON metric-definition providers
+
+Core ownership model:
+
+- Core library owns PMT source selection, device enumeration, telem reads,
+ metric DB container operations, and both metric-definition providers
+ (built-in compiled defs and runtime JSON parsing/loading).
+
+## Prerequisites
+
+- A C toolchain (gcc/clang)
+- make
+- python3 (for JSON metric generation)
+- libjansson (JSON parsing library)
+- Linux (dev/test on systems with `/sys/bus/auxiliary/drivers/pmt_telemetry` for telem)
+
+## Build Instructions
+
+The built-in metrics pipeline has two opt-in stages, then the build:
+
+```text
+Intel-PMT repo (XML) --[pmtxml2json.py]--> defs/*.json
+ |
+ [gen_builtin_defs.py]
+ v
+ generated/builtin_defs.c --> make --> pmtctl
+```
+
+Each stage is a separate Make target so a routine `make` never hits the
+network and never re-runs codegen unnecessarily.
+
+### Option 1: Build with built-in metrics (recommended)
+
+First-time setup (the `defs-json-fetch` step git clones the Intel-PMT repo into
+`~/.cache/pmtctl` and converts every aggregator XML to perf-style JSON):
+
+```bash
+make defs-json-fetch # git clone Intel-PMT (cached) and produce defs/*.json
+make defs # JSON -> generated/builtin_defs.c
+make # build pmtctl with built-in metric definitions
+```
+
+If you already have JSON files of your own, drop them under `defs/`
+and skip straight to `make defs && make`.
+
+To update from upstream Intel-PMT later:
+
+```bash
+make defs-json-pull # git pull the cache and regenerate JSON
+make defs # regenerate generated/builtin_defs.c
+make # rebuild
+```
+
+### Option 2: Build without built-in metrics
+
+If you don't have metric JSONs or prefer to load them at runtime:
+
+```bash
+make
+```
+
+This uses the empty stub (`lib/builtin_defs_empty.c`); load metrics at
+runtime with `-J/--json-file`.
+
+### Make targets (summary)
+
+| Target | Purpose |
+|---------------------|----------------------------------------------------|
+| `all` (default) | Build `pmtctl` and `libpmtctl_core.a` |
+| `defs-json-fetch` | git clone Intel-PMT (cached) and emit `defs/*.json` |
+| `defs-json-pull` | Same as above, but git pull the cache first |
+| `defs` | Generate `generated/builtin_defs.c` from JSON |
+| `defs-clean` | Remove `defs/` and `generated/builtin_defs.c` |
+| `clean` | Remove build outputs (keeps `defs/` intact) |
+| `install` / | Install or remove `pmtctl`, lib, headers, .pc |
+| `uninstall` | |
+
+Useful variables (override on the make command line):
+
+- `PYTHON` — Python interpreter (default `python3`)
+- `DEFS_DIR` — JSON output / input directory (default `defs`)
+- `GENERATED_DIR` — codegen output directory (default `generated`)
+- `PMT_CACHE_DIR` — Intel-PMT clone cache (default `~/.cache/pmtctl`)
+
+### Library artifacts produced
+
+Building `make` also builds the static library artifact under
+`build/<build-type>/lib/`:
+
+- `libpmtctl_core.a`
+
+## Usage (examples)
+
+General form:
+
+```text
+pmtctl [global options] <command> [command options]
+```
+
+Global options:
+
+- `-h, --help` Show help and exit
+- `-V, --version` Show version and exit
+- `-b, --source <mode>` Data source: `telem` (pmu support is pending upstream driver availability)
+- `-J, --json-file <path>` Path to metrics JSON (file or directory) — loads metrics at runtime
+- `-d, --device <selector>` Restrict to single endpoint (guid or ep name)
+
+Note: Metrics can be loaded in two ways:
+1. **Built-in** (compiled during build) — see "Build with JSON metrics" above
+2. **Runtime** (loaded via `-J` option) — useful for testing or using different metric sets
+
+Commands:
+
+- `list` — list known metrics and/or discovered devices
+- `stat` — sample/stream metrics over time (similar to `perf stat`)
+
+Examples (basic):
+
+```bash
+# list all metrics with built-in or runtime-loaded definitions
+./pmtctl list
+
+# list with GUIDs (useful for debugging metric definitions)
+./pmtctl list --guids
+
+# load metrics from a directory at runtime
+./pmtctl -J /path/to/metrics/ list --guids
+
+# load metrics from a single JSON file at runtime
+./pmtctl -J /path/to/metrics.json list --guids
+
+# list devices only
+./pmtctl list --devices
+
+# keep the last pager screen on exit (useful before running stat)
+./pmtctl list -X
+
+# sample a named metric at the default 1 s interval
+sudo ./pmtctl stat -e temp_socket
+
+# sample at 500 ms intervals
+sudo ./pmtctl stat -e socket_power --interval 500
+
+# take a single snapshot and exit
+sudo ./pmtctl stat -e fw_version_0 --once
+
+# sample multiple metrics (one line per metric per sample)
+sudo ./pmtctl stat -e temp_socket -e socket_power --vertical
+
+# restrict to a specific device by GUID
+sudo ./pmtctl -d guid=22806802 stat -e temp_core0
+
+# read raw sample data by sample id (no metric definitions required)
+sudo ./pmtctl stat --raw id=0,lsb=0,msb=31 --count 2
+
+# read multiple raw samples with bit slicing
+sudo ./pmtctl stat --raw id=2,msb=7 --raw id=3,lsb=8,msb=15
+
+# output values in hex
+sudo ./pmtctl stat -e fw_version_0 --once --hex
+```
+
+See `pmtctl_cli_spec.txt` in the repository root for the full CLI
+specification and additional example usage.
+
+## Developer Notes
+
+### Adding new C source files
+
+If you add new `.c` files:
+
+- CLI/frontend code goes in `src/` and is added to top-level `Makefile` `SRC`.
+- Reusable library core code goes in `lib/` and is added to `lib/Makefile`
+ `CORE_SRC`.
+- Built-in provider code goes in `lib/` and is added to `lib/Makefile`
+ `BUILTIN_OBJ` inputs.
+- JSON provider code goes in `lib/` and is added to `lib/Makefile` `JSON_OBJ`
+ inputs.
+
+This keeps transport and provider policy boundaries explicit.
+
+### Regenerating metrics from JSON
+
+The Makefile recursively tracks `*.json` under `defs/` (so per-platform
+subdirectories produced by `pmtxml2json.py` are picked up automatically):
+
+```bash
+# Re-generate after editing or adding JSON under defs/
+make defs
+
+# Throw away converted JSON + codegen output (does NOT touch the
+# Intel-PMT cache under ~/.cache/pmtctl)
+make defs-clean
+```
+
+`make clean` intentionally does *not* remove `defs/` — the XML->JSON step
+can be slow, so use `make defs-clean` when you really want to start over.
+
+The `scripts/gen_builtin_defs.py` script also runs standalone and accepts
+both files and directories:
+
+```bash
+python3 scripts/gen_builtin_defs.py defs/ > generated/builtin_defs.c
+```
+
+## PMTXML2JSON Conversion
+
+`scripts/pmtxml2json.py` turns Intel PMT XML definitions into pmtctl /
+perf-style JSON. The `make defs-json-fetch` target wraps the common case;
+invoke the script directly for one-off workflows:
+
+```bash
+# convert all XML groups under a local Intel-PMT xml tree
+python3 scripts/pmtxml2json.py --by-path /path/to/Intel-PMT/xml --output-dir defs
+
+# auto-fetch Intel-PMT into cache, then convert from the fetched xml directory
+python3 scripts/pmtxml2json.py --fetch-pmt-repo --output-dir defs
+
+# refresh the cached Intel-PMT repository before converting
+python3 scripts/pmtxml2json.py --fetch-pmt-repo --refresh-pmt-repo --output-dir defs
+```
+
+Fetch/cache behavior:
+
+- `--fetch-pmt-repo` is opt-in and preserves existing local-path workflows.
+- Default cache location is `~/.cache/pmtctl` (override with `--pmt-cache-dir`).
+- `--refresh-pmt-repo` only works with `--fetch-pmt-repo` and updates the cache explicitly.
+
+If `--fetch-pmt-repo` is used without a positional XML file and without
+`--by-path`, the converter automatically uses the fetched Intel-PMT `xml/`
+directory as the discovery root.
+
+## Install and Export
+
+Minimal install/export support is available for the CLI and static libraries:
+
+```bash
+# Stage install output
+make DESTDIR=$PWD/stage install
+```
+
+Installs:
+
+- `bin/pmtctl`
+- `lib/libpmtctl_core.a`
+- `include/pmtctl/{pmtctl.h,metrics_db.h,device.h}`
+- `lib/pkgconfig/libpmtctl-core.pc`
+
+Uninstall:
+
+```bash
+make DESTDIR=$PWD/stage uninstall
+```
+
+## Testing
+
+Stat commands require elevated privileges to read telemetry files:
+
+```bash
+sudo ./pmtctl stat -e <metric_name>
+```
--
2.43.0