Section 7 - Profiles and Tunables¶
Every example so far either left an operator's tunables (num_aie_columns,
tile_size, ...) out entirely, letting Operator.resolve(dev) pick sane
defaults, or gave them explicitly at the .step(...) call site. A real
model does neither at scale: it autotunes each operator's tunables once per
device and keeps the result in a profile, a JSON file the graph applies
without body repeating a tunable at every call.
Walkthrough of profiles.py¶
class Scaled(iron.Graph):
"""``1.5 * x + y``: one ``AXPY`` step, its tunables left to the profile."""
def body(self, x, y):
return AXPY.step(x, y, scalar_factor=1.5)
body names only what makes AXPY this operator — scalar_factor — and
leaves tile_size and num_aie_columns to whatever resolves them.
profile = iron.Profile()
profile.add(AXPY, size=2048, tile_size=1024, num_aie_columns=2)
graph = Scaled()
graph.profile = profile
Profile.add(cls, **fields) records one entry: the param() fields given
(size here) are what an entry matches — a graph's step is only shaped
by this entry if every dimension it names agrees; a dimension left out
matches any value. The tunable() fields given (tile_size,
num_aie_columns) are what the entry sets, for every step whose shape
matches. Assigning profile to graph.profile makes it apply to body
wherever the graph is recorded — including graph.reference(...), which
constructs the same operators under the same profile, so a check reflects
what the device actually runs.
Precedence¶
A value for one tunable can come from three places, in this order:
- The call's own keyword —
AXPY.step(x, y, scalar_factor=1.5, num_aie_columns=1)always wins, profile or not. - The profile — the most specific matching entry (more
param()fields named is more specific; two equally specific entries that disagree raise). Operator.resolve(dev)— the operator's own default for the bound device, when neither of the above gave a value.
iron/applications/llama/profiles/
is the worked example at model scale: one entry per operator shape a real
decoder builds, written by python -m iron.lm.tune <application> --checkpoint
<directory>, which times every setting of every operator's tunables and
rewrites the profile. Review a regenerated profile with git diff before
committing it — a tunable moving is a performance change worth seeing, not
just a file diff.
Exercises¶
- Run
python3 profiles.py; it prints the tunables the profile chose and checks the graph against numpy, same as earlier sections. - Add a second
profile.add(AXPY, size=1024, tile_size=256, num_aie_columns=1)entry and record the graph atx=(1024,), y=(1024,)— a different shape picks the other entry. - Add
num_aie_columns=1to theAXPY.step(...)call itself (keeping the profile'snum_aie_columns=2) and rereadop.num_aie_columnsafter recording: the call's own value wins.