-
Notifications
You must be signed in to change notification settings - Fork 24
[Feat][Platform] Add ops_manifest.yaml with rmsnorm_fwd entry #636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lcy-seso
wants to merge
5
commits into
tile-ai:main
Choose a base branch
from
lcy-seso:feat/platform/issue-627
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+242
−57
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
0c88ac1
[Feat][Platform] Add ops_manifest.yaml with rmsnorm_fwd entry
lcy-seso 0cb9eaa
[Fix][Platform] Move defaultdict import to module level (PEP 8)
lcy-seso f8e2b42
[Test] Rewrite manifest tests as generic schema validation
lcy-seso fbf097b
[Doc] Add M7→M8 edge and optimize Mermaid module diagram layout
lcy-seso 315d817
[Doc][Platform] Align manifest spec and implementation
lcy-seso File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| # ops_manifest.yaml -- Spec-driven op registry for TileOPs | ||
| # | ||
| # Schema | ||
| # ------ | ||
| # ops: | ||
| # <op_name>: # Unique op identifier (e.g. rmsnorm_fwd) | ||
| # signature: | ||
| # inputs: [{name, dtype, shape}] # Input tensors | ||
| # outputs: [{name, dtype, shape}] # Output tensors | ||
| # params: [{name, type, default}] # Scalar / config parameters | ||
| # shape_rules: [str] # Optional Python expressions relating dimensions | ||
| # workloads: [{x_shape, dtypes, label?}] # Representative shapes for benchmarking | ||
| # roofline: # Analytical cost model | ||
| # flops: <expr> # Inline Python expression -OR- | ||
| # bytes: <expr> # both flops and bytes expressions | ||
| # func: <module:function> # Alternative: reference to Python function | ||
| # source: | ||
| # kernel: <path> # Path to kernel implementation | ||
| # op: <path> # Path to op wrapper | ||
| # test: <path> # Path to test file | ||
| # bench: <path> # Path to benchmark file | ||
| # family: <str> # Op family for grouping (e.g. norm, attention) | ||
| # | ||
| # Notes: | ||
| # - Backward ops are registered as independent entries (e.g. rmsnorm_bwd). | ||
| # - shape_rules use Python expression syntax and are optional. | ||
| # - roofline supports two modes: inline expressions (flops/bytes) or func. | ||
|
|
||
| ops: | ||
| rmsnorm_fwd: | ||
| family: norm | ||
|
|
||
| signature: | ||
| inputs: | ||
| - name: x | ||
| dtype: "{float16, bfloat16}" | ||
| shape: "[M, N]" | ||
| - name: weight | ||
| dtype: "{float16, bfloat16}" | ||
| shape: "[N]" | ||
| outputs: | ||
| - name: y | ||
| dtype: "{float16, bfloat16}" | ||
| shape: "[M, N]" | ||
| params: | ||
| - name: dim | ||
| type: int | ||
| default: -1 | ||
| - name: eps | ||
| type: float | ||
| default: 1.0e-6 | ||
| shape_rules: | ||
| - "weight.shape == (x.shape[-1],)" | ||
| - "y.shape == x.shape" | ||
|
|
||
| workloads: | ||
| # Llama-3.1-8B (hidden_dim=4096) | ||
| - {x_shape: [2048, 4096], dtypes: [float16, bfloat16], label: "llama-3.1-8b-prefill"} | ||
| - {x_shape: [1, 4096], dtypes: [bfloat16], label: "llama-3.1-8b-decode"} | ||
| # Llama-3.1-70B (hidden_dim=8192) | ||
| - {x_shape: [2048, 8192], dtypes: [float16, bfloat16], label: "llama-3.1-70b-prefill"} | ||
| - {x_shape: [1, 8192], dtypes: [bfloat16], label: "llama-3.1-70b-decode"} | ||
| # Llama-3.1-405B (hidden_dim=16384) | ||
| - {x_shape: [2048, 16384], dtypes: [float16, bfloat16], label: "llama-3.1-405b-prefill"} | ||
| - {x_shape: [1, 16384], dtypes: [bfloat16], label: "llama-3.1-405b-decode"} | ||
|
|
||
| roofline: | ||
| # Per row: N squares + (N-1) adds + div + add + rsqrt + N muls (normalize) + N muls (weight) ≈ 4N | ||
| flops: "4 * M * N" | ||
| # Bytes: read x (M*N) + read weight (N) + write y (M*N), x2 for fp16/bf16 elem_size | ||
| bytes: "2 * (M * N + N + M * N)" | ||
|
|
||
| source: | ||
| kernel: tileops/kernels/norm/rms_norm.py | ||
| op: tileops/ops/norm/rms_norm.py | ||
| test: tests/ops/test_rms_norm.py | ||
| bench: benchmarks/ops/bench_rms_norm.py |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,7 @@ dev = [ | |
| "codespell==2.4.1", | ||
| "pytest>=8.0", | ||
| "pytest-xdist>=3.0", | ||
| "pyyaml>=6.0", | ||
| ] | ||
|
|
||
| [build-system] | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| """Schema validation for ops_manifest.yaml. | ||
|
|
||
| Validates structural invariants across all ops in the manifest. | ||
| Not op-specific — tests apply to every entry. | ||
| """ | ||
|
|
||
| from pathlib import Path | ||
|
|
||
| import pytest | ||
| import yaml | ||
|
|
||
| pytestmark = pytest.mark.smoke | ||
|
|
||
| REPO_ROOT = Path(__file__).resolve().parent.parent | ||
| MANIFEST_PATH = REPO_ROOT / "ops_manifest.yaml" | ||
|
|
||
|
|
||
| @pytest.fixture(scope="module") | ||
| def manifest(): | ||
| """Load and parse the ops manifest.""" | ||
| assert MANIFEST_PATH.exists(), f"ops_manifest.yaml not found at {MANIFEST_PATH}" | ||
| with open(MANIFEST_PATH) as f: | ||
| data = yaml.safe_load(f) | ||
| assert isinstance(data, dict), "Manifest root must be a YAML mapping" | ||
| return data | ||
|
|
||
|
|
||
| @pytest.fixture(scope="module") | ||
| def all_ops(manifest): | ||
| """Return the ops dict from the manifest.""" | ||
| assert "ops" in manifest, "Manifest must have top-level 'ops' key" | ||
| assert isinstance(manifest["ops"], dict) | ||
| return manifest["ops"] | ||
|
|
||
|
|
||
| class TestManifestStructure: | ||
| """Manifest file exists, parses, and has the expected top-level structure.""" | ||
|
|
||
| def test_manifest_exists(self): | ||
| assert MANIFEST_PATH.exists() | ||
|
|
||
| def test_manifest_is_valid_yaml(self, manifest): | ||
| assert manifest is not None | ||
|
|
||
| def test_has_ops_key(self, manifest): | ||
| assert "ops" in manifest | ||
| assert isinstance(manifest["ops"], dict) | ||
|
|
||
|
|
||
| class TestOpSchema: | ||
| """Every op entry has the required fields and valid sub-structure.""" | ||
|
|
||
| REQUIRED_TOP_FIELDS = {"family", "signature", "workloads", "roofline", "source"} | ||
|
|
||
| def test_every_op_has_required_fields(self, all_ops): | ||
| for op_name, entry in all_ops.items(): | ||
| missing = self.REQUIRED_TOP_FIELDS - set(entry.keys()) | ||
| assert not missing, f"{op_name} missing fields: {missing}" | ||
|
|
||
| def test_every_signature_has_inputs_and_outputs(self, all_ops): | ||
| for op_name, entry in all_ops.items(): | ||
| sig = entry["signature"] | ||
| assert "inputs" in sig, f"{op_name}: signature missing 'inputs'" | ||
| assert isinstance(sig["inputs"], list), f"{op_name}: inputs must be a list" | ||
| assert len(sig["inputs"]) >= 1, f"{op_name}: must have at least 1 input" | ||
| assert "outputs" in sig, f"{op_name}: signature missing 'outputs'" | ||
| assert isinstance(sig["outputs"], list), f"{op_name}: outputs must be a list" | ||
|
|
||
| def test_every_roofline_has_valid_mode(self, all_ops): | ||
| for op_name, entry in all_ops.items(): | ||
| roofline = entry["roofline"] | ||
| has_inline = "flops" in roofline and "bytes" in roofline | ||
| has_func = "func" in roofline | ||
| assert has_inline or has_func, ( | ||
| f"{op_name}: roofline must have (flops + bytes) or func" | ||
| ) | ||
|
|
||
| def test_shape_rules_are_valid_expressions(self, all_ops): | ||
| for op_name, entry in all_ops.items(): | ||
| sig = entry["signature"] | ||
| if "shape_rules" not in sig: | ||
| continue | ||
| for rule in sig["shape_rules"]: | ||
| try: | ||
| compile(rule, "<shape_rule>", "eval") | ||
| except SyntaxError as exc: | ||
| pytest.fail( | ||
| f"{op_name}: invalid shape_rule: {rule!r} ({exc})" | ||
| ) | ||
|
|
||
|
|
||
| class TestSourcePaths: | ||
| """All source paths point to existing files.""" | ||
|
|
||
| def test_all_source_paths_exist(self, all_ops): | ||
| for op_name, entry in all_ops.items(): | ||
| source = entry["source"] | ||
| for key, rel_path in source.items(): | ||
| full_path = REPO_ROOT / rel_path | ||
| assert full_path.exists(), ( | ||
| f"{op_name}: source.{key} not found: {rel_path}" | ||
| ) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.