SuperAPI AI Directory

external-gitcode-ascend-ascendc-operator-compile-debug

Coding & development

View repository

Updated 10-15 17:19

About this skill

AscendC Operator Compilation, Installation and Accuracy Testing

Compile the ascend-kernel project, install the whl package, generate and run accuracy tests. Usually called by the ascendc-operator-code-gen skill after code generation is complete.

Prerequisites

  • op_host, op_kernel code has been generated
  • ops.h, register.cpp, csrc/CMakeLists.txt have been updated (framework adaptation complete)
  • CANN environment is available

Workflow

Phase 0: Environment Preparation

MANDATORY — The environment must be loaded before every shell command. Hardcoding paths is prohibited, and searching for paths on your own is prohibited.

Obtain Environment Information

If an upstream skill (such as ascendc-operator-dev) has already confirmed the CANN path and Conda environment name, use them directly without asking again.

If environment information was not obtained from upstream, confirm it according to the following process:

CANN Environment:

  1. Check the environment variable ASCEND_HOME_PATH(echo $ASCEND_HOME_PATH)
  2. If already set: use it directly, and treat it as the CANN_PATH
  3. If not set:MUST ask the user for the CANN installation path

Conda Environment:

  1. Check whether a conda environment is currently activated (echo $CONDA_DEFAULT_ENV)
  2. If already activated(value is not base and is not empty): use the current environment directly
  3. If not activated or is base:MUST ask the user for the conda environment name

Activate Environment

After confirmation, load before every shell command:

source ${CANN_PATH}/*/set_env.sh
conda activate <env_name>

Practical experience: Not loading the environment will cause: (1) build.sh cannot find the AscendC compiler; (2) the pip/python versions are incorrect; (3) torch_npu cannot be found when running tests. It is recommended to source once before every shell command.

Phase 1: Compilation

cd ascend-kernel
chmod +x build.sh  # 模板复制后可能缺少执行权限
bash build.sh

Determining Compilation Success:

ls ./output/ascend_kernel*.whl

The presence of the .whl file indicates success.

Compilation Failure: enter the troubleshooting loop (see below), at most 3 times.

Phase 2: Installation

cd ascend-kernel
pip install output/ascend_kernel*.whl --force-reinstall --no-deps

Phase 3: Generating Test Files

First check whether ascend-kernel/tests/test_<op_name>.py already exists; if it exists, skip generation.

If it does not exist, under ascend-kernel/tests/ create test_<op_name>.py。

Test File Structure:

#!/usr/bin/env python3
"""Unit tests for <op_name> NPU operator."""

import torch
import torch_npu
import pytest

try:
    import ascend_kernel
except ImportError:
    import os, glob
    script_dir = os.path.dirname(os.path.abspath(__file__))
    project_root = os.path.dirname(script_dir)
    lib_pattern = os.path.join(project_root, "python/ascend_kernel/ascend_kernel/lib/*.so")
    lib_files = glob.glob(lib_pattern)
    if lib_files:
        torch.ops.load_library(lib_files[0])
    else:
        raise ImportError("Could not find ascend_kernel library")


def is_npu_available():
    try:
        return torch.npu.is_available()
    except Exception:
        return False


@pytest.fixture(scope="module")
def device():
    if not is_npu_available():
        pytest.skip("NPU not available")
    return torch.device("npu:0")


class Test<OpName>:

    @pytest.mark.parametrize("shape", [
        # 根据算子特点选择典型 shape
    ])
    @pytest.mark.parametrize("dtype", [torch.float16, torch.float32])
    def test_basic(self, device, shape, dtype):
        x = torch.randn(shape, dtype=dtype, device=device)

        npu_result = torch.ops.npu.<op_name>(x)
        cpu_reference = <pytorch_reference>(x.cpu())

        rtol, atol = (1e-3, 1e-3) if dtype == torch.float16 else (1e-5, 1e-5)
        assert torch.allclose(npu_result.cpu(), cpu_reference, rtol=rtol, atol=atol), \
            f"max diff = {(npu_result.cpu() - cpu_reference).abs().max().item()}"


def run_simple_test():
    """简单功能测试(无精度校验)"""
    if not is_npu_available():
        print("NPU not available, skipping test")
        return False

    device = torch.device("npu:0")
    try:
        for dtype in [torch.float16, torch.float32]:
            x = torch.randn(1024, dtype=dtype, device=device)
            result = torch.ops.npu.<op_name>(x)
            print(f"dtype={dtype}, output shape={result.shape} OK")
        print("Test PASSED!")
        return True
    except Exception as e:
        print(f"Test FAILED: {e}")
        import traceback
        traceback.print_exc()
        return False


if __name__ == "__main__":
    run_simple_test()

Key Points of Test Case Design:

Scenario Parameterized Content Accuracy Standard
Basic shape 1D/2D/3D/4D fp32: rtol=1e-5, fp16/bf16: rtol=1e-3
Different sizes 1, 7, 256, 65536, 1M Same as above
Boundary values All zeros, all negative, maximum values Absolute value comparison
Operator-specific According to the constraints in the design document According to operator characteristics

CPU Reference Implementation: Use native PyTorch functions (such as torch.acosh、torch.softmax , etc.). If there is no direct equivalent, write the Python reference logic by hand.

Accuracy Comparison Strategy:

  • FP32 NPU result vs FP32 CPU result: compare directly
  • FP16 NPU result vs CPU reference: first compute on the CPU with FP32, then convert back with .to(dtype) and compare

Test Data Generation Notes:

  • Check the valid input range of the operator (e.g., acosh requires x >= 1, log requires x > 0, sqrt requires x >= 0)
  • When generating data, use torch.rand() * scale + offset to ensure it falls within the valid range
  • Include boundary value tests (e.g., acosh(1)=0, relu(0)=0)

Stage 4: Run Tests

Functional Test(must pass):

cd ascend-kernel && python tests/test_<op_name>.py

Precision Test(recommended to run):

cd ascend-kernel && pytest tests/test_<op_name>.py -v

Test Pass Criteria:

  • Functional test: The program exits normally (exit code 0)
  • Precision test: All pytest cases pass

Troubleshooting Loop (up to 3 times)

失败 → 分析错误日志 → 定位错误文件:行号 → 修复代码 → 重新编译/测试
  ↓ (仍失败)
第 2 次 → 重新分析,检查遗漏的 include/声明/CMakeLists
  ↓ (仍失败)
第 3 次 → 深入检查 API 用法、类型匹配、CMake 配置
  ↓ (仍失败)
停止 → 向用户报告详细错误信息和已尝试的修复

Compilation Error Decision Tree

Error Symptom Modification Location Investigation Direction
undeclared identifier ops.h or op_host cpp Missing function declaration or include
no matching function op_host cpp Parameter types/order do not match the kernel entry point
undefined reference / linker error csrc/CMakeLists.txt Source file not added to OP_SRCS or ascendc_library
redefinition ops.h / register.cpp Duplicate definition
AscendC kernel compilation error op_kernel cpp API usage or type not supported

Test Error Decision Tree

Error Symptom Investigation Direction
ImportError: ascend_kernel whl not installed or so not generated
RuntimeError: ... not found The registration name in register.cpp does not match the call name
allclose failed Computation logic or precision issue, check the kernel Compute function
shape mismatch Incorrect tensor shape calculation output by op_host
SIGABRT / device error Tiling parameter error or UB out-of-bounds

Anti-Pattern Checklist

  • NEVER Hardcoding CANN paths or Conda environment paths; must be obtained from upstream or asked to the user
  • NEVER Searching the file system yourself to guess CANN or Conda paths
  • NEVER Modifying cmake/ or csrc/utils/ files under
  • NEVER Deleting the registration code of other operators during troubleshooting
  • NEVER Skipping functional testing and directly performing precision testing
  • NEVER Ignoring compilation warnings (especially those related to type truncation)
  • NEVER Passing rvalues (temporary objects, literals, expressions) in EXEC_KERNEL_CMD
  • NEVER Continuing to try after failing more than 3 troubleshooting attempts; should report to the user

Modifiable File Scope

File Modification Content
csrc/ops/<op_name>/op_host/*.cpp Host-side logic
csrc/ops/<op_name>/op_kernel/*.cpp Kernel-side logic
csrc/ops.h Function declaration
csrc/register.cpp Operator registration
csrc/CMakeLists.txt Compilation source file list
tests/test_<op_name>.py Test file