Skip to content

docs: skill for working with a gt4py.next cache from a shell - #2794

Closed
havogt wants to merge 1 commit into
GridTools:mainfrom
havogt:cache-shell-recipes
Closed

docs: skill for working with a gt4py.next cache from a shell#2794
havogt wants to merge 1 commit into
GridTools:mainfrom
havogt:cache-shell-recipes

Conversation

@havogt

@havogt havogt commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Independent of the cache-manager stack (#2769#2768#2792) — this adds one
skill file and nothing else, and its recipes are written to hold whatever cache
layout is in place.

Why

Clearing the translation cache normally needs a gt4py-capable interpreter: to
resolve the cache directory, to read an entry, to take the lock. On a compute
node, in a container, against a copied cache, or with a gt4py too old to ship
gt4py-next-cache, none of that is available — and the reflex is grep.

grep does work. But of the three forms one would naturally try, two fail by
reporting nothing, which reads as nothing cached — the wrong direction to be
wrong in when the next step is a multi-node benchmark.

Measured against a real 224-entry icon4py cache and a smaller one containing
lap_program, laplap_program and skewedlap_program:

Form Result
grep -rlaF <name> correct on 22/22 programs; over-matches substrings
grep -rlaP '(?<!\w)<name>(?!\w)' 3 of 22 programs returned 0 hits
grep -rlaE '[^A-Za-z0-9_]<name>…' 0 of 22
any of them without -a 0 hits under ugrep

The boundary failure has an exact cause: pickle stores a short string as
0x8c <length-byte> <bytes>, so the byte before the name is its length. The
three that vanished are the three whose names are 48, 48 and 49 characters — the
length byte is then '0', '0', '1', alphanumeric, so (?<!\w) rejects the
match. Any name of 48–57, 65–90 or 97–122 characters disappears the same way.

Plain -F is sound precisely because it errs the other way: it can never miss
(the name is literally in the file) and only over-matches when one program name
contains another, which is harmless since a wrongly deleted entry is simply
re-translated.

What

.agents/skills/translation-cache-shell/ — find the cache, inventory it, list
the entries of a program, clear them, and name a single entry; plus the two
anti-recommendations above and the one thing these recipes cannot do: take
gt4py._core.locking.lock, so they must not run while ranks are compiling.

Recipes scope by *.pkl rather than by directory name, because only translation
entries are pickles — verified 34/34 and 331/331 on two caches — so they survive
the layout changes in #2769 and #2792 regardless of merge order.

Kept separate from the translation-cache skill added in #2768, which drives the
CLI: the two are selected in different situations, and this one exists to say
what it cannot do.

Verification

Every command in the file was run verbatim against two real caches, including
the entry-naming one-liner (exact on all 331 entries, names 14–58 chars; the
documented caveat is that a name of 65+ characters would leave a spurious leading
letter). grep here resolves to ugrep 7.5.0, which is how the missing--a
failure was found — the documented form was then checked under both ugrep and
GNU grep 3.12.

@havogt
havogt force-pushed the cache-shell-recipes branch from afceb2e to 11621d4 Compare August 14, 2026 14:06
## Find the cache

```bash
find . -maxdepth 3 -name '.gt4py_cache' -type d

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably instead of trying to find it, we should just say something like "it's in .gt4py_cache, next to the
working directory of the run (or under GT4PY_BUILD_CACHE_DIR)."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — dropped the find invocation; the section now just states that it is .gt4py_cache next to the working directory of the run, or under GT4PY_BUILD_CACHE_DIR.

@@ -0,0 +1,113 @@
---
name: translation-cache-shell
description: Inspect and prune a gt4py.next cache with shell tools only — find, grep, rm — when no gt4py-capable interpreter is at hand. TRIGGER when clearing or examining a `.gt4py_cache` on a machine where gt4py cannot be imported (a compute node, a container, a copied cache, a gt4py too old to ship `gt4py-next-cache`), or when a benchmark must be cleared of cached translations before it runs. SKIP when `gt4py-next-cache` is available — it takes the same lock as the runtime, which these recipes cannot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's assume a cache manager cli does not exist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — every mention of a cache-manager CLI is gone, from the description and from the body.

Comment on lines +25 to +28
Under the default *session* lifetime there is nothing to find: the cache lives in
a temporary directory that is deleted when the process exits. Only
`GT4PY_BUILD_CACHE_LIFETIME=persistent` puts it in `.gt4py_cache`, next to the
working directory of the run (or under `GT4PY_BUILD_CACHE_DIR`).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of mentioning the default explicitly, say it's only there if GT4PY_BUILD_CACHE_LIFETIME=persistent is set and link to the config module for defaults.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — no longer names a default; it says the cache is only written there when GT4PY_BUILD_CACHE_LIFETIME=persistent, and links to config.py for the defaults.

Comment on lines +53 to +58
This **over-matches**: a name that contains another name returns both, so
`lap_program` also lists the entries of `laplap_program`. That is harmless — a
wrongly deleted entry is simply re-translated — and it never misses, because the
name is always literally present. Rely on it in that direction only: *entries
found* is a reason to delete, *nothing found* is trustworthy, but "found" does
not prove those entries would have been replayed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This **over-matches**: a name that contains another name returns both, so
`lap_program` also lists the entries of `laplap_program`. That is harmless — a
wrongly deleted entry is simply re-translated — and it never misses, because the
name is always literally present. Rely on it in that direction only: *entries
found* is a reason to delete, *nothing found* is trustworthy, but "found" does
not prove those entries would have been replayed.
This **over-matches**: a name that contains another name returns both.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied verbatim.

Comment on lines +80 to +82
Deleting every translation is `find <cache> -name '*.pkl' -delete`. Build folders
are untouched either way, which is what you want: the point is to force
re-translation, and the rebuild follows from it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, we can just delete the whole cache folder.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — replaced with "To clear everything, delete the cache folder."

Comment on lines +100 to +103
`gt4py-next-cache` — shipped with newer gt4py — takes `gt4py._core.locking.lock`
around each unlink, the same lock the runtime holds while writing. These recipes
do not, so an `rm` here can race a concurrent writer. On a shared filesystem with
MPI ranks compiling, clear the cache between jobs rather than during one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not mention this tool here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — the section now states the constraint on its own: the runtime locks each cache file while writing it (gt4py._core.locking) and these recipes do not, so do not run them while ranks are compiling.

The translation cache is what makes a benchmark measure the old compiler, and
clearing it means reaching into `.gt4py_cache` by hand wherever gt4py cannot be
imported -- a compute node, a container, a cache copied from elsewhere. The
reflex is `grep`.

That works, but only in one form, and the two obvious refinements fail by
reporting nothing -- which reads as nothing cached, the wrong way to be wrong
here. Write down the form that holds and why the others do not: `-a` because the
entries are binary and `ugrep` silently skips them otherwise, `-F` because a
word-boundary pattern is defeated by pickle's length prefix, which sits
immediately before the name and is itself alphanumeric for names of 48-57, 65-90
or 97-122 characters. On a real 224-entry cache that silently lost 3 of 22
programs. The delete pipeline gets `--null`/`-0` so a path with a space does not
split, and `-r` so an empty match set does not invoke `rm` bare.

The recipes scope by `*.pkl` rather than by directory, since only translation
entries are pickles, so they hold across cache layouts. Each was run verbatim
against two real caches before being written down.
@havogt
havogt force-pushed the cache-shell-recipes branch from 11621d4 to a698d26 Compare August 14, 2026 14:19
@havogt

havogt commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Probably safer to provide a script in some form to delete entries (for deterministic results).

@havogt havogt closed this Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant