已合并
feat(matmul_story): add one-click run script with auto target recommendation #100
yangyang016创建于 3月23日
feat(matmul_story): add one-click run script with auto target recommendation #100
已合并
共 7 个文件变更+379-21
| @@ -37,6 +37,8 @@ set(RECIPE_VARIANTS quant_matmul_mxfp4) | |||
| 37 | foreach(variant IN LISTS RECIPE_VARIANTS) | 37 | foreach(variant IN LISTS RECIPE_VARIANTS) |
| 38 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/examples/${variant}/scripts/ | 38 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/examples/${variant}/scripts/ |
| 39 | DESTINATION ${MATMUL_INSTALL_PREFIX}/matmul_recipes/${variant} | 39 | DESTINATION ${MATMUL_INSTALL_PREFIX}/matmul_recipes/${variant} |
| 40 | - FILES_MATCHING PATTERN "*.py" | 40 | + FILES_MATCHING |
| 41 | + PATTERN "*.py" | ||
| 42 | + PATTERN "*.sh" | ||
| 41 | ) | 43 | ) |
| 42 | endforeach() | 44 | endforeach() |
| @@ -67,9 +67,39 @@ NPU ARCH 3510 | |||
| 67 | 67 | ||
| 68 | 两个可执行文件在运行结束后都会自动调用 `verify_result.py`,将 NPU 输出与 CPU golden 进行一致性校验。 | 68 | 两个可执行文件在运行结束后都会自动调用 `verify_result.py`,将 NPU 输出与 CPU golden 进行一致性校验。 |
| 69 | 69 | ||
| 70 | -## 构建与运行 | 70 | +## 一键运行(推荐) |
| 71 | 71 | ||
| 72 | -在仓库根目录下完成编译和安装后,进入当前样例目录: | 72 | +仓库提供 `run.sh`(位于 `matmul_recipes/examples/quant_matmul_mxfp4/scripts/`),可一键串联 **构建 → 数据生成 → 算子执行 → 结果校验** 全流程。 |
| 73 | +推荐先进入样例目录再执行,命令更短: | ||
| 74 | + | ||
| 75 | +```bash | ||
| 76 | +cd Samples/2_Performance/matmul_story/matmul_recipes/examples/quant_matmul_mxfp4 | ||
| 77 | + | ||
| 78 | +# 自动构建 + 自动推荐最优算法 + 运行 | ||
| 79 | +bash scripts/run.sh 16 2048 16384 | ||
| 80 | + | ||
| 81 | +# 指定目标可执行文件,跳过重新构建 | ||
| 82 | +bash scripts/run.sh \ | ||
| 83 | + --target quant_matmul_mxfp4_a_full_load --skip-build 16 2048 16384 | ||
| 84 | + | ||
| 85 | +# 查看完整帮助 | ||
| 86 | +bash scripts/run.sh --help | ||
| 87 | +``` | ||
| 88 | + | ||
| 89 | +### run.sh 参数说明 | ||
| 90 | + | ||
| 91 | +| 参数 | 说明 | | ||
| 92 | +|------|------| | ||
| 93 | +| `m k n` | 矩阵维度(必填)。`k` 须为偶数。 | | ||
| 94 | +| `--target <name>` | 指定要运行的可执行文件名。省略时自动调用推荐脚本选择最优目标。 | | ||
林 | |||
| 95 | +| `--skip-build` | 跳过构建/安装阶段,复用已有 `build_out`。 | | ||
林 yangyang016 4月2日 评论: 4月2日 评论: | |||
| 96 | +| `-h, --help` | 显示帮助信息。 | | ||
| 97 | + | ||
| 98 | +如需查看完整算法推荐排名(含耗时表格),请在安装目录下直接运行 `quant_matmul_mxfp4_algorithm_recommend.py`(见下文「手动构建与运行」)。 | ||
| 99 | + | ||
| 100 | +## 手动构建与运行 | ||
| 101 | + | ||
| 102 | +如需手动控制各步骤,可在仓库根目录下完成编译和安装后,进入当前样例目录: | ||
| 73 | 103 | ||
| 74 | ```bash | 104 | ```bash |
| 75 | cmake -S . -B build | 105 | cmake -S . -B build |
| @@ -101,3 +131,15 @@ python3 gen_data.py 16 2048 16384 | |||
| 101 | ```bash | 131 | ```bash |
| 102 | python3 quant_matmul_mxfp4_algorithm_recommend.py 16 2048 16384 | 132 | python3 quant_matmul_mxfp4_algorithm_recommend.py 16 2048 16384 |
| 103 | ``` | 133 | ``` |
| 134 | + | ||
| 135 | +下图为推荐脚本输出的**结构示意**(数值为虚构,仅说明版式): | ||
| 136 | + | ||
| 137 | +```text | ||
| 138 | +[Profile Breakdown] | ||
| 139 | ++--------------------------------+----------+---------+----------+---------+---------+------------+--------------+ | ||
| 140 | +| candidate |kernel(us)| mac(us) |scalar(us)| mte1(us)| mte2(us)|fixpipe(us) |icache_miss(%)| | ||
| 141 | ++================================+==========+=========+==========+=========+=========+============+==============+ | ||
| 142 | +| quant_matmul_mxfp4_swat | 12.345| 1.234 | 0.567| 0.123 | 0.456 | 0.789 | 0.100 | | ||
| 143 | +| quant_matmul_mxfp4_a_full_load | 15.678| 2.100 | 0.800| 0.200 | 0.300 | 0.500 | 0.250 | | ||
| 144 | ++--------------------------------+----------+---------+----------+---------+---------+------------+--------------+ | ||
| 145 | +``` | ||
| @@ -16,7 +16,7 @@ import sys | |||
| 16 | import tempfile | 16 | import tempfile |
| 17 | from dataclasses import dataclass | 17 | from dataclasses import dataclass |
| 18 | from pathlib import Path | 18 | from pathlib import Path |
| 19 | -from typing import List, Optional | 19 | +from typing import List, Optional, Tuple |
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | MSPROF_OUTPUT_DIR_NAME = "msprof_recommend" | 22 | MSPROF_OUTPUT_DIR_NAME = "msprof_recommend" |
| @@ -73,11 +73,13 @@ class CandidateResult: | |||
| 73 | 73 | ||
| 74 | 74 | ||
| 75 | def print_usage(program_name: str) -> None: | 75 | def print_usage(program_name: str) -> None: |
| 76 | - print(f"Usage: {program_name} m k n") | 76 | + print(f"Usage: {program_name} m k n [--print-target]") |
| 77 | print("Args:") | 77 | print("Args:") |
| 78 | print(" m: row of matrix A") | 78 | print(" m: row of matrix A") |
| 79 | print(" k: shared dimension of A and B") | 79 | print(" k: shared dimension of A and B") |
| 80 | print(" n: col of matrix B") | 80 | print(" n: col of matrix B") |
| 81 | + print("Options:") | ||
| 82 | + print(" --print-target: print only the recommended executable name") | ||
| 81 | print(f"Example: {program_name} 1024 4096 2048") | 83 | print(f"Example: {program_name} 1024 4096 2048") |
| 82 | 84 | ||
| 83 | 85 | ||
| @@ -90,19 +92,37 @@ def parse_positive_uint64(arg: str, name: str) -> int: | |||
| 90 | return value | 92 | return value |
| 91 | 93 | ||
| 92 | 94 | ||
| 93 | -def parse_arguments(argv: List[str]) -> tuple[int, int, int]: | 95 | +def parse_arguments(argv: List[str]) -> Tuple[int, int, int, bool]: |
| 94 | if len(argv) >= 2 and argv[1] in ("-h", "--help"): | 96 | if len(argv) >= 2 and argv[1] in ("-h", "--help"): |
| 95 | print_usage(Path(argv[0]).name) | 97 | print_usage(Path(argv[0]).name) |
| 96 | raise SystemExit(0) | 98 | raise SystemExit(0) |
| 97 | - if len(argv) != 4: | 99 | + |
| 100 | + print_target_only = False | ||
| 101 | + positional: List[str] = [] | ||
| 102 | + for arg in argv[1:]: | ||
| 103 | + if arg == "--print-target": | ||
| 104 | + print_target_only = True | ||
| 105 | + continue | ||
| 106 | + if arg.startswith("-"): | ||
| 107 | + raise ValueError(f"Unknown option: {arg}") | ||
| 108 | + positional.append(arg) | ||
| 109 | + | ||
| 110 | + if len(positional) != 3: | ||
| 98 | raise ValueError("Expected exactly 3 arguments: m k n") | 111 | raise ValueError("Expected exactly 3 arguments: m k n") |
| 99 | 112 | ||
| 100 | - m = parse_positive_uint64(argv[1], "m") | 113 | + m = parse_positive_uint64(positional[0], "m") |
| 101 | - k = parse_positive_uint64(argv[2], "k") | 114 | + k = parse_positive_uint64(positional[1], "k") |
| 102 | - n = parse_positive_uint64(argv[3], "n") | 115 | + n = parse_positive_uint64(positional[2], "n") |
| 103 | if k % 2 != 0: | 116 | if k % 2 != 0: |
| 104 | raise ValueError("k must be an even number") | 117 | raise ValueError("k must be an even number") |
| 105 | - return m, k, n | 118 | + return m, k, n, print_target_only |
| 119 | + | ||
| 120 | + | ||
| 121 | +def get_ranked_results(results: List[CandidateResult]) -> List[CandidateResult]: | ||
| 122 | + return sorted( | ||
| 123 | + [item for item in results if item.succeeded], | ||
| 124 | + key=lambda item: item.kernel_time_us if item.kernel_time_us is not None else float("inf"), | ||
| 125 | + ) | ||
| 106 | 126 | ||
| 107 | 127 | ||
| 108 | def resolve_executable(script_dir: Path, executable_name: str) -> Path: | 128 | def resolve_executable(script_dir: Path, executable_name: str) -> Path: |
| @@ -391,7 +411,7 @@ def print_ranking(results: List[CandidateResult]) -> None: | |||
| 391 | 411 | ||
| 392 | def main(argv: List[str]) -> int: | 412 | def main(argv: List[str]) -> int: |
| 393 | try: | 413 | try: |
| 394 | - m, k, n = parse_arguments(argv) | 414 | + m, k, n, print_target_only = parse_arguments(argv) |
| 395 | except ValueError as error: | 415 | except ValueError as error: |
| 396 | print(f"ERROR: {error}") | 416 | print(f"ERROR: {error}") |
| 397 | print_usage(Path(argv[0]).name) | 417 | print_usage(Path(argv[0]).name) |
| @@ -418,8 +438,16 @@ def main(argv: List[str]) -> int: | |||
| 418 | candidate_result = run_candidate(script_dir, candidate, m, k, n) | 438 | candidate_result = run_candidate(script_dir, candidate, m, k, n) |
| 419 | results.append(candidate_result) | 439 | results.append(candidate_result) |
| 420 | 440 | ||
| 441 | + ranked_results = get_ranked_results(results) | ||
| 442 | + if print_target_only: | ||
| 443 | + if not ranked_results: | ||
| 444 | + print("ERROR: No compatible algorithm found for the current shape.") | ||
| 445 | + return 1 | ||
| 446 | + print(ranked_results[0].label) | ||
| 447 | + return 0 | ||
| 448 | + | ||
| 421 | print_ranking(results) | 449 | print_ranking(results) |
| 422 | - return 0 if any(result.succeeded for result in results) else 1 | 450 | + return 0 if ranked_results else 1 |
| 423 | finally: | 451 | finally: |
| 424 | cleanup_msprof_output_dir(msprof_output_dir) | 452 | cleanup_msprof_output_dir(msprof_output_dir) |
| 425 | 453 | ||
| @@ -0,0 +1,125 @@ | |||
| 1 | +# ---------------------------------------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | +set -euo pipefail | ||
| 12 | + | ||
| 13 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 14 | + | ||
| 15 | +find_repo_root() { | ||
| 16 | + local dir="$SCRIPT_DIR" | ||
| 17 | + while [[ "$dir" != "/" ]]; do | ||
| 18 | + if [[ -f "$dir/.ci/build.sh" ]]; then | ||
| 19 | + echo "$dir" | ||
| 20 | + return 0 | ||
| 21 | + fi | ||
| 22 | + dir="$(dirname "$dir")" | ||
| 23 | + done | ||
| 24 | + return 1 | ||
| 25 | +} | ||
| 26 | + | ||
| 27 | +REPO_ROOT="$(find_repo_root || true)" | ||
| 28 | +if [[ -z "$REPO_ROOT" ]]; then | ||
| 29 | + echo "ERROR: cannot locate repo root containing .ci/build.sh" | ||
| 30 | + exit 1 | ||
| 31 | +fi | ||
| 32 | + | ||
| 33 | +INSTALL_DIR="${REPO_ROOT}/build_out/2_Performance/matmul_story/matmul_recipes/quant_matmul_mxfp4" | ||
| 34 | +TARGET="" | ||
| 35 | +SKIP_BUILD=false | ||
| 36 | +M="" | ||
| 37 | +K="" | ||
| 38 | +N="" | ||
| 39 | + | ||
| 40 | +usage() { | ||
| 41 | + cat <<'EOF' | ||
| 42 | +Usage: bash run.sh [OPTIONS] m k n | ||
| 43 | + | ||
| 44 | +Options: | ||
| 45 | + --target <name> Specify executable name to run. | ||
| 46 | + --skip-build Skip build/install stage. | ||
| 47 | + -h, --help Show this help. | ||
| 48 | + | ||
| 49 | +When --target is omitted, run.sh auto-selects target via: | ||
| 50 | + python3 quant_matmul_mxfp4_algorithm_recommend.py --print-target m k n | ||
| 51 | +EOF | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +while [[ $# -gt 0 ]]; do | ||
| 55 | + case "$1" in | ||
| 56 | + --target) | ||
| 57 | + [[ -z "${2:-}" ]] && { echo "ERROR: --target needs a value"; exit 1; } | ||
| 58 | + TARGET="$2" | ||
| 59 | + shift 2 | ||
| 60 | + ;; | ||
| 61 | + --skip-build) | ||
| 62 | + SKIP_BUILD=true | ||
| 63 | + shift | ||
| 64 | + ;; | ||
| 65 | + -h|--help) | ||
| 66 | + usage | ||
| 67 | + exit 0 | ||
| 68 | + ;; | ||
| 69 | + -*) | ||
| 70 | + echo "ERROR: unknown option: $1" | ||
| 71 | + usage | ||
| 72 | + exit 1 | ||
| 73 | + ;; | ||
| 74 | + *) | ||
| 75 | + if [[ -z "$M" ]]; then | ||
| 76 | + M="$1" | ||
| 77 | + elif [[ -z "$K" ]]; then | ||
| 78 | + K="$1" | ||
| 79 | + elif [[ -z "$N" ]]; then | ||
| 80 | + N="$1" | ||
| 81 | + else | ||
| 82 | + echo "ERROR: unexpected argument: $1" | ||
| 83 | + usage | ||
| 84 | + exit 1 | ||
| 85 | + fi | ||
| 86 | + shift | ||
| 87 | + ;; | ||
| 88 | + esac | ||
| 89 | +done | ||
| 90 | + | ||
| 91 | +if [[ -z "$M" || -z "$K" || -z "$N" ]]; then | ||
| 92 | + echo "ERROR: m k n are required" | ||
| 93 | + usage | ||
| 94 | + exit 1 | ||
| 95 | +fi | ||
| 96 | + | ||
| 97 | +if [[ "$SKIP_BUILD" != true ]]; then | ||
| 98 | + bash "${REPO_ROOT}/.ci/build.sh" | ||
| 99 | +fi | ||
| 100 | + | ||
| 101 | +if [[ ! -d "$INSTALL_DIR" ]]; then | ||
| 102 | + echo "ERROR: install dir not found: $INSTALL_DIR" | ||
| 103 | + echo "Hint: remove --skip-build for full build/install." | ||
| 104 | + exit 1 | ||
| 105 | +fi | ||
| 106 | + | ||
| 107 | +cd "$INSTALL_DIR" | ||
| 108 | + | ||
| 109 | +python3 gen_data.py "$M" "$K" "$N" | ||
| 110 | + | ||
| 111 | +if [[ -z "$TARGET" ]]; then | ||
| 112 | + TARGET="$(python3 quant_matmul_mxfp4_algorithm_recommend.py --print-target "$M" "$K" "$N")" | ||
| 113 | +fi | ||
| 114 | + | ||
| 115 | +if [[ -z "$TARGET" ]]; then | ||
| 116 | + echo "ERROR: failed to select a target executable" | ||
| 117 | + exit 1 | ||
| 118 | +fi | ||
| 119 | + | ||
| 120 | +if [[ ! -x "./$TARGET" ]]; then | ||
| 121 | + echo "ERROR: executable not found: $INSTALL_DIR/$TARGET" | ||
| 122 | + exit 1 | ||
| 123 | +fi | ||
| 124 | + | ||
| 125 | +"./$TARGET" "$M" "$K" "$N" | ||
| @@ -20,5 +20,7 @@ add_subdirectory(7_fullload) | |||
| 20 | 20 | ||
| 21 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scripts/ | 21 | install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scripts/ |
| 22 | DESTINATION ${MATMUL_INSTALL_PREFIX}/matmul_tutorials | 22 | DESTINATION ${MATMUL_INSTALL_PREFIX}/matmul_tutorials |
| 23 | - FILES_MATCHING PATTERN "*.py" | 23 | + FILES_MATCHING |
| 24 | + PATTERN "*.py" | ||
| 25 | + PATTERN "*.sh" | ||
| 24 | ) | 26 | ) |
| @@ -24,9 +24,39 @@ | |||
| 24 | - `matmul_tutorial_mxfp4_memery_access_coalescing`(Step 6) | 24 | - `matmul_tutorial_mxfp4_memery_access_coalescing`(Step 6) |
| 25 | - `matmul_tutorial_mxfp4_a_fullload`(Step 7) | 25 | - `matmul_tutorial_mxfp4_a_fullload`(Step 7) |
| 26 | 26 | ||
| 27 | -## 构建与运行 | 27 | +## 一键运行(推荐) |
| 28 | 28 | ||
| 29 | -在仓库根目录执行编译安装,并进入教程安装目录: | 29 | +仓库提供 `scripts/run.sh`,可一键串联 **构建 → 数据生成 → 算子执行 → 结果校验** 全流程。 |
| 30 | +建议先进入 `matmul_tutorials/` 目录再执行: | ||
| 31 | + | ||
| 32 | +```bash | ||
| 33 | +cd Samples/2_Performance/matmul_story/matmul_tutorials | ||
| 34 | + | ||
| 35 | +# 指定 Step 运行 | ||
| 36 | +bash scripts/run.sh --target matmul_tutorial_mxfp4_swat 256 256 256 | ||
| 37 | + | ||
| 38 | +# 自动构建 + 未指定 target 时运行 Step 0(matmul_tutorial_mxfp4_base) | ||
| 39 | +bash scripts/run.sh 256 256 256 | ||
Y 确认下target是否需要传 ![]() ![]() | |||
| 40 | + | ||
| 41 | +# 跳过构建阶段 | ||
| 42 | +bash scripts/run.sh --target matmul_tutorial_mxfp4_swat_balance --skip-build 256 256 256 | ||
| 43 | + | ||
| 44 | +# 查看完整帮助 | ||
| 45 | +bash scripts/run.sh --help | ||
| 46 | +``` | ||
| 47 | + | ||
| 48 | +### run.sh 参数说明 | ||
| 49 | + | ||
| 50 | +| 参数 | 说明 | | ||
| 51 | +|------|------| | ||
| 52 | +| `m k n` | 矩阵维度(必填)。`k` 须为偶数。 | | ||
| 53 | +| `--target <name>` | 指定要运行的教程可执行文件名;省略时默认 Step 0(`matmul_tutorial_mxfp4_base`) | | ||
| 54 | +| `--skip-build` | 跳过构建/安装阶段,复用已有 `build_out`。 | | ||
| 55 | +| `-h, --help` | 显示帮助信息。 | | ||
| 56 | + | ||
| 57 | +## 手动构建与运行 | ||
| 58 | + | ||
| 59 | +如需手动控制各步骤,在仓库根目录执行编译安装,并进入教程安装目录: | ||
| 30 | 60 | ||
| 31 | ```bash | 61 | ```bash |
| 32 | cmake -S . -B build | 62 | cmake -S . -B build |
| @@ -43,13 +73,8 @@ python3 gen_data.py 256 256 256 | |||
| 43 | 73 | ||
| 44 | # 2) 运行某个 Step(示例:Step 2) | 74 | # 2) 运行某个 Step(示例:Step 2) |
| 45 | ./matmul_tutorial_mxfp4_swat 256 256 256 | 75 | ./matmul_tutorial_mxfp4_swat 256 256 256 |
| 46 | - | ||
| 47 | -# 3) 结果校验(若可执行文件未自动校验,可手动执行) | ||
| 48 | -python3 verify_result.py 256 256 | ||
| 49 | ``` | 76 | ``` |
| 50 | 77 | ||
| 51 | -> 调用约定:教程程序以自身所在目录作为工作目录,读写 `./input` 和 `./output`,并在该目录下调用 `verify_result.py`。 | ||
| 52 | - | ||
| 53 | ## 相关文档 | 78 | ## 相关文档 |
| 54 | 79 | ||
| 55 | - 顶层说明:[`../README.md`](../README.md) | 80 | - 顶层说明:[`../README.md`](../README.md) |
| @@ -0,0 +1,134 @@ | |||
| 1 | +# ---------------------------------------------------------------------------------------------------------- | ||
| 2 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 3 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 4 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 5 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 6 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 7 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 8 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 9 | +# ---------------------------------------------------------------------------------------------------------- | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +set -euo pipefail | ||
| 13 | + | ||
| 14 | +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| 15 | +find_repo_root() { | ||
| 16 | + local dir="$SCRIPT_DIR" | ||
| 17 | + while [[ "$dir" != "/" ]]; do | ||
| 18 | + if [[ -f "$dir/.ci/build.sh" ]]; then | ||
| 19 | + echo "$dir" | ||
| 20 | + return 0 | ||
| 21 | + fi | ||
| 22 | + dir="$(dirname "$dir")" | ||
| 23 | + done | ||
| 24 | + return 1 | ||
| 25 | +} | ||
| 26 | +REPO_ROOT="$(find_repo_root || true)" | ||
| 27 | +if [[ -z "$REPO_ROOT" ]]; then | ||
| 28 | + echo "ERROR: cannot locate repo root containing .ci/build.sh" | ||
| 29 | + exit 1 | ||
| 30 | +fi | ||
| 31 | +INSTALL_DIR="${REPO_ROOT}/build_out/2_Performance/matmul_story/matmul_tutorials" | ||
| 32 | +DEFAULT_TUTORIAL_TARGET="matmul_tutorial_mxfp4_base" | ||
| 33 | + | ||
| 34 | +TARGET="" | ||
| 35 | +SKIP_BUILD=false | ||
| 36 | +M="" | ||
| 37 | +K="" | ||
| 38 | +N="" | ||
| 39 | + | ||
| 40 | +usage() { | ||
| 41 | + cat <<'EOF' | ||
| 42 | +Usage: bash run.sh [OPTIONS] m k n | ||
| 43 | + | ||
| 44 | +One-stop script: build, generate data, run, and verify a matmul tutorial step. | ||
| 45 | + | ||
| 46 | +Positional arguments: | ||
| 47 | + m Row count of matrix A | ||
| 48 | + k Shared dimension of A and B (must be even) | ||
| 49 | + n Column count of matrix B | ||
| 50 | + | ||
| 51 | +Options: | ||
| 52 | + --target <name> Tutorial executable to run (e.g. matmul_tutorial_mxfp4_swat). | ||
| 53 | + When omitted, defaults to Step 0: matmul_tutorial_mxfp4_base. | ||
| 54 | + --skip-build Skip the build/install phase (reuse existing build_out). | ||
| 55 | + -h, --help Show this help message and exit. | ||
| 56 | + | ||
| 57 | +Available tutorial executables (Step 0 – Step 7): | ||
| 58 | + matmul_tutorial_mxfp4_base (Step 0) | ||
| 59 | + matmul_tutorial_mxfp4_pingpong (Step 1) | ||
| 60 | + matmul_tutorial_mxfp4_swat (Step 2) | ||
| 61 | + matmul_tutorial_mxfp4_swat_balance (Step 3) | ||
| 62 | + matmul_tutorial_mxfp4_swat_unitflag (Step 4) | ||
| 63 | + matmul_tutorial_mxfp4_half1l1_ping_halfl1_pong (Step 5) | ||
| 64 | + matmul_tutorial_mxfp4_memery_access_coalescing (Step 6) | ||
| 65 | + matmul_tutorial_mxfp4_a_fullload (Step 7) | ||
| 66 | + | ||
| 67 | +Examples: | ||
| 68 | + # Run with explicit target | ||
| 69 | + bash scripts/run.sh --target matmul_tutorial_mxfp4_swat 256 256 256 | ||
| 70 | + | ||
| 71 | + # Default Step 0 + skip rebuild | ||
| 72 | + bash scripts/run.sh --skip-build 256 256 256 | ||
| 73 | + | ||
| 74 | +EOF | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +while [[ $# -gt 0 ]]; do | ||
| 78 | + case "$1" in | ||
| 79 | + --target) | ||
| 80 | + [[ -z "${2:-}" ]] && { echo "ERROR: --target requires a value"; usage; exit 1; } | ||
| 81 | + TARGET="$2"; shift 2 ;; | ||
| 82 | + --skip-build) | ||
| 83 | + SKIP_BUILD=true; shift ;; | ||
| 84 | + -h|--help) | ||
| 85 | + usage; exit 0 ;; | ||
| 86 | + -*) | ||
| 87 | + echo "ERROR: unknown option: $1"; usage; exit 1 ;; | ||
| 88 | + *) | ||
| 89 | + if [[ -z "$M" ]]; then M="$1" | ||
| 90 | + elif [[ -z "$K" ]]; then K="$1" | ||
| 91 | + elif [[ -z "$N" ]]; then N="$1" | ||
| 92 | + else echo "ERROR: unexpected argument: $1"; usage; exit 1 | ||
| 93 | + fi | ||
| 94 | + shift ;; | ||
| 95 | + esac | ||
| 96 | +done | ||
| 97 | + | ||
| 98 | +if [[ -z "$M" || -z "$K" || -z "$N" ]]; then | ||
| 99 | + echo "ERROR: m, k, n are required." | ||
| 100 | + usage | ||
| 101 | + exit 1 | ||
| 102 | +fi | ||
| 103 | + | ||
| 104 | +# ── 1. Build ──────────────────────────────────────────────────────────────── | ||
| 105 | +if [[ "$SKIP_BUILD" != true ]]; then | ||
| 106 | + echo "=== Building project (via .ci/build.sh) ===" | ||
| 107 | + bash "${REPO_ROOT}/.ci/build.sh" | ||
| 108 | +fi | ||
| 109 | + | ||
| 110 | +if [[ ! -d "$INSTALL_DIR" ]]; then | ||
| 111 | + echo "ERROR: Install directory not found: $INSTALL_DIR" | ||
| 112 | + echo " Run without --skip-build to perform a full build first." | ||
| 113 | + exit 1 | ||
| 114 | +fi | ||
| 115 | +cd "$INSTALL_DIR" | ||
| 116 | + | ||
| 117 | +# ── 2. Generate test data ────────────────────────────────────────────────── | ||
| 118 | +echo "=== Generating test data (m=$M k=$K n=$N) ===" | ||
| 119 | +python3 gen_data.py "$M" "$K" "$N" | ||
| 120 | + | ||
| 121 | +# ── 3. Determine target executable ───────────────────────────────────────── | ||
| 122 | +if [[ -z "$TARGET" ]]; then | ||
| 123 | + TARGET="${DEFAULT_TUTORIAL_TARGET}" | ||
| 124 | + echo " Using default Step 0 target: $TARGET" | ||
| 125 | +fi | ||
| 126 | + | ||
| 127 | +if [[ ! -x "./$TARGET" ]]; then | ||
| 128 | + echo "ERROR: Executable not found or not executable: $INSTALL_DIR/$TARGET" | ||
| 129 | + exit 1 | ||
| 130 | +fi | ||
| 131 | + | ||
| 132 | +# ── 4. Run ────────────────────────────────────────────────────────────────── | ||
| 133 | +echo "=== Running ./$TARGET $M $K $N ===" | ||
| 134 | +"./$TARGET" "$M" "$K" "$N" | ||


需要验证不带target的效果