Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ docs/_build/

# Generated visualization data and manually collected report bundles
.visualization/

# FlyDSL kernel build artifacts and profiler output (generated at run time)
tasks/flydsl2flydsl/*/build/
tasks/flydsl2flydsl/*/.rocprofv3/
tasks/flydsl2flydsl/*/performance_report.json
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,22 @@ performance_command:

task_type: triton2triton

# Optional: limit a task to a GPU architecture.
platform_support:
required_arch: gfx942
status: active # active | skip
skip_reason: null

prompt:
source_code: null
instructions: null
cheatsheet: null
```

Tasks marked `platform_support.status: skip`, or requiring a different GPU
architecture, are filtered before workspace creation. Omit `platform_support`
for tasks that run on every architecture.

Repository-level tasks use `task_type: repository`, `repo_url`, and `repository_language`; their source and target hints are optional. See [docs/how-to/add-task.md](docs/how-to/add-task.md) for the complete schemas.

## Development
Expand Down
4 changes: 4 additions & 0 deletions agents/task_validator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ make docker-run CONFIG=config_task_validator.yaml

Each task workspace will contain a `validation_report.yaml` with per-check results. A `validation_summary.yaml` is written to the workspace root with aggregated statistics.

Tasks filtered by `platform_support.status: skip` or a non-matching
`platform_support.required_arch` are skipped before workspace creation and are
not included in the validation summary counts.

### Agent Configuration

Edit `agents/task_validator/agent_config.yaml`. This portable example leaves the
Expand Down
4 changes: 3 additions & 1 deletion agents/task_validator/validation_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ def build_validation_prompt(task_config_dir: str, workspace: str, eval_config: d
- `compile_command` (list of strings)
- `correctness_command` (list of strings)
- `task_type` (string, one of: hip2hip, cuda2hip, triton2triton, triton2flydsl, torch2hip, torch2flydsl, instruction2triton, flydsl2flydsl, repository)
Also check that optional fields (`performance_command`, `prompt`) are well-formed if present.
Also check that optional fields (`performance_command`, `prompt`, `platform_support`) are well-formed if present.
`platform_support`, when present, is a mapping with optional `status` (`active` or `skip`),
optional `required_arch` (string such as `gfx942`), and optional `skip_reason` (string).

**IMPORTANT — `task_type: repository` schema differs.** Repository tasks clone a full upstream
project and drive it through `scripts/task_runner.py` instead of shipping an isolated kernel file.
Expand Down
10 changes: 10 additions & 0 deletions docs/how-to/add-task.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,22 @@ prompt:
source_code: null # override the default source-code section
instructions: null # custom instructions
cheatsheet: null # reference/cheatsheet content

# Optional platform gate. Omit this block for tasks that run everywhere.
platform_support:
required_arch: gfx942 # compared with the detected GPU architecture
status: active # active | skip
skip_reason: null # recommended when status is skip
```

Some specialized launchers and task runners use additional fields such as
`harness_path` or `target_file_path`. Document those fields with the task or
agent that consumes them; they are not part of the common evaluator schema.

Tasks with `platform_support.status: skip`, or with a `required_arch` that does
not match the current run, are skipped before workspace creation. Historical
per-suite fields such as `runnable_on_gfx942` are documentation only.

## Authoring rules

To produce trustworthy, comparable scores, every task must have a reproducible
Expand Down
5 changes: 4 additions & 1 deletion docs/how-to/task-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ make docker-run CONFIG=config_validator.yaml

Each task workspace receives a `validation_report.yaml` with per-check results,
and a `validation_summary.yaml` with aggregated statistics is written to the
workspace root.
workspace root. Tasks skipped by `platform_support.status: skip` or by a
non-matching `platform_support.required_arch` are filtered before workspace
creation, so they do not produce a validation report or appear in the summary
counts.

For large validation batches on a multi-GPU server, use the parallel Docker
runner. It starts one validator worker container per GPU and writes the same
Expand Down
9 changes: 9 additions & 0 deletions docs/reference/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ For isolated-kernel tasks (`hip2hip`, `cuda2hip`, `triton2triton`,
| `correctness_timeout` | No | Per-command correctness timeout in seconds (default `3600`) |
| `performance_timeout` | No | Per-command performance timeout in seconds (default `3600`) |
| `task_result_template` | No | Legacy compatibility field. The centralized evaluator writes the standard result schema regardless of this value |
| `platform_support` | No | Optional run-gating metadata; see below |
| `prompt.source_code` | No | Override the prompt's source-code section |
| `prompt.instructions` | No | Custom prompt instructions |
| `prompt.cheatsheet` | No | Reference/cheatsheet content for the prompt |
Expand All @@ -150,11 +151,19 @@ For repository-level tasks (`task_type: repository`):
| `repo_subdir` | No | Workspace subdirectory for the clone; defaults to the repository name derived from `repo_url` |
| `source_file_path` | No | Optional target source-file hints, relative to the cloned repository root |
| `target_kernel_functions` | No | Optional target function or kernel-symbol hints |
| `platform_support` | No | Optional run-gating metadata; see below |
| `prompt.instructions` | No | Custom prompt instructions |
| `prompt.cheatsheet` | No | Reference/cheatsheet content for the prompt |

See [Add a task](../how-to/add-task.md) for layout and authoring rules.

### Platform support

`platform_support.status: skip` excludes a task unconditionally. An active task
with `platform_support.required_arch` is run only when that value matches the
detected GPU architecture. If `platform_support` is omitted, the task remains
runnable on every architecture.

## Result schema (`task_result.yaml`)

Each task produces a `task_result.yaml` in its workspace:
Expand Down
10 changes: 10 additions & 0 deletions example_configs/validate_flydsl_pending_mi355x.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
agent:
template: task_validator

tasks:
- flydsl2flydsl/blockscale_preshuffle_gemm_kernel
- flydsl2flydsl/preshuffle_gemm_v2_kernel

target_gpu_model: MI355X
log_directory: logs
workspace_directory_prefix: workspace
114 changes: 112 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,103 @@ def _discover_tasks(tasks: list[str]) -> dict[str, str]:
return task_config_dict


def should_run_task_for_platform(
task_name: str,
task_config: dict[str, Any],
current_gfx_arch: str | None,
logger: logging.Logger,
) -> bool:
"""Return whether a task's optional platform metadata includes this run."""
platform_support = task_config.get("platform_support")
if platform_support is None:
return True
if not isinstance(platform_support, dict):
logger.warning(
"Task %s has non-dict platform_support=%r; treating task as runnable",
task_name,
platform_support,
)
return True

raw_status = platform_support.get("status", "active")
status = str(raw_status).strip().lower() if raw_status is not None else "active"
if status == "skip":
skip_reason = str(platform_support.get("skip_reason") or "").strip()
suffix = f": {skip_reason}" if skip_reason else ""
logger.warning(
"Skipping task %s before workspace setup: platform_support.status=skip%s",
task_name,
suffix,
)
return False
if status and status != "active":
logger.warning(
"Task %s has unsupported platform_support.status=%r; treating task as runnable",
task_name,
raw_status,
)

required_arch = platform_support.get("required_arch")
if not required_arch:
return True
if not isinstance(required_arch, str):
logger.warning(
"Task %s has non-string platform_support.required_arch=%r; treating task as runnable",
task_name,
required_arch,
)
return True

required_arch = required_arch.strip()
if not required_arch:
return True
if not current_gfx_arch:
logger.warning(
"Skipping task %s before workspace setup: platform_support.required_arch=%s, "
"but current GPU arch could not be resolved",
task_name,
required_arch,
)
return False
if required_arch != current_gfx_arch:
logger.warning(
"Skipping task %s before workspace setup: platform_support.required_arch=%s "
"does not match current GPU arch %s",
task_name,
required_arch,
current_gfx_arch,
)
return False

return True


def filter_tasks_by_platform(
task_config_dict: dict[str, str],
current_gfx_arch: str | None,
logger: logging.Logger,
) -> dict[str, str]:
"""Filter task configs using their optional platform_support metadata."""
runnable_tasks: dict[str, str] = {}
skipped_tasks: list[str] = []

for task_name, task_config_dir in task_config_dict.items():
with open(task_config_dir, "r") as f:
task_config = yaml.safe_load(f) or {}
if should_run_task_for_platform(task_name, task_config, current_gfx_arch, logger):
runnable_tasks[task_name] = task_config_dir
else:
skipped_tasks.append(task_name)

if skipped_tasks:
logger.warning(
"Platform support preflight skipped %d task(s): %s",
len(skipped_tasks),
skipped_tasks,
)
return runnable_tasks


def _build_context(
args: argparse.Namespace,
*,
Expand Down Expand Up @@ -269,6 +366,7 @@ def _build_context(
python_path = apply_subprocess_python_path()
logger.info(f"Subprocess Python environment: {python_path}")
setup_rocm_env(config["target_gpu_model"], logger)
current_gfx_arch = os.environ.get("PYTORCH_ROCM_ARCH")

agent_launcher = None
if need_agent_launcher:
Expand All @@ -278,8 +376,10 @@ def _build_context(
logger.error(f"Failed to load agent launcher: {e}")
return None

task_config_dict = _discover_tasks(tasks)
logger.info(f"Found {len(task_config_dict)} configured task(s)")
configured_tasks = _discover_tasks(tasks)
logger.info(f"Found {len(configured_tasks)} configured task(s)")
task_config_dict = filter_tasks_by_platform(configured_tasks, current_gfx_arch, logger)
logger.info(f"Found {len(task_config_dict)} runnable task(s) after platform preflight")
logger.info(f"Tasks: {list(task_config_dict.keys())}")

return {
Expand Down Expand Up @@ -356,6 +456,16 @@ def run_task(
task_type = task_config.get("task_type", "")
is_validator = agent == AgentType.TASK_VALIDATOR

# Task packages may include a previously committed validator report.
# It is evidence about an older source snapshot, not completion evidence
# for this run. Remove the copied report before launching the validator
# so an agent/backend failure cannot be mistaken for a successful run.
if is_validator:
stale_report = workspace_path / "validation_report.yaml"
if stale_report.exists():
stale_report.unlink()
logger.info("Removed copied stale validation_report.yaml before validation")

baseline_cases = []
if is_validator:
logger.info("task_validator run: skipping baseline/evaluation/perf-plot benchmark pipeline")
Expand Down
14 changes: 14 additions & 0 deletions tasks/flydsl2flydsl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# FlyDSL / aiter runtime + JIT artifacts (regenerated on compile/correctness)
__pycache__/
*.pyc
build/
_geak_aiter_jit_gpu*/
*.so

# scratch harness experiments / backups
*_geak_harness*.py
*geak_testharness*.py
*_harness_final.py
*harness_v[0-9].py
*shapes_source*.txt
*.bak
89 changes: 89 additions & 0 deletions tasks/flydsl2flydsl/ARCH_SUPPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# FlyDSL `flydsl2flydsl` — Architecture Support Matrix

**Pinned FlyDSL version:** `v0.2.0` (commit `28a18d328b4882c999864b2df2f8f9fe3fcc8b47`)
**Benchmark hardware:** AMD MI300X = **gfx942 (CDNA3)** and AMD MI355X =
**gfx950 (CDNA4)**

All kernel sources in this task suite are pinned to FlyDSL **v0.2.0**. This suite
contains the gfx942-relevant subset of the v0.2.0 `kernels/`. Kernels that target
other architectures (RDNA4/gfx1250, RDNA/RDNA3) are not runnable on MI300X and
have been removed from this suite; they are preserved unchanged on the
`flydsl2flydsl-skip-tasks-parked` branch for a later pass. The two CDNA4/gfx950
FP8 GEMMs remain here as active tasks selected only on matching hardware.

Architecture-specific tasks carry a machine-readable `platform_support` block;
tasks without that optional block run normally on the selected platform:

```yaml
platform_support:
required_arch: gfx942 # or gfx950
runnable_on_gfx942: true
status: active
```

---

## ✅ Active on MI300X (gfx942) — benchmarked when gfx942 is selected (13)

| Task | Source (`kernels/…`) | Pattern |
|------|----------------------|---------|
| `softmax_kernel` | softmax_kernel.py | L1 reduction |
| `rmsnorm_kernel` | rmsnorm_kernel.py | L1 reduction |
| `layernorm_kernel` | layernorm_kernel.py | L1 reduction |
| `fused_rope_cache_kernel` | fused_rope_cache_kernel.py | L2 fused |
| `silu_and_mul_fq_kernel` | silu_and_mul_fq.py | L2 fused + quant |
| `topk_gating_softmax_kernel` | topk_gating_softmax_kernel.py | L2 MoE gating |
| `moe_sorting_kernel` | moe_sorting_kernel.py | L2 MoE sort |
| `blockscale_preshuffle_gemm_kernel` | blockscale_preshuffle_gemm.py | L3 GEMM (fp8 blockscale) |
| `preshuffle_gemm_v2_kernel` | preshuffle_gemm_v2.py | L3 GEMM (preshuffle) |
| `hgemm_splitk_kernel` | hgemm_splitk.py | L3 GEMM (split-K) |
| `flash_attn_func_kernel` | flash_attn_func.py | L3 attention |
| `pa_decode_swa_kernel` | pa_decode_swa.py | L3 paged-attn decode (SWA) |
| `pa_decode_fp8_kernel` | pa_decode_fp8.py | L3 paged-attn decode (FP8); normal framework task using the provided `aiter` runtime |

## ✅ Active on MI355X (gfx950) — benchmarked when gfx950 is selected (3)

`pa_decode_fp8_kernel` runs as a normal task on gfx950. The following two GEMMs
are gfx950-only:

These two FP8 GEMMs are ported from the HipKittens CDNA4 kernels and emit the
**CDNA4-only 16-byte `buffer_load_lds` intrinsic** (global→LDS direct DMA). The
gfx942 (CDNA3) LLVM backend cannot legalize that operand and aborts at codegen
with `LLVM ERROR: Do not know how to expand this operator's operand!` (process
exits 134). Their `config.yaml` therefore uses `required_arch: gfx950`,
`runnable_on_gfx942: false`, and `status: active`. The runner selects them on
gfx950 and excludes them on gfx942 before workspace setup.

| Task | Source (`kernels/…`) | Scope |
|------|----------------------|-------|
| `pa_decode_fp8_kernel` | pa_decode_fp8.py | Active without a task-specific architecture or dependency skip |
| `fp8_gemm_4wave_kernel` | fp8_gemm_4wave.py | Active on gfx950; 16B `buffer_load_lds` is CDNA4-only |
| `fp8_gemm_8wave_kernel` | fp8_gemm_8wave.py | Active on gfx950; 16B `buffer_load_lds` is CDNA4-only |

### Parked (RDNA4/gfx1250 or RDNA) — moved out of this PR

The following gfx1250 / RDNA kernels are not runnable on MI300X (gfx942) and have
been removed from this suite. They are preserved unchanged on the
`flydsl2flydsl-skip-tasks-parked` branch (along with the shared top-level
`kernels/` helpers they depend on) and can be revisited in a later pass:

- `gemm_fp8fp4_gfx1250_kernel` (gfx1250 — FP8/FP4 WMMA)
- `wmma_gemm_gfx1250_kernel` (gfx1250 — WMMA matrix ops)
- `moe_gemm_2stage_mxscale_gfx1250_kernel` (gfx1250 — MXFP-scale MoE GEMM)
- `moe_gemm_2stage_wmma_gfx1250_kernel` (gfx1250 — WMMA MoE GEMM)
- `rdna3_f16_gemm_kernel` (rdna3 — RDNA3 WMMA f16 GEMM)
- `rdna_f16_gemm_kernel` (rdna — RDNA-only f16 GEMM)
- `rdna_fp8_preshuffle_gemm_kernel` (rdna — RDNA-only fp8 preshuffle GEMM)

---

## Notes
- Each task is self-contained: the FlyDSL helper modules it needs are vendored
under that task's own `kernels/` subfolder. There is no shared top-level
`kernels/` folder in this suite.
- `gfx950` literals appearing alongside `gfx942` are feature-gates (e.g. HW LDS
transpose, K16 MFMA, 16B LDS DMA). Most kernels fall back to a gfx942 path and
still run on MI300X — **but `fp8_gemm_4wave` / `fp8_gemm_8wave` do NOT**: they
unconditionally emit the CDNA4-only 16B `buffer_load_lds` and abort at codegen
on gfx942 (see the gfx950 section above). They remain active tasks, but are
selected only on gfx950.
Loading
Loading