with one click
cpu-basics
CPU C++ 算子核心概念、标准结构模式、KernelBench 代码规范和内嵌扩展方法
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
CPU C++ 算子核心概念、标准结构模式、KernelBench 代码规范和内嵌扩展方法
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
AscendC direct-invoke 崩溃/挂起修复索引:Kernel timeout、hang、Segmentation Fault、aic error、buffer 死锁、plog/memcheck 调试。
AscendC direct-invoke 精度失败修复索引:输出全 0/随机值、DataCopy 对齐、EnQue/DeQue 同步、FP16/FP32 精度、Cast RoundMode、DumpTensor 分段定位。
AscendC direct-invoke 工程契约:WA 使用 kernel.py + ascendc_op/,ModelNew 调用 torch.ops.npu.*,adapter 负责复制工程、CMake 构建和 npu-arch patch。适用于 dsl=ascendc 的 autoresearch 任务。
把注册式 AscendC 算子迁移为 direct-invoke 工程的保真原则:kernel 算法和 tiling 公式不乱改,只替换注册框架胶水、入口 ABI、host launch 与 PyTorch extension。
CATLASS TileShape 与 on-chip 缓存容量约束:L1/L0A/L0B/L0C 预算公式、fp16/fp32 Pingpong 双缓冲、512B 对齐与排布对 Tile 选型的影响。调参前必读。
CATLASS Gemm 性能调优:DispatchPolicy、Tile 与分核负载均衡、Swizzle、何时用 padding/Split-K/Preload。面向 AR 修改 catlass_kernel.asc 中的类型别名。
| name | cpu-basics |
| description | CPU C++ 算子核心概念、标准结构模式、KernelBench 代码规范和内嵌扩展方法 |
| category | fundamental |
| version | 1.0.0 |
| metadata | {"backend":"cpu","dsl":"cpp","operator_patterns":"all","architecture":"x86_64, aarch64"} |
PYBIND11_MODULE 注册的 C++ 函数,编译后在 CPU 上执行load_inline 动态编译加载所有 CPU C++ 内核都遵循相同的五步结构模式:
torch::Tensor standard_kernel(torch::Tensor x) {
// 1. 确保输入张量是连续的
if (!x.is_contiguous()) {
x = x.contiguous();
}
// 2. 检查数据类型,支持多种类型
torch::ScalarType dtype = x.scalar_type();
bool need_convert = (dtype != torch::kFloat32 && dtype != torch::kFloat64 &&
dtype != torch::kInt32 && dtype != torch::kInt64);
torch::Tensor input = need_convert ? x.to(torch::kFloat32) : x;
// 3. 创建输出张量
torch::Tensor output = torch::zeros_like(input);
// 4. 根据数据类型分发计算
if (input.scalar_type() == torch::kFloat32) {
auto x_ptr = input.data_ptr<float>();
auto out_ptr = output.data_ptr<float>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0f, x_ptr[i]); // ReLU: max(0, x)
}
} else if (input.scalar_type() == torch::kFloat64) {
auto x_ptr = input.data_ptr<double>();
auto out_ptr = output.data_ptr<double>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0, x_ptr[i]);
}
} else if (input.scalar_type() == torch::kInt32) {
auto x_ptr = input.data_ptr<int32_t>();
auto out_ptr = output.data_ptr<int32_t>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0, x_ptr[i]);
}
} else if (input.scalar_type() == torch::kInt64) {
auto x_ptr = input.data_ptr<int64_t>();
auto out_ptr = output.data_ptr<int64_t>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0L, x_ptr[i]);
}
}
// 5. 转换回原类型
if (need_convert) {
output = output.to(dtype);
}
return output;
}
重要: 生成的代码必须遵循 KernelBench 格式规范,使用 Python 模块内嵌 C++ 代码 的方式。
下方模板可作为 CPU KernelBench 算子的起始实现。
import torch
from torch.utils.cpp_extension import load_inline
# 内联C++扩展代码
cpp_source = """
#include <torch/extension.h>
torch::Tensor op_name_kernel(torch::Tensor x) {
// 1. 确保输入张量是连续的
if (!x.is_contiguous()) {
x = x.contiguous();
}
// 2. 检查数据类型,支持多种类型
torch::ScalarType dtype = x.scalar_type();
bool need_convert = (dtype != torch::kFloat32 && dtype != torch::kFloat64 &&
dtype != torch::kInt32 && dtype != torch::kInt64);
torch::Tensor input = need_convert ? x.to(torch::kFloat32) : x;
// 3. 创建输出张量
torch::Tensor output = torch::zeros_like(input);
// 4. 根据数据类型分发计算
if (input.scalar_type() == torch::kFloat32) {
auto x_ptr = input.data_ptr<float>();
auto out_ptr = output.data_ptr<float>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
// 具体的算子计算逻辑
out_ptr[i] = compute_logic(x_ptr[i]);
}
} else if (input.scalar_type() == torch::kFloat64) {
// 同样的逻辑,但使用 double 类型
auto x_ptr = input.data_ptr<double>();
auto out_ptr = output.data_ptr<double>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = compute_logic(x_ptr[i]);
}
} else if (input.scalar_type() == torch::kInt32) {
auto x_ptr = input.data_ptr<int32_t>();
auto out_ptr = output.data_ptr<int32_t>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = compute_logic(x_ptr[i]);
}
} else if (input.scalar_type() == torch::kInt64) {
auto x_ptr = input.data_ptr<int64_t>();
auto out_ptr = output.data_ptr<int64_t>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = compute_logic(x_ptr[i]);
}
}
// 5. 转换回原类型
if (need_convert) {
output = output.to(dtype);
}
return output;
}
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.def("op_name_kernel", &op_name_kernel, "CPU op_name operator");
}
"""
# 动态加载C++扩展
op_name_module = load_inline(
name="custom_op_name",
cpp_sources=cpp_source,
extra_cflags=["-O3"],
verbose=True
)
# Python接口函数
def op_name(x: torch.Tensor) -> torch.Tensor:
if x.device.type != "cpu":
x = x.cpu()
return op_name_module.op_name_kernel(x)
load_inline 动态编译并加载扩展PYBIND11_MODULE 宏注册算子适用于激活函数、逐元素运算等简单操作。
// ReLU: max(0, x)
torch::Tensor relu_kernel(torch::Tensor x) {
if (!x.is_contiguous()) x = x.contiguous();
torch::ScalarType dtype = x.scalar_type();
bool need_convert = (dtype != torch::kFloat32 && dtype != torch::kFloat64);
torch::Tensor input = need_convert ? x.to(torch::kFloat32) : x;
torch::Tensor output = torch::zeros_like(input);
if (input.scalar_type() == torch::kFloat32) {
auto x_ptr = input.data_ptr<float>();
auto out_ptr = output.data_ptr<float>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0f, x_ptr[i]);
}
} else if (input.scalar_type() == torch::kFloat64) {
auto x_ptr = input.data_ptr<double>();
auto out_ptr = output.data_ptr<double>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0, x_ptr[i]);
}
}
if (need_convert) output = output.to(dtype);
return output;
}
适用于求和、最大值、最小值等聚合操作。
// Sum reduction: 沿指定维度求和
torch::Tensor sum_reduction_kernel(torch::Tensor x) {
if (!x.is_contiguous()) x = x.contiguous();
torch::ScalarType dtype = x.scalar_type();
bool need_convert = (dtype != torch::kFloat32 && dtype != torch::kFloat64);
torch::Tensor input = need_convert ? x.to(torch::kFloat32) : x;
int64_t numel = input.numel();
torch::Tensor output;
if (input.scalar_type() == torch::kFloat32) {
auto x_ptr = input.data_ptr<float>();
float result = 0.0f;
for (int64_t i = 0; i < numel; ++i) {
result += x_ptr[i]; // 求和归约
}
output = torch::tensor({result}, torch::kFloat32);
} else if (input.scalar_type() == torch::kFloat64) {
auto x_ptr = input.data_ptr<double>();
double result = 0.0;
for (int64_t i = 0; i < numel; ++i) {
result += x_ptr[i];
}
output = torch::tensor({result}, torch::kFloat64);
}
if (need_convert) output = output.to(dtype);
return output;
}
确保所有操作都有适当的边界检查和错误处理。
torch::Tensor safe_operation_kernel(torch::Tensor x) {
// 1. 检查张量有效性
TORCH_CHECK(x.numel() > 0, "Input tensor cannot be empty");
TORCH_CHECK(x.dim() > 0, "Input tensor must have at least one dimension");
// 2. 确保张量连续性
if (!x.is_contiguous()) {
x = x.contiguous();
}
// 3. 类型检查和转换
torch::ScalarType dtype = x.scalar_type();
bool need_convert = (dtype != torch::kFloat32 && dtype != torch::kFloat64);
torch::Tensor input = need_convert ? x.to(torch::kFloat32) : x;
torch::Tensor output = torch::zeros_like(input);
// 4. 安全的数据处理
if (input.scalar_type() == torch::kFloat32) {
auto x_ptr = input.data_ptr<float>();
auto out_ptr = output.data_ptr<float>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0f, x_ptr[i]);
}
} else if (input.scalar_type() == torch::kFloat64) {
auto x_ptr = input.data_ptr<double>();
auto out_ptr = output.data_ptr<double>();
int64_t numel = input.numel();
for (int64_t i = 0; i < numel; ++i) {
out_ptr[i] = std::max(0.0, x_ptr[i]);
}
}
if (need_convert) output = output.to(dtype);
return output;
}
// 类型检查
torch::ScalarType dtype = x.scalar_type();
bool is_float32 = (dtype == torch::kFloat32);
bool is_float64 = (dtype == torch::kFloat64);
bool is_int32 = (dtype == torch::kInt32);
bool is_int64 = (dtype == torch::kInt64);
// 类型转换
torch::Tensor input = x.to(torch::kFloat32); // 转换为 float32
torch::Tensor output = result.to(dtype); // 转换回原类型
if (!x.is_contiguous()) {
x = x.contiguous();
}
// float32 指针
auto x_ptr = input.data_ptr<float>();
auto out_ptr = output.data_ptr<float>();
// float64 指针
auto x_ptr = input.data_ptr<double>();
auto out_ptr = output.data_ptr<double>();
// int32 指针
auto x_ptr = input.data_ptr<int32_t>();
auto out_ptr = output.data_ptr<int32_t>();
// int64 指针
auto x_ptr = input.data_ptr<int64_t>();
auto out_ptr = output.data_ptr<int64_t>();
// 创建输出张量
torch::Tensor output = torch::zeros_like(input); // 同形状零张量
torch::Tensor output = torch::ones_like(input); // 同形状单位张量
torch::Tensor output = input.clone(); // 克隆张量
// 张量属性
int64_t numel = input.numel(); // 元素总数
int64_t dim = input.dim(); // 维度数
torch::IntArrayRef shape = input.sizes(); // 形状
TORCH_CHECK(x.numel() > 0, "Input tensor cannot be empty");
TORCH_CHECK(x.dim() > 0, "Input tensor must have at least one dimension");
omp_get_thread_num()等OpenMP运行时API// ❌ 错误:在受限上下文中调用OpenMP API
std::mt19937 gen(seed + omp_get_thread_num()); // 编译错误!
// ✅ 正确:在并行区域内正常调用
#pragma omp parallel
{
int tid = omp_get_thread_num(); // 正确
std::mt19937 gen(seed + tid);
}
本文件的模板、API 注意事项和优化建议已经覆盖 CPU KernelBench 算子的常用实现路径。