|
| 1 | +# skill.md — Claude working guide for mlperf-automations |
| 2 | + |
| 3 | +Compact task-oriented reference. Read AGENTS.md for full technical detail. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Mental model (read this first) |
| 8 | + |
| 9 | +``` |
| 10 | +mlcflow CLI → finds script by tags → resolves variations & deps → |
| 11 | + customise.py:preprocess() → run.sh → customise.py:postprocess() → |
| 12 | + caches new_env to ~/MLC/repos/local/cache/{uid}/ |
| 13 | +``` |
| 14 | + |
| 15 | +**Two repos, two roles:** |
| 16 | +- `mlperf-automations` (this repo) = content: 377 script directories + `automation/` engine |
| 17 | +- `mlcflow` = driver CLI: installs via pip, dynamically loads the engine above |
| 18 | + |
| 19 | +**Three key files per script:** |
| 20 | +- `meta.yaml` — identity, tags, deps, variations, env mapping (schema in `automation/script/meta_schema.py`) |
| 21 | +- `customize.py` — Python hooks: `preprocess()` builds the shell command; `postprocess()` reads results |
| 22 | +- `run.sh` — executes `eval "${MLC_MLPERF_ENDPOINT_CMD}"` and exits non-zero on failure |
| 23 | + |
| 24 | +--- |
| 25 | + |
| 26 | +## Task playbooks |
| 27 | + |
| 28 | +### "I need to understand what a script does" |
| 29 | + |
| 30 | +```bash |
| 31 | +cat script/<alias>/meta.yaml # tags, deps, variations, input_mapping |
| 32 | +cat script/<alias>/customize.py # what it validates and what command it builds |
| 33 | +cat script/<alias>/run.sh # what actually executes |
| 34 | +cat script/<alias>/README.md # human summary |
| 35 | +``` |
| 36 | + |
| 37 | +Key fields to read in meta.yaml: `tags`, `deps`, `variations`, `input_mapping`, |
| 38 | +`new_env_keys`, `default_env`. |
| 39 | + |
| 40 | +### "I need to add a new script" |
| 41 | + |
| 42 | +1. Scaffold with `mlc add script`: |
| 43 | + ```bash |
| 44 | + # Basic skeleton (copies template,generic) |
| 45 | + mlc add script mlcommons@mlperf-automations:<alias> --tags=<tags> |
| 46 | + |
| 47 | + # Copy nearest existing script as the template instead |
| 48 | + mlc add script mlcommons@mlperf-automations:<alias> --tags=<tags> \ |
| 49 | + --template_tags=app,mlperf,inference,reference |
| 50 | + ``` |
| 51 | + This creates `script/<alias>/` with `meta.yaml`, `customize.py`, and `run.sh`. |
| 52 | + If multiple scripts match `--template_tags`, it prompts you to pick one. |
| 53 | + |
| 54 | +2. Edit `meta.yaml` — update at minimum: |
| 55 | + - `alias`, `uid` (already generated), `tags`, `category` |
| 56 | + - `input_mapping` (CLI args → env vars) |
| 57 | + - `new_env_keys` (what this script promises to export) |
| 58 | + - `deps` chain |
| 59 | +3. Edit `customize.py` — implement `preprocess(i)`: |
| 60 | + - Guard required env vars (return `{'return':1,'error':'...'}` if missing) |
| 61 | + - Build the shell command string in `env['MY_CMD']` |
| 62 | +4. Edit `run.sh` — ensure it evals the command and exits non-zero on failure. |
| 63 | +5. `mlc lint script --tags=<alias>` — fix key order |
| 64 | +6. `mlct <alias>` — run built-in tests |
| 65 | +7. PR → `main` branch |
| 66 | + |
| 67 | +### "I need to add a variation" |
| 68 | + |
| 69 | +Add to `meta.yaml variations:`: |
| 70 | +```yaml |
| 71 | +variations: |
| 72 | + my-variant: |
| 73 | + group: my-group # omit group if stackable (free-standing) |
| 74 | + default: true # omit if not the default |
| 75 | + env: |
| 76 | + MY_ENV_VAR: value |
| 77 | + deps: |
| 78 | + - tags: get,extra,dep # extra dep only when this variation is active |
| 79 | +``` |
| 80 | +
|
| 81 | +Invoke: `mlcr <tags>,_my-variant` (underscore prefix on CLI). |
| 82 | + |
| 83 | +### "I need to add a conditional dependency" |
| 84 | + |
| 85 | +```yaml |
| 86 | +deps: |
| 87 | + - tags: get,cuda |
| 88 | + enable_if_env: |
| 89 | + MLC_MLPERF_DEVICE: [gpu, cuda] # only run if device is gpu or cuda |
| 90 | + - tags: get,rocm |
| 91 | + skip_if_env: |
| 92 | + MLC_HOST_OS_TYPE: [windows] # skip on Windows |
| 93 | +``` |
| 94 | + |
| 95 | +### "I need to debug a script that fails silently" |
| 96 | + |
| 97 | +```bash |
| 98 | +mlcr <tags> --verbose # full debug output |
| 99 | +mlc find cache --tags=<failing-dep> # check if dep is cached |
| 100 | +mlc rm cache --tags=<failing-dep> # clear dep cache and re-run |
| 101 | +mlc show cache --tags=<script-tags> # inspect cached new_env |
| 102 | +cat ~/MLC/repos/local/cache/*/mlc-cached-state.json | python3 -m json.tool |
| 103 | +``` |
| 104 | + |
| 105 | +Common root causes: |
| 106 | +- Dep cached but stale → `mlc rm cache --tags=<dep-tags>` |
| 107 | +- `new_env_keys` missing from meta.yaml → key is silently dropped at the boundary |
| 108 | +- `preprocess` returned success but didn't set the expected env var → add assertion |
| 109 | +- `MLC_TMP_*` var expected downstream but not in `new_env_keys` → rename it or declare it |
| 110 | + |
| 111 | +### "I need to understand why an env var is not reaching a script" |
| 112 | + |
| 113 | +Env propagation rules: |
| 114 | +1. CLI `--key=val` → `input_mapping` → `env[MAPPED_VAR]` |
| 115 | +2. `env` passes to deps unless dep has `clean_env_keys` that matches |
| 116 | +3. Dep's `new_env_keys` is the **only** way values come back from a dep |
| 117 | +4. `MLC_TMP_*` never cached, never passed to deps automatically |
| 118 | +5. If a parent caches, only declared `new_env_keys` are replayed on cache hit |
| 119 | + |
| 120 | +### "I need to run the inference benchmark locally for testing" |
| 121 | + |
| 122 | +```bash |
| 123 | +# Quickest smoke test — resnet50, onnxruntime, CPU, 500 samples |
| 124 | +mlcr run-mlperf,inference,_submission,_short,_r6.0-dev \ |
| 125 | + --model=resnet50 --implementation=mlcommons-python \ |
| 126 | + --backend=onnxruntime --device=cpu \ |
| 127 | + --scenario=Offline --test_query_count=500 --target_qps=1 \ |
| 128 | + --hw_name=my_machine --quiet |
| 129 | +
|
| 130 | +# Find performance (tunes target QPS before a real run) |
| 131 | +mlcr run-mlperf,inference,_find-performance,_short,_r6.0-dev \ |
| 132 | + --model=resnet50 --implementation=mlcommons-python \ |
| 133 | + --backend=onnxruntime --device=cpu \ |
| 134 | + --scenario=Offline --hw_name=my_machine --quiet |
| 135 | +
|
| 136 | +# Accuracy-only run |
| 137 | +mlcr run-mlperf,inference,_accuracy-only,_short,_r6.0-dev \ |
| 138 | + --model=resnet50 --implementation=mlcommons-python \ |
| 139 | + --backend=onnxruntime --device=cpu \ |
| 140 | + --scenario=Offline --hw_name=my_machine --quiet |
| 141 | +
|
| 142 | +# Full submission run (both modes + compliance + checker + tar) |
| 143 | +mlcr run-mlperf,inference,_submission,_full,_r6.0-dev \ |
| 144 | + --model=resnet50 --implementation=mlcommons-python \ |
| 145 | + --backend=onnxruntime --device=cpu \ |
| 146 | + --scenario=Offline --execution_mode=valid \ |
| 147 | + --submitter=MLCommons --hw_name=my_machine --quiet |
| 148 | +``` |
| 149 | + |
| 150 | +### "I need to inspect or clear cache" |
| 151 | + |
| 152 | +```bash |
| 153 | +mlc find cache --tags=get,mlperf,endpoints # find cache folder |
| 154 | +mlc show cache --tags=get,mlperf,endpoints # print new_env snapshot |
| 155 | +mlc rm cache --tags=get,mlperf,endpoints # delete specific cache |
| 156 | +mlc rm cache -f # delete ALL caches |
| 157 | +mlc prune cache # delete expired (past cache_expiration) |
| 158 | +``` |
| 159 | + |
| 160 | +### "I need to run in Docker" |
| 161 | + |
| 162 | +```bash |
| 163 | +mlcd app,mlperf,inference,endpoints,_echo-server --num_samples=50 |
| 164 | +# Rebuilds image if meta.yaml docker: section changed: |
| 165 | +mlcd app,mlperf,inference,endpoints --docker_rebuild |
| 166 | +``` |
| 167 | + |
| 168 | +--- |
| 169 | + |
| 170 | +## Quick reference: meta.yaml field cheat-sheet |
| 171 | + |
| 172 | +| Field | What it does | |
| 173 | +|---|---| |
| 174 | +| `alias` | Script directory name and lookup key | |
| 175 | +| `uid` | 16-hex unique ID; never change after first commit | |
| 176 | +| `automation_uid` | UID of the `script` automation type (`5b4e0237da074764`); the only automation type currently in this repo | |
| 177 | +| `tags` | Comma-separated discovery tags; must be a superset of what callers request | |
| 178 | +| `category` | Grouping label in docs | |
| 179 | +| `default_env` | Env vars set before variation env (lowest priority) | |
| 180 | +| `new_env_keys` | **Only** these keys leave the script; use `*` and `?` wildcards | |
| 181 | +| `input_mapping` | CLI `--key` → `ENV_VAR` translation | |
| 182 | +| `deps` | Scripts to run before `preprocess()` | |
| 183 | +| `prehook_deps` | Scripts to run after `preprocess()`, before `run.sh` | |
| 184 | +| `posthook_deps` | Scripts to run after `run.sh`, before `postprocess()` | |
| 185 | +| `post_deps` | Scripts to run after `postprocess()` | |
| 186 | +| `variations` | Named parameter sets; `group:` makes them mutually exclusive | |
| 187 | +| `add_deps_recursive` / `adr` | Override tags/versions on named deps deep in subtree | |
| 188 | +| `versions` | Per-version dep overrides and env | |
| 189 | +| `cache` | Enable caching (default: false) | |
| 190 | +| `cache_expiration` | Auto-invalidate after `1h` / `1d` / `1w` | |
| 191 | +| `tests` | Inline test cases run by `mlct` | |
| 192 | + |
| 193 | +--- |
| 194 | + |
| 195 | +## customize.py hook signatures |
| 196 | + |
| 197 | +```python |
| 198 | +def preprocess(i): # before run.sh |
| 199 | +def postprocess(i): # after run.sh |
| 200 | +def predeps(i): # before dep execution |
| 201 | +def postdeps(i): # after dep execution |
| 202 | +``` |
| 203 | + |
| 204 | +All receive the same `i` dict: |
| 205 | +```python |
| 206 | +i['env'] # mutable env dict → set vars here |
| 207 | +i['automation'] # ScriptAutomation instance → i['automation'].logger |
| 208 | +i['os_info'] # dict from detect-os |
| 209 | +i['meta'] # parsed meta.yaml |
| 210 | +``` |
| 211 | + |
| 212 | +All must return `{'return': 0}` or `{'return': 1, 'error': 'reason'}`. |
| 213 | + |
| 214 | +--- |
| 215 | + |
| 216 | +## Env variable naming conventions |
| 217 | + |
| 218 | +No rigid rules — just two hard constraints and a naming guideline: |
| 219 | + |
| 220 | +- **`MLC_` prefix** — use on all env vars set by MLC scripts so they are clearly distinguishable from the surrounding environment. |
| 221 | +- **`MLC_TMP_*`** — reserved for transient vars: never cached, never passed to deps. Use this when a value is only needed within the current script's run. |
| 222 | +- **`+VAR` in `new_env_keys`** — prepend to an existing env var (e.g. `+PATH`); the engine handles concatenation. |
| 223 | + |
| 224 | +Everything else: name vars to reflect the script they come from and what they hold. Keep names reasonably short and meaningful — no other convention is enforced. |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +## Files to read first by task type |
| 229 | + |
| 230 | +| Task | Read these first | |
| 231 | +|---|---| |
| 232 | +| Understand the inference benchmark | `script/run-mlperf-inference-app/meta.yaml`, `customize.py` | |
| 233 | +| Reference for a new MLPerf benchmark (dep chain, variations, dispatch pattern) | `script/app-mlperf-inference-mlcommons-python/meta.yaml`, `script/run-mlperf-inference-app/meta.yaml` | |
| 234 | +| Debug env propagation | `automation/script/module.py` (search: `new_env_keys`, `clean_env_keys`) | |
| 235 | +| Debug caching | `automation/script/cache_utils.py` | |
| 236 | +| Add a script | Nearest similar script + `automation/script/meta_schema.py` | |
| 237 | +| Fix meta.yaml format | `automation/script/lint.py` | |
| 238 | +| Run CI locally | `.github/workflows/test-mlc-script-features.yml` | |
| 239 | +| Understand Docker path | `automation/script/docker.py` | |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## Don'ts |
| 244 | + |
| 245 | +- Don't use `print()` in `customize.py` — use `i['automation'].logger` |
| 246 | +- Don't raise exceptions for recoverable errors — return `{'return': 1, 'error': '...'}` |
| 247 | +- Don't edit `mlc-cached-state.json` or `tmp-env.sh` by hand |
| 248 | +- Don't push directly to `main` — always open a PR; use `dev` only for urgent merges without approval |
| 249 | +- Don't hard-code paths in `run.sh` — use env vars set by `preprocess` |
| 250 | +- Don't change `automation_uid: 5b4e0237da074764` — it's the UID of the `script` automation type, not a script-specific value |
| 251 | +- Don't commit API keys — pass via `--api_key=...` only |
| 252 | +- Don't set `MLC_TMP_*` in `new_env_keys` (it's a transient namespace) |
0 commit comments