Examples¶
This page collects five real specs from the manifest. Each spec is followed by a table that maps each form used in it to the section that describes it. The specs are taken from src/tileops/manifest/, with comments and some workload rows removed.
1. GemmFwdOp: type family¶
# src/tileops/manifest/spec/gemm.yaml
GemmFwdOp:
ref_api: "torch.matmul"
family: gemm
status: implemented
signature:
types:
Mat:
params: {t: Bool, R: Dim, C: Dim}
match: t
cases:
- {when: false, is: "[R, C]"}
- {when: true, is: "[C, R]"}
forall: {M: Dim, N: Dim, K: Dim, T: "DType[float16 | bfloat16]"}
params:
trans_a: {type: bool, default: false}
trans_b: {type: bool, default: true}
inputs:
a: {dtype: T, shape: "Mat[trans_a, M, K]"}
b: {dtype: T, shape: "Mat[trans_b, K, N]"}
outputs:
d: {dtype: T, shape: "[M, N]"}
workloads:
- {M: 1024, N: 1024, K: 1024, trans_a: false, trans_b: false, dtype_cases: [{T: float16}, {T: bfloat16}], label: square-1k}
- {M: 128, N: 2112, K: 7168, trans_a: false, trans_b: true, dtype_cases: [{T: bfloat16}], label: ds-v3-decode-qkv-a}
# remaining rows omitted
roofline:
flops: "2 * M * N * K"
Table 1 The forms used in GemmFwdOp
| No. | Form in the spec | Described in |
|---|---|---|
| 1 | types.Mat: trans_a and trans_b decide the axis order of a and b |
Extensions § 2 |
| 2 | forall declares three axis lengths and one DType index |
Spec fields § 3 |
| 3 | trans_a and trans_b are both construction parameters and discriminants of Mat |
Spec fields § 4 |
| 4 | workload rows give the values of parameters and indices; the first row expands into two cases, with ids square-1k-float16 and square-1k-bfloat16 |
Spec fields § 8 |
| 5 | roofline gives only flops; bytes is derived from the signature and equals (M*K + K*N + M*N) times the bytes per element |
Spec fields § 9 |
2. MoEPrePermuteFwdOp: ADT, let and generator¶
The type of the layout parameter is the ADT MGroupedLayout defined in spec/types.yaml; its definition is in Extensions § 3.
# src/tileops/manifest/spec/moe.yaml
MoEPrePermuteFwdOp:
family: moe
status: implemented
signature:
types:
LayoutMetadata:
params: {layout: MGroupedLayout, E: Dim, P: Dim}
match: layout
cases:
- {when: {contiguous: {metadata_kind: physical_psum}}, is: "[E]"}
- {when: {contiguous: {metadata_kind: per_row}}, is: "[P]"}
forall: {T: Dim, H: Dim, K: Dim, D: "DType[float16 | bfloat16]"}
params:
layout: {type: MGroupedLayout}
num_local_experts: {type: int}
inputs:
hidden_states: {dtype: D, shape: "[T, H]", contiguous: true}
local_expert_ids: {dtype: int32, shape: "[T, K]", contiguous: true, values: "topk_ids(T, K, num_local_experts)", requires: ["in_range(0, num_local_experts)"]}
let:
P: "moe.capacity(layout, T * K, num_local_experts)"
outputs:
expert_input: {dtype: D, shape: "[P, H]", contiguous: true}
layout_metadata: {dtype: int32, shape: "LayoutMetadata[layout, num_local_experts, P]", contiguous: true}
inverse_indices: {dtype: int32, shape: "[T * K]", contiguous: true}
shape_rules:
- "layout.kind == 'contiguous'"
- "num_local_experts > 0"
- "T > 0"
- "K > 0"
workloads:
- {T: 32, H: 128, K: 2, num_local_experts: 4, layout: {contiguous: {packing: tight, metadata_kind: physical_psum, alignment: 1}}, dtype_cases: [{D: float16}, {D: bfloat16}], label: "decode-t32"}
# remaining rows omitted
roofline:
flops: "0"
Table 2 The forms used in MoEPrePermuteFwdOp
| No. | Form in the spec | Described in |
|---|---|---|
| 1 | layout.kind == 'contiguous' is a domain restriction that excludes the masked layout, so LayoutMetadata needs no case for masked |
Extensions § 2, § 3 |
| 2 | LayoutMetadata pattern-matches on the constructor and the field metadata_kind |
Extensions § 2 |
| 3 | the int parameter num_local_experts appears directly in shapes |
Spec fields § 4 |
| 4 | P in let is computed by the primitive moe.capacity and used in output shapes |
Extensions § 4 |
| 5 | the values of local_expert_ids are generated by the generator topk_ids, and its contents are constrained by requires |
Extensions § 7 |
| 6 | each tensor declares contiguous: true |
Extensions § 5 |
| 7 | layout in the workload row is written as an ADT value |
Extensions § 3 |
3. MeanPoolingFwdOp: optional inputs and metadata tensors¶
# src/tileops/manifest/spec/pool.yaml
MeanPoolingFwdOp:
family: pool
status: implemented
signature:
types:
PoolOut:
params: {p: Bool, B: Dim, NC: Dim, S: Dim, c: Dim, H: Dim, D: Dim}
match: p
cases:
- {when: true, is: "[B, NC, H, D]"}
- {when: false, is: "[B, ceil_div(S, c), H, D]"}
forall: {B: Dim, S: Dim, H: Dim, D: Dim, NS: Dim, NC: Dim, T: "DType[float16 | bfloat16 | float32]", seq_lens: "Seq[Int]"}
params:
chunk_size: {type: int}
accum_dtype: {type: torch.dtype}
inputs:
x: {dtype: T, shape: "[B, S, H, D]"}
offsets: {dtype: int32, optional: true, shape: "[NS + 1]", values: "prefix_sum(seq_lens)", requires: ["prefix_offsets(S)"]}
indices: {dtype: int32, optional: "present(offsets)", shape: "[NC, 2]", values: "chunk_indices(seq_lens, chunk_size)"}
outputs:
output: {dtype: T, shape: "PoolOut[present(offsets), B, NC, S, chunk_size, H, D]"}
shape_rules:
- "chunk_size > 0 and chunk_size % 32 == 0"
- "D <= 128 or D % 128 == 0"
- "category(accum_dtype) == 'float'"
workloads:
- {B: 1, S: 8192, H: 64, D: 128, chunk_size: 64, accum_dtype: float32, dtype_cases: [{T: float16}, {T: bfloat16}], label: uniform-8k}
- {B: 1, S: 8192, H: 64, D: 128, seq_lens: "repeat(2048, 4)", chunk_size: 64, accum_dtype: float32, some: [offsets], dtype_cases: [{T: float16}, {T: float32}], label: ragged-even}
# remaining rows omitted
roofline:
flops: "B * S * H * D + B * (NC if present(offsets) else ceil_div(S, chunk_size)) * H * D"
Table 3 The forms used in MeanPoolingFwdOp
| No. | Form in the spec | Described in |
|---|---|---|
| 1 | indices is declared optional: "present(offsets)", so it is passed together with offsets or omitted together with it |
Extensions § 1 |
| 2 | the type family PoolOut uses present(offsets) as its discriminant |
Extensions § 2 |
| 3 | the first row does not pass offsets and does not use seq_lens, so the row does not give it; the second row passes offsets through some: [offsets] and gives seq_lens, written here as the value primitive call "repeat(2048, 4)" |
Extensions § 1, Spec fields § 8 |
| 4 | NS and NC are solved by unification of the generator results and are not given in the row |
Extensions § 7 |
| 5 | category(accum_dtype) == 'float' requires the accumulation dtype to be a floating-point type |
Extensions § 9 |
| 6 | the roofline formula distinguishes the two cases with present(offsets) |
Spec fields § 9 |
4. ReluFwdOp: arbitrary rank and effect¶
# src/tileops/manifest/spec/elementwise_unary_activation.yaml
ReluFwdOp:
ref_api: "torch.nn.functional.relu"
family: elementwise
status: implemented
signature:
forall: {S: Shape, T: "DType[float16 | bfloat16 | float32]"}
params:
inplace: {type: bool, default: false, kw_only: true}
inputs:
input: {dtype: T, shape: "[*S]", mutated: inplace}
outputs:
output: {dtype: T, shape: "[*S]", alias: input}
workloads:
- {S: [2048, 4096], dtype_cases: [{T: float16}, {T: bfloat16}], label: "hidden-state-prefill"}
- {S: [1, 4096], dtype_cases: [{T: bfloat16}], label: "hidden-state-decode"}
roofline:
flops: "prod(S)"
Table 4 The forms used in ReluFwdOp
| No. | Form in the spec | Described in |
|---|---|---|
| 1 | the kind of S is Shape, and the input and output use the same shape term [*S] |
Spec fields § 3, § 5 |
| 2 | mutated: inplace and alias: input mean that when inplace is true the op writes the input and returns it |
Extensions § 6 |
| 3 | S in the workload rows is written as a list of integers |
Spec fields § 8 |
5. AlibiFwdOp: no tensor inputs¶
# src/tileops/manifest/spec/elementwise_generative.yaml
AlibiFwdOp:
family: elementwise
status: implemented
signature:
params:
seq_len: {type: int, kw_only: true}
num_heads: {type: int, kw_only: true}
out_dtype: {type: "float16 | bfloat16 | float32", default: float32, kw_only: true}
device: {type: "torch.device | str | None", default: null, kw_only: true}
outputs:
output: {dtype: out_dtype, shape: "[num_heads, seq_len, seq_len]"}
shape_rules:
- "seq_len > 0"
- "num_heads > 0"
workloads:
- {seq_len: 2048, num_heads: 32, out_dtype: float16, label: "mpt-7b-2k"}
- {seq_len: 2048, num_heads: 32, out_dtype: bfloat16, label: "mpt-7b-2k"}
# remaining rows omitted
roofline:
flops: "3 * num_heads * seq_len * seq_len"
Table 5 The forms used in AlibiFwdOp
| No. | Form in the spec | Described in |
|---|---|---|
| 1 | every index comes from a construction parameter, so the spec has no forall |
Spec fields § 4 |
| 2 | the output's dtype uses the dtype parameter out_dtype directly |
Spec fields § 7 |
| 3 | the op has no call-time tensor inputs, so it declares a device parameter |
Extensions § 5, Calls and validation § 4 |
| 4 | the two rows have the same label, and their case ids are distinguished by the value of the dtype parameter: mpt-7b-2k-float16 and mpt-7b-2k-bfloat16 |
Spec fields § 8 |