已合并
[feat]Add torch triton-runtime headers, demo and README #36851
cmy_melody创建于 5月27日
[feat]Add torch triton-runtime headers, demo and README #36851
已合并
共 16 个文件变更+952-0
| @@ -0,0 +1,56 @@ | |||
| 1 | +# libtorch_triton_ascend | ||
| 2 | + | ||
| 3 | +## 跑demo | ||
| 4 | + | ||
| 5 | +demo.cpp 包含三个示例: | ||
| 6 | + | ||
| 7 | +1. **Add Kernel (explicit grid)** - 使用显式 grid 的向量加法 kernel,展示最基本的 Triton kernel 调用方式 | ||
| 8 | +2. **Add Kernel (C++ lambda grid)** - 使用 C++ lambda 函数计算 grid,类似 Triton 的 `lambda meta`,完全在 C++ 端解析无需 Python 参与 | ||
| 9 | +3. **LayerNorm Kernel** - LayerNorm 算子示例,展示更复杂的 kernel 参数传递和计算 | ||
| 10 | + | ||
| 11 | +运行流程: | ||
| 12 | + | ||
| 13 | +1)generate libtriton_runtime.so | ||
| 14 | + | ||
| 15 | +```bash | ||
| 16 | +cd triton_runtime | ||
| 17 | +bash build.sh | ||
| 18 | +cd .. | ||
| 19 | +``` | ||
| 20 | + | ||
| 21 | +2)run demo | ||
| 22 | + | ||
| 23 | +```bash | ||
| 24 | +bash examples/run_demo.sh | ||
| 25 | +``` | ||
| 26 | + | ||
| 27 | +3)期望输出 | ||
| 28 | + | ||
| 29 | +```text | ||
| 30 | +... | ||
| 31 | +=== LayerNorm Kernel === | ||
| 32 | +[KernelRegistry] 'layer_norm_kernel': def layer_norm_kernel(output_ptr, input_ptr, weight_ptr, bias_ptr, n_rows: [constexpr], n_cols: [constexpr], stride, eps, BLOCK_SIZE: [constexpr]) | ||
| 33 | +C++ BLOCK_SIZE: 512 | ||
| 34 | +C++ triton out[0,:5]: 0.1781 | ||
| 35 | +-1.6806 | ||
| 36 | +-1.2184 | ||
| 37 | +-0.3596 | ||
| 38 | +-0.9843 | ||
| 39 | +[ npuFloatType{5} ] | ||
| 40 | +C++ torch ref[0,:5]: 0.1781 | ||
| 41 | +-1.6806 | ||
| 42 | +-1.2184 | ||
| 43 | +-0.3596 | ||
| 44 | +-0.9843 | ||
| 45 | +[ npuFloatType{5} ] | ||
| 46 | +C++: max diff: 7.15256e-07 | ||
| 47 | +C++: match: YES | ||
| 48 | + registered: layer_norm_kernel | ||
| 49 | + registered: add_kernel | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +4)打开环境变量查看详细日志 | ||
| 53 | + | ||
| 54 | +```bash | ||
| 55 | +export LOG_TORCH_TRITON_RUNTIME=1 | ||
| 56 | +``` | ||
| @@ -0,0 +1,69 @@ | |||
| 1 | +cmake_minimum_required(VERSION 3.18) | ||
| 2 | +project(demo LANGUAGES CXX) | ||
| 3 | + | ||
| 4 | +# Helper function for demo targets | ||
| 5 | +function(add_demo target_name) | ||
| 6 | + add_executable(${target_name} ${target_name}.cpp) | ||
| 7 | + | ||
| 8 | + target_include_directories(${target_name} PRIVATE | ||
| 9 | + ${TRITON_RUNTIME_DIR}/include | ||
| 10 | + ${PYTORCH_PYTHON_PACKAGES}/include | ||
| 11 | + ${PYTORCH_NPU_PACKAGES}/include | ||
| 12 | + ${Python3_INCLUDE_DIRS} | ||
| 13 | + ${CANN_PATH}/include | ||
| 14 | + ${CANN_PATH}/include/experiment | ||
| 15 | + ${CANN_PATH}/include/experiment/msprof | ||
| 16 | + ${CANN_PATH}/pkg_inc | ||
| 17 | + ${CANN_PATH}/pkg_inc/profiling | ||
| 18 | + ) | ||
| 19 | + | ||
| 20 | + target_link_directories(${target_name} PRIVATE | ||
| 21 | + ${TRITON_RUNTIME_DIR}/build | ||
| 22 | + ${PYTORCH_PYTHON_PACKAGES}/lib | ||
| 23 | + ${PYTORCH_PYTHON_PACKAGES}/../torch.libs | ||
| 24 | + ${CANN_PATH}/lib64 | ||
| 25 | + ${PYTORCH_NPU_PACKAGES}/lib | ||
| 26 | + ) | ||
| 27 | + | ||
| 28 | + target_link_libraries(${target_name} PRIVATE | ||
| 29 | + triton_runtime | ||
| 30 | + torch | ||
| 31 | + ${TORCH_LIBRARIES} | ||
| 32 | + torch_cpu | ||
| 33 | + torch_npu | ||
| 34 | + c10 | ||
| 35 | + dl | ||
| 36 | + Python3::Python | ||
| 37 | + runtime | ||
| 38 | + ascendcl | ||
| 39 | + profapi | ||
| 40 | + ssl | ||
| 41 | + crypto | ||
| 42 | + ) | ||
| 43 | + | ||
| 44 | + set_target_properties(${target_name} PROPERTIES | ||
| 45 | + BUILD_RPATH "${TRITON_RUNTIME_DIR}/build;${PYTORCH_PYTHON_PACKAGES}/lib;${PYTORCH_NPU_PACKAGES}/lib;${CANN_PATH}/lib64" | ||
| 46 | + INSTALL_RPATH "${TRITON_RUNTIME_DIR}/build;${PYTORCH_PYTHON_PACKAGES}/lib;${PYTORCH_NPU_PACKAGES}/lib;${CANN_PATH}/lib64" | ||
| 47 | + ) | ||
| 48 | +endfunction() | ||
| 49 | + | ||
| 50 | +set(CMAKE_CXX_STANDARD 17) | ||
| 51 | +set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 52 | + | ||
| 53 | +# ──── Paths (override with -D flags if needed) ──── | ||
| 54 | + | ||
| 55 | +set(PYTORCH_PYTHON_PACKAGES "${PYTORCH_PYTHON_PACKAGES}" CACHE PATH "torch Python packages directory") | ||
| 56 | +set(PYTORCH_NPU_PACKAGES "${PYTORCH_NPU_PACKAGES}" CACHE PATH "torch_npu Python packages directory") | ||
| 57 | +set(CANN_PATH "${CANN_PATH}" CACHE PATH "CANN installation root") | ||
| 58 | + | ||
| 59 | +message("CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}") | ||
| 60 | +set(TRITON_RUNTIME_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../triton_runtime" CACHE PATH "Path to triton_runtime project root") | ||
| 61 | + | ||
| 62 | +set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE FILEPATH "Python executable path") | ||
| 63 | + | ||
| 64 | +find_package(Python3 3.10 COMPONENTS Interpreter Development REQUIRED) | ||
| 65 | +find_package(Torch REQUIRED) | ||
| 66 | + | ||
| 67 | +# ──── Demo executables ──── | ||
| 68 | + | ||
| 69 | +add_demo(demo) | ||
| @@ -0,0 +1,158 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +using namespace triton_runtime; | ||
| 7 | + | ||
| 8 | +void run_add_kernel() { | ||
| 9 | + auto& rt = TritonRuntime::instance(); | ||
| 10 | + | ||
| 11 | + // register kernel | ||
| 12 | + auto s = rt.register_kernel("examples/my_kernels.py", "add_kernel"); | ||
| 13 | + if (!s.ok()) { | ||
| 14 | + std::cerr << "Register failed: " << s.error_message() << std::endl; | ||
| 15 | + return; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + rt.print_kernel_signature("add_kernel"); | ||
| 19 | + | ||
| 20 | + // Prepare data on NPU | ||
| 21 | + auto x = torch::rand({1000}, torch::kFloat32).to("npu"); | ||
| 22 | + auto y = torch::rand({1000}, torch::kFloat32).to("npu"); | ||
| 23 | + auto out = torch::empty_like(x); | ||
| 24 | + int n_elements = 1000; | ||
| 25 | + int BLOCK_SIZE = 1024; | ||
| 26 | + | ||
| 27 | + auto grid = (n_elements + BLOCK_SIZE - 1) / BLOCK_SIZE; | ||
| 28 | + | ||
| 29 | + // Launch Triton kernel | ||
| 30 | + s = rt.run("add_kernel", Grid(grid, 1, 1), x, y, out, n_elements, BLOCK_SIZE); | ||
| 31 | + if (!s.ok()) { | ||
| 32 | + std::cerr << "Launch failed: " << s.error_message() << std::endl; | ||
| 33 | + return; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + // validate result | ||
| 37 | + auto libtorch_result = torch::add(x, y); | ||
| 38 | + std::cout << "C++ libtorch add[0:5]: " << libtorch_result.slice(0, 0, 5) << std::endl; | ||
| 39 | + std::cout << "C++ triton out[0:5]: " << out.slice(0, 0, 5) << std::endl; | ||
| 40 | + auto diff = (libtorch_result - out).abs().max().item<float>(); | ||
| 41 | + std::cout << "C++: max diff: " << diff << std::endl; | ||
| 42 | + std::cout << "C++: match: " << (diff < 1e-5 ? "YES" : "NO") << std::endl; | ||
| 43 | +} | ||
| 44 | + | ||
| 45 | +// C++ lambda grid — like Triton's lambda meta: (...) but resolved entirely | ||
| 46 | +// in C++ without Python involvement. | ||
| 47 | +void run_add_kernel_lambda_grid() { | ||
| 48 | + auto& rt = TritonRuntime::instance(); | ||
| 49 | + | ||
| 50 | + auto s = rt.register_kernel("examples/my_kernels.py", "add_kernel"); | ||
| 51 | + if (!s.ok()) { | ||
| 52 | + std::cerr << "Register failed: " << s.error_message() << std::endl; | ||
| 53 | + return; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + auto x = torch::rand({1000}, torch::kFloat32).to("npu"); | ||
| 57 | + auto y = torch::rand({1000}, torch::kFloat32).to("npu"); | ||
| 58 | + auto out = torch::empty_like(x); | ||
| 59 | + int n_elements = 1000; | ||
| 60 | + int BLOCK_SIZE = 1024; | ||
| 61 | + | ||
| 62 | + // meta["key"] returns variant<int32_t,float,bool>, same as Triton's bound_args. | ||
| 63 | + GridFn grid_fn = [](BoundArgs& meta) -> Grid { | ||
| 64 | + int n = meta["n_elements"]; | ||
| 65 | + int bs = meta["BLOCK_SIZE"]; | ||
| 66 | + return Grid((n + bs - 1) / bs, 1, 1); | ||
| 67 | + }; | ||
| 68 | + | ||
| 69 | + s = rt.run("add_kernel", Grid(grid_fn), x, y, out, | ||
| 70 | + n_elements, BLOCK_SIZE); | ||
| 71 | + if (!s.ok()) { | ||
| 72 | + std::cerr << "Launch failed: " << s.error_message() << std::endl; | ||
| 73 | + return; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + auto libtorch_result = torch::add(x, y); | ||
| 77 | + std::cout << "C++ libtorch add[0:5]: " << libtorch_result.slice(0, 0, 5) << std::endl; | ||
| 78 | + std::cout << "C++ triton out[0:5]: " << out.slice(0, 0, 5) << std::endl; | ||
| 79 | + auto diff = (libtorch_result - out).abs().max().item<float>(); | ||
| 80 | + std::cout << "C++: max diff: " << diff << std::endl; | ||
| 81 | + std::cout << "C++: match: " << (diff < 1e-5 ? "YES" : "NO") << std::endl; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +void run_layer_norm_kernel() { | ||
| 85 | + auto& rt = TritonRuntime::instance(); | ||
| 86 | + | ||
| 87 | + // register kernel | ||
| 88 | + auto s = rt.register_kernel("examples/my_kernels.py", "layer_norm_kernel"); | ||
| 89 | + if (!s.ok()) { | ||
| 90 | + std::cerr << "Register failed: " << s.error_message() << std::endl; | ||
| 91 | + return; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + rt.print_kernel_signature("layer_norm_kernel"); | ||
| 95 | + | ||
| 96 | + // Prepare data on NPU | ||
| 97 | + int n_rows = 128; | ||
| 98 | + int n_cols = 512; | ||
| 99 | + float eps = 1e-5; | ||
| 100 | + auto x = torch::randn({n_rows, n_cols}, torch::kFloat32).to("npu"); | ||
| 101 | + auto weight = torch::ones({n_cols}, torch::kFloat32).to("npu"); | ||
| 102 | + auto bias = torch::zeros({n_cols}, torch::kFloat32).to("npu"); | ||
| 103 | + auto out = torch::empty_like(x); | ||
| 104 | + int64_t stride = x.stride(0); | ||
| 105 | + | ||
| 106 | + // BLOCK_SIZE = next_power_of_2(n_cols) | ||
| 107 | + int BLOCK_SIZE = 1; | ||
| 108 | + while (BLOCK_SIZE < n_cols) BLOCK_SIZE *= 2; | ||
| 109 | + | ||
| 110 | + std::cout << "C++ BLOCK_SIZE: " << BLOCK_SIZE << std::endl; | ||
| 111 | + | ||
| 112 | + // Launch Triton kernel | ||
| 113 | + s = rt.run("layer_norm_kernel", Grid(n_rows, 1, 1), | ||
| 114 | + out, x, weight, bias, | ||
| 115 | + n_rows, n_cols, stride, eps, | ||
| 116 | + BLOCK_SIZE); | ||
| 117 | + if (!s.ok()) { | ||
| 118 | + std::cerr << "Launch failed: " << s.error_message() << std::endl; | ||
| 119 | + return; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + // validate result | ||
| 123 | + auto ref = torch::layer_norm(x, {n_cols}, weight, bias, eps); | ||
| 124 | + std::cout << "C++ triton out[0,:5]: " << out.index({0, torch::indexing::Slice(0, 5)}) << std::endl; | ||
| 125 | + std::cout << "C++ torch ref[0,:5]: " << ref.index({0, torch::indexing::Slice(0, 5)}) << std::endl; | ||
| 126 | + auto diff = (ref - out).abs().max().item<float>(); | ||
| 127 | + std::cout << "C++: max diff: " << diff << std::endl; | ||
| 128 | + std::cout << "C++: match: " << (diff < 1e-3 ? "YES" : "NO") << std::endl; | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +int main() { | ||
| 132 | + // List registered kernels | ||
| 133 | + auto& rt = TritonRuntime::instance(); | ||
| 134 | + | ||
| 135 | + // simple case — explicit grid | ||
| 136 | + std::cout << "=== Add Kernel (explicit grid) ===" << std::endl; | ||
| 137 | + run_add_kernel(); | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + // lambda grid — C++ callable, resolves without Python | ||
| 141 | + std::cout << "\n=== Add Kernel (C++ lambda grid) ===" << std::endl; | ||
| 142 | + run_add_kernel_lambda_grid(); | ||
| 143 | + | ||
| 144 | + for (const auto& name : rt.list_kernels()) { | ||
| 145 | + std::cout << " registered: " << name << std::endl; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + | ||
| 149 | + // complicate case | ||
| 150 | + std::cout << "\n=== LayerNorm Kernel ===" << std::endl; | ||
| 151 | + run_layer_norm_kernel(); | ||
| 152 | + | ||
| 153 | + for (const auto& name : rt.list_kernels()) { | ||
| 154 | + std::cout << " registered: " << name << std::endl; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + return 0; | ||
| 158 | +} | ||
| @@ -0,0 +1,63 @@ | |||
| 1 | +import triton | ||
| 2 | +import triton.language as tl | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +def add_kernel(x_ptr: tl.tensor, | ||
| 6 | + y_ptr: tl.tensor, | ||
| 7 | + output_ptr, | ||
| 8 | + n_elements, | ||
| 9 | + BLOCK_SIZE: tl.constexpr, | ||
| 10 | + ): | ||
| 11 | + """向量加法 kernel(参考 test_libtorch_ffmh)""" | ||
| 12 | + pid = tl.program_id(axis=0) | ||
| 13 | + block_start = pid * BLOCK_SIZE | ||
| 14 | + offsets = block_start + tl.arange(0, BLOCK_SIZE) | ||
| 15 | + mask = offsets < n_elements | ||
| 16 | + x = tl.load(x_ptr + offsets, mask=mask) | ||
| 17 | + y = tl.load(y_ptr + offsets, mask=mask) | ||
| 18 | + output = x + y | ||
| 19 | + tl.store(output_ptr + offsets, output, mask=mask) | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +def layer_norm_kernel( | ||
| 24 | + output_ptr, | ||
| 25 | + input_ptr, | ||
| 26 | + weight_ptr, | ||
| 27 | + bias_ptr, | ||
| 28 | + n_rows: tl.constexpr, | ||
| 29 | + n_cols: tl.constexpr, | ||
| 30 | + stride, | ||
| 31 | + eps, | ||
| 32 | + BLOCK_SIZE: tl.constexpr, | ||
| 33 | +): | ||
| 34 | + """Fused LayerNorm kernel: output = (x - mean) / sqrt(var + eps) * weight + bias | ||
| 35 | + | ||
| 36 | + 每个 program 处理一行数据,计算该行的均值和方差后归一化。 | ||
| 37 | + 支持 2D 输入 (n_rows x n_cols),weight/bias 为长度 n_cols 的向量。 | ||
| 38 | + """ | ||
| 39 | + row_idx = tl.program_id(0) | ||
| 40 | + row_start = row_idx * stride | ||
| 41 | + col_offsets = tl.arange(0, BLOCK_SIZE) | ||
| 42 | + mask = col_offsets < n_cols | ||
| 43 | + | ||
| 44 | + # 加载一行数据 | ||
| 45 | + x = tl.load(input_ptr + row_start + col_offsets, mask=mask, other=0.0) | ||
| 46 | + | ||
| 47 | + # 计算均值 | ||
| 48 | + x_mean = tl.sum(x, axis=0) / n_cols | ||
| 49 | + | ||
| 50 | + # 计算方差 | ||
| 51 | + x_centered = x - x_mean | ||
| 52 | + x_var = tl.sum(x_centered * x_centered, axis=0) / n_cols | ||
| 53 | + | ||
| 54 | + # 归一化 | ||
| 55 | + rstd = 1.0 / tl.sqrt(x_var + eps) | ||
| 56 | + x_norm = x_centered * rstd | ||
| 57 | + | ||
| 58 | + # 仿射变换: weight * x_norm + bias | ||
| 59 | + weight = tl.load(weight_ptr + col_offsets, mask=mask, other=1.0) | ||
| 60 | + bias = tl.load(bias_ptr + col_offsets, mask=mask, other=0.0) | ||
| 61 | + output = weight * x_norm + bias | ||
| 62 | + | ||
| 63 | + tl.store(output_ptr + row_start + col_offsets, output, mask=mask) | ||
| @@ -0,0 +1,58 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +set -e | ||
| 3 | + | ||
| 4 | +export TORCH_DEVICE_BACKEND_AUTOLOAD=0 | ||
| 5 | + | ||
| 6 | +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) | ||
| 7 | +BUILD_DIR=${SCRIPT_DIR}/build | ||
| 8 | +DEMO_BIN=${BUILD_DIR}/demo | ||
| 9 | + | ||
| 10 | +# ── Environment ── | ||
| 11 | + | ||
| 12 | +PYTHON3="${PYTHON3:-python3}" | ||
| 13 | +PYTHONHOME=$($PYTHON3 -c 'import sys; print(sys.prefix)') | ||
| 14 | +TORCH_PATH=$($PYTHON3 -c 'import torch; print(torch.__path__[0])') | ||
| 15 | +TORCH_NPU_PATH=$($PYTHON3 -c 'import torch_npu; print(torch_npu.__path__[0])') | ||
| 16 | +CANN_ROOT="${ASCEND_HOME_PATH:-${ASCEND_HOME:-}}" | ||
| 17 | + | ||
| 18 | +if [ -z "$CANN_ROOT" ]; then | ||
| 19 | + echo "[ERROR] Set ASCEND_HOME_PATH or ASCEND_HOME first" | ||
| 20 | + exit 1 | ||
| 21 | +fi | ||
| 22 | + | ||
| 23 | +TORCH_CMAKE_PREFIX=$($PYTHON3 -c 'import torch; print(torch.utils.cmake_prefix_path)' 2>/dev/null) | ||
| 24 | +PYBIND11_CMAKE_DIR=$($PYTHON3 -m pybind11 --cmakedir 2>/dev/null) | ||
| 25 | + | ||
| 26 | +# ── Build ── | ||
| 27 | + | ||
| 28 | +echo "=== Build demo ===" | ||
| 29 | +echo "PYTHON3: $(which $PYTHON3)" | ||
| 30 | +echo "PYTHONHOME: ${PYTHONHOME}" | ||
| 31 | +echo "TORCH_CMAKE_PREFIX: ${TORCH_CMAKE_PREFIX}" | ||
| 32 | +echo "TORCH_PATH: ${TORCH_PATH}" | ||
| 33 | +echo "TORCH_NPU_PATH: ${TORCH_NPU_PATH}" | ||
| 34 | +cmake -S "${SCRIPT_DIR}" -B "${BUILD_DIR}" -DCMAKE_BUILD_TYPE=Release \ | ||
| 35 | + -DPYTORCH_PYTHON_PACKAGES="${TORCH_PATH}" \ | ||
| 36 | + -DPYTORCH_NPU_PACKAGES="${TORCH_NPU_PATH}" \ | ||
| 37 | + -DCANN_PATH="${CANN_ROOT}" \ | ||
| 38 | + -DPYTHON_EXECUTABLE="$(which $PYTHON3)" \ | ||
| 39 | + -DCMAKE_PREFIX_PATH="${TORCH_CMAKE_PREFIX};${PYBIND11_CMAKE_DIR}" | ||
| 40 | +cmake --build "${BUILD_DIR}" -j$(nproc) | ||
| 41 | + | ||
| 42 | +# ── Run ── | ||
| 43 | + | ||
| 44 | +echo "" | ||
| 45 | +echo "=== Run demo ===" | ||
| 46 | +echo "" | ||
| 47 | + | ||
| 48 | +TORCH_LIB="${TORCH_PATH}/lib" | ||
| 49 | +TORCH_NPU_LIB="${TORCH_NPU_PATH}/lib" | ||
| 50 | +CANN_LIB="${CANN_ROOT}/lib64" | ||
| 51 | +RT_BUILD="${SCRIPT_DIR}/../build" | ||
| 52 | + | ||
| 53 | +PROJECT_ROOT="${SCRIPT_DIR}/../.." | ||
| 54 | + | ||
| 55 | +PYTHONHOME="${PYTHONHOME}" \ | ||
| 56 | +PYTHONPATH="${PROJECT_ROOT}:${PYTHONPATH:-}" \ | ||
| 57 | +LD_LIBRARY_PATH="${RT_BUILD}:${TORCH_LIB}:${TORCH_NPU_LIB}:${CANN_LIB}:${LD_LIBRARY_PATH}" \ | ||
| 58 | + "$DEMO_BIN" | ||
| @@ -0,0 +1,91 @@ | |||
| 1 | +cmake_minimum_required(VERSION 3.18) | ||
| 2 | +project(triton_runtime VERSION 0.1.0 LANGUAGES CXX) | ||
| 3 | + | ||
| 4 | +set(CMAKE_CXX_STANDARD 17) | ||
| 5 | +set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| 6 | + | ||
| 7 | +set(PYTORCH_PYTHON_PACKAGES "${PYTORCH_PYTHON_PACKAGES}" CACHE PATH "torch Python packages directory") | ||
| 8 | +set(PYTORCH_NPU_PACKAGES "${PYTORCH_NPU_PACKAGES}" CACHE PATH "torch_npu Python packages directory") | ||
| 9 | +set(CANN_PATH "${CANN_PATH}" CACHE PATH "CANN installation root") | ||
| 10 | + | ||
| 11 | +set(PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}" CACHE FILEPATH "Python executable path") | ||
| 12 | + | ||
| 13 | +find_package(Python3 3.10 COMPONENTS Interpreter Development REQUIRED) | ||
| 14 | +find_package(Torch REQUIRED) | ||
| 15 | +find_package(pybind11 REQUIRED) | ||
| 16 | + | ||
| 17 | +# ──── Library ──── | ||
| 18 | + | ||
| 19 | +set(LIB_SOURCES | ||
| 20 | + src/arg_info.cpp | ||
| 21 | + src/python_env.cpp | ||
| 22 | + src/kernel_registry.cpp | ||
| 23 | + src/kernel_compiler.cpp | ||
| 24 | + src/kernel_cache.cpp | ||
| 25 | + src/triton_runtime.cpp | ||
| 26 | +) | ||
| 27 | + | ||
| 28 | +add_library(triton_runtime SHARED ${LIB_SOURCES}) | ||
| 29 | + | ||
| 30 | +target_include_directories(triton_runtime | ||
| 31 | + PUBLIC | ||
| 32 | + ${CMAKE_CURRENT_SOURCE_DIR}/include | ||
| 33 | + PRIVATE | ||
| 34 | + ${PYTORCH_PYTHON_PACKAGES}/include | ||
| 35 | + ${PYTORCH_NPU_PACKAGES}/include | ||
| 36 | + ${Python3_INCLUDE_DIRS} | ||
| 37 | + ${CANN_PATH}/include | ||
| 38 | + ${CANN_PATH}/include/experiment | ||
| 39 | + ${CANN_PATH}/include/experiment/msprof | ||
| 40 | + ${CANN_PATH}/pkg_inc | ||
| 41 | + ${CANN_PATH}/pkg_inc/profiling | ||
| 42 | +) | ||
| 43 | + | ||
| 44 | +target_link_directories(triton_runtime PRIVATE | ||
| 45 | + ${PYTORCH_PYTHON_PACKAGES}/lib | ||
| 46 | + ${PYTORCH_PYTHON_PACKAGES}/../torch.libs | ||
| 47 | + ${CANN_PATH}/lib64 | ||
| 48 | + ${PYTORCH_NPU_PACKAGES}/lib | ||
| 49 | +) | ||
| 50 | + | ||
| 51 | +target_link_libraries(triton_runtime | ||
| 52 | + PUBLIC | ||
| 53 | + torch | ||
| 54 | + ${TORCH_LIBRARIES} | ||
| 55 | + PRIVATE | ||
| 56 | + pybind11::embed | ||
| 57 | + torch_cpu | ||
| 58 | + torch_npu | ||
| 59 | + c10 | ||
| 60 | + dl | ||
| 61 | + Python3::Python | ||
| 62 | + runtime | ||
| 63 | + ascendcl | ||
| 64 | + profapi | ||
| 65 | + ssl | ||
| 66 | + crypto | ||
| 67 | +) | ||
| 68 | + | ||
| 69 | +target_compile_options(triton_runtime PRIVATE -Wall -Wextra -fPIC) | ||
| 70 | +set_target_properties(triton_runtime PROPERTIES | ||
| 71 | + OUTPUT_NAME triton_runtime | ||
| 72 | + VERSION ${PROJECT_VERSION} | ||
| 73 | + SOVERSION 0 | ||
| 74 | +) | ||
| 75 | + | ||
| 76 | +# ──── Install ──── | ||
| 77 | + | ||
| 78 | +install(TARGETS triton_runtime | ||
| 79 | + LIBRARY DESTINATION lib | ||
| 80 | +) | ||
| 81 | +install(DIRECTORY include/ | ||
| 82 | + DESTINATION include | ||
| 83 | +) | ||
| 84 | + | ||
| 85 | +# ──── Tests ──── | ||
| 86 | + | ||
| 87 | +option(TRITON_RUNTIME_BUILD_TESTS "Build tests" OFF) | ||
| 88 | +if(TRITON_RUNTIME_BUILD_TESTS) | ||
| 89 | + enable_testing() | ||
| 90 | + add_subdirectory(test) | ||
| 91 | +endif() | ||
| @@ -0,0 +1,57 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) | ||
| 4 | +BUILD_DIR=${SCRIPT_DIR}/build | ||
| 5 | + | ||
| 6 | +# ── Environment ── | ||
| 7 | +if [ -z "$ASCEND_HOME_PATH" ] && [ -z "$ASCEND_HOME" ]; then | ||
| 8 | + echo "[ERROR] Set ASCEND_HOME_PATH or ASCEND_HOME first" | ||
| 9 | + exit 1 | ||
| 10 | +fi | ||
| 11 | +CANN_ROOT="${ASCEND_HOME_PATH:-$ASCEND_HOME}" | ||
| 12 | + | ||
| 13 | +PYTHON3="${PYTHON3:-python3}" | ||
| 14 | +if ! command -v $PYTHON3 &>/dev/null; then | ||
| 15 | + echo "[ERROR] python3 not found" | ||
| 16 | + exit 1 | ||
| 17 | +fi | ||
| 18 | + | ||
| 19 | +TORCH_PATH=$($PYTHON3 -c 'import torch; print(torch.__path__[0])') | ||
| 20 | +TORCH_NPU_PATH=$($PYTHON3 -c 'import torch_npu; print(torch_npu.__path__[0])') | ||
| 21 | + | ||
| 22 | +TORCH_CMAKE_PREFIX=$($PYTHON3 -c 'import torch; print(torch.utils.cmake_prefix_path)' 2>/dev/null) | ||
| 23 | +if [ -z "$TORCH_CMAKE_PREFIX" ]; then | ||
| 24 | + echo "[ERROR] torch not installed or not importable" | ||
| 25 | + exit 1 | ||
| 26 | +fi | ||
| 27 | + | ||
| 28 | +PYBIND11_CMAKE_DIR=$($PYTHON3 -m pybind11 --cmakedir 2>/dev/null) | ||
| 29 | +if [ -z "$PYBIND11_CMAKE_DIR" ]; then | ||
| 30 | + echo "[ERROR] pybind11 not installed or not importable" | ||
| 31 | + exit 1 | ||
| 32 | +fi | ||
| 33 | + | ||
| 34 | +echo "=== Build triton_runtime ===" | ||
| 35 | +echo " CANN_ROOT: $CANN_ROOT" | ||
| 36 | +echo " Python3: $PYTHON3" | ||
| 37 | +echo " Torch cmake prefix: $TORCH_CMAKE_PREFIX" | ||
| 38 | +echo " pybind11 cmake dir: $PYBIND11_CMAKE_DIR" | ||
| 39 | + | ||
| 40 | +# ── CMake Configure ── | ||
| 41 | +mkdir -p "$BUILD_DIR" | ||
| 42 | +cd "$BUILD_DIR" | ||
| 43 | + | ||
| 44 | +cmake .. \ | ||
| 45 | + -DCMAKE_BUILD_TYPE=Debug \ | ||
| 46 | + -DPYTHON_EXECUTABLE="$(which $PYTHON3)" \ | ||
| 47 | + -DPYTORCH_PYTHON_PACKAGES="${TORCH_PATH}" \ | ||
| 48 | + -DPYTORCH_NPU_PACKAGES="${TORCH_NPU_PATH}" \ | ||
| 49 | + -DCANN_PATH="${CANN_ROOT}" \ | ||
| 50 | + -DCMAKE_PREFIX_PATH="$TORCH_CMAKE_PREFIX;$PYBIND11_CMAKE_DIR" | ||
| 51 | + | ||
| 52 | +# ── Build ── | ||
| 53 | +make -j$(nproc) | ||
| 54 | + | ||
| 55 | +echo "" | ||
| 56 | +echo "=== Build succeeded ===" | ||
| 57 | +echo " SO: $BUILD_DIR/libtriton_runtime.so" | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | +namespace triton_runtime { | ||
| 7 | + | ||
| 8 | +class ArgInfo { | ||
| 9 | +public: | ||
| 10 | + using ScalarVariant = std::variant<int32_t, float, bool>; | ||
| 11 | + | ||
| 12 | + ArgInfo(const at::Tensor& tensor); | ||
| 13 | + ArgInfo(int32_t val); | ||
| 14 | + ArgInfo(int64_t val); | ||
| 15 | + ArgInfo(float val); | ||
| 16 | + ArgInfo(double val); | ||
| 17 | + ArgInfo(bool val); | ||
| 18 | + | ||
| 19 | + bool is_pointer() const; | ||
| 20 | + std::string scalar_value() const; | ||
| 21 | + | ||
| 22 | + void* device_ptr() const; | ||
| 23 | + const at::Tensor& tensor() const; | ||
| 24 | + const ScalarVariant& scalar() const; | ||
| 25 | + std::vector<int64_t> shape() const; | ||
| 26 | + size_t scalar_size() const; | ||
| 27 | + | ||
| 28 | +private: | ||
| 29 | + void* ptr_ = nullptr; | ||
| 30 | + ScalarVariant scalar_ = int32_t(0); | ||
| 31 | + std::vector<int64_t> shape_; | ||
| 32 | + at::Tensor tensor_; | ||
| 33 | + size_t scalar_size_ = sizeof(int32_t); | ||
| 34 | +}; | ||
| 35 | + | ||
| 36 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,50 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +namespace triton_runtime { | ||
| 9 | + | ||
| 10 | +// Wraps ArgInfo::ScalarVariant with implicit conversion, so the lambda can do | ||
| 11 | +// int n = meta["n_elements"]; // operator int() | ||
| 12 | +struct ScalarValue { | ||
| 13 | + using Var = std::variant<int32_t, float, bool>; | ||
| 14 | + Var v; | ||
| 15 | + | ||
| 16 | + ScalarValue() = default; | ||
| 17 | + ScalarValue(const Var& v) : v(v) {} | ||
| 18 | + ScalarValue(int32_t x) : v(x) {} | ||
| 19 | + ScalarValue(float x) : v(x) {} | ||
| 20 | + ScalarValue(bool x) : v(x) {} | ||
| 21 | + | ||
| 22 | + operator int() const { return std::visit([](auto x) { return int(x); }, v); } | ||
| 23 | + operator float() const { return std::visit([](auto x) { return float(x); }, v); } | ||
| 24 | + operator bool() const { return std::visit([](auto x) { return bool(x); }, v); } | ||
| 25 | +}; | ||
| 26 | + | ||
| 27 | +using BoundArgs = std::unordered_map<std::string, ScalarValue>; | ||
| 28 | + | ||
| 29 | +struct Grid; | ||
| 30 | +using GridFn = std::function<Grid(BoundArgs&)>; | ||
| 31 | + | ||
| 32 | +// Grid is either a fixed (x,y,z) or a callable that resolves (x,y,z) | ||
| 33 | +// from bound_args. Both modes live in the same type — no extra wrapper. | ||
| 34 | +struct Grid { | ||
| 35 | + int x = 1, y = 1, z = 1; | ||
| 36 | + GridFn fn; | ||
| 37 | + | ||
| 38 | + Grid() = default; | ||
| 39 | + Grid(int x, int y = 1, int z = 1) : x(x), y(y), z(z) {} | ||
| 40 | + Grid(GridFn f) : fn(std::move(f)) {} | ||
| 41 | + | ||
| 42 | + bool is_callable() const { return !!fn; } | ||
| 43 | + | ||
| 44 | + Grid resolve(BoundArgs& args) const { | ||
| 45 | + if (fn) return fn(args); | ||
| 46 | + return *this; | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | +namespace triton_runtime { | ||
| 16 | + | ||
| 17 | +// dlopen-based launcher: the generated launcher .so exposes this extern "C" entry point | ||
| 18 | +typedef void (*TritonLaunchKernelFn)( | ||
| 19 | + const char* kernelName, const void* func, void* stream, | ||
| 20 | + int gridX, int gridY, int gridZ, | ||
| 21 | + const int64_t* shapes_data, const int* shape_dims, int num_tensors, | ||
| 22 | + const int* tensor_kinds, | ||
| 23 | + void* const* kernel_args, const size_t* arg_sizes, int num_args); | ||
| 24 | + | ||
| 25 | +struct CompiledKernelEntry { | ||
| 26 | + std::string kernel_name; | ||
| 27 | + void* kernel_func_ptr = nullptr; | ||
| 28 | + std::string launcher_so_path; | ||
| 29 | + void* launcher_so_handle = nullptr; | ||
| 30 | + TritonLaunchKernelFn launch_fn = nullptr; | ||
| 31 | + std::vector<int> tensor_kinds; // 0=input, 1=output, 2=input_output | ||
| 32 | + std::vector<bool> is_constexpr; | ||
| 33 | + | ||
| 34 | + std::string toString() const { | ||
| 35 | + std::ostringstream oss; | ||
| 36 | + oss << "CompiledKernelEntry{kernel_name=" << kernel_name | ||
| 37 | + << ", kernel_func_ptr=" << kernel_func_ptr | ||
| 38 | + << ", launcher_so=" << launcher_so_path | ||
| 39 | + << ", launch_fn=" << reinterpret_cast<const void*>(launch_fn) | ||
| 40 | + << ", num_tensors=" << tensor_kinds.size() | ||
| 41 | + << ", num_constexpr="; | ||
| 42 | + int ce_count = 0; | ||
| 43 | + for (bool b : is_constexpr) if (b) ce_count++; | ||
| 44 | + oss << ce_count << "/" << is_constexpr.size(); | ||
| 45 | + oss << "}"; | ||
| 46 | + return oss.str(); | ||
| 47 | + } | ||
| 48 | +}; | ||
| 49 | + | ||
| 50 | +class KernelCache { | ||
| 51 | +public: | ||
| 52 | + static KernelCache& instance(); | ||
| 53 | + | ||
| 54 | + static uint64_t compute_cache_key( | ||
| 55 | + const KernelDescriptor& kernel_desc, | ||
| 56 | + const std::vector<ArgInfo>& args); | ||
| 57 | + | ||
| 58 | + std::shared_ptr<CompiledKernelEntry> query( | ||
| 59 | + const std::string& kernel_name, | ||
| 60 | + uint64_t cache_key) const; | ||
| 61 | + | ||
| 62 | + void store(const std::string& kernel_name, | ||
| 63 | + uint64_t cache_key, | ||
| 64 | + std::shared_ptr<CompiledKernelEntry> entry); | ||
| 65 | + | ||
| 66 | + void invalidate(const std::string& kernel_name); | ||
| 67 | + void clear(); | ||
| 68 | + void shutdown(); | ||
| 69 | + | ||
| 70 | +private: | ||
| 71 | + KernelCache() = default; | ||
| 72 | + std::unordered_map<std::string, | ||
| 73 | + std::unordered_map<uint64_t, std::shared_ptr<CompiledKernelEntry>>> cache_; | ||
| 74 | + mutable std::shared_mutex mutex_; | ||
| 75 | +}; | ||
| 76 | + | ||
| 77 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +namespace triton_runtime { | ||
| 12 | + | ||
| 13 | +class KernelCompiler { | ||
| 14 | +public: | ||
| 15 | + static KernelCompiler& instance(); | ||
| 16 | + | ||
| 17 | + std::shared_ptr<CompiledKernelEntry> compile( | ||
| 18 | + const KernelDescriptor& kernel_desc, | ||
| 19 | + const std::vector<ArgInfo>& args, | ||
| 20 | + const Grid& grid); | ||
| 21 | + | ||
| 22 | + void shutdown(); | ||
| 23 | + | ||
| 24 | +private: | ||
| 25 | + KernelCompiler() = default; | ||
| 26 | + | ||
| 27 | + pybind11::object do_python_compile( | ||
| 28 | + const KernelDescriptor& kernel_desc, | ||
| 29 | + const std::vector<ArgInfo>& args, | ||
| 30 | + const Grid& grid); | ||
| 31 | +}; | ||
| 32 | + | ||
| 33 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,66 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +namespace triton_runtime { | ||
| 12 | + | ||
| 13 | +struct KernelDescriptor { | ||
| 14 | + std::string kernel_name; | ||
| 15 | + std::string python_file; | ||
| 16 | + std::string function_name; | ||
| 17 | + std::string signature_json; | ||
| 18 | + std::string signature_str; // formatted: "def fn(arg: [type], ...)" | ||
| 19 | + pybind11::object jit_function; | ||
| 20 | + std::vector<bool> is_constexpr; | ||
| 21 | + std::vector<std::string> param_names; // params[i].name, for C++ bound_args | ||
| 22 | + bool is_autotuned = false; | ||
| 23 | + | ||
| 24 | + std::string toString() const { | ||
| 25 | + std::ostringstream oss; | ||
| 26 | + oss << "KernelDescriptor{kernel_name=" << kernel_name | ||
| 27 | + << ", python_file=" << python_file | ||
| 28 | + << ", function_name=" << function_name | ||
| 29 | + << ", signature_str=" << signature_str | ||
| 30 | + << ", num_params=" << param_names.size() | ||
| 31 | + << ", is_autotuned=" << (is_autotuned ? "true" : "false") | ||
| 32 | + << "}"; | ||
| 33 | + return oss.str(); | ||
| 34 | + } | ||
| 35 | +}; | ||
| 36 | + | ||
| 37 | +class KernelRegistry { | ||
| 38 | +public: | ||
| 39 | + static KernelRegistry& instance(); | ||
| 40 | + | ||
| 41 | + Status register_kernel(const std::string& python_file, | ||
| 42 | + const std::string& function_name, | ||
| 43 | + const std::string& kernel_name); | ||
| 44 | + | ||
| 45 | + Status register_kernel_from_dir(const std::string& dir_path); | ||
| 46 | + | ||
| 47 | + std::shared_ptr<KernelDescriptor> lookup(const std::string& kernel_name) const; | ||
| 48 | + bool has_kernel(const std::string& kernel_name) const; | ||
| 49 | + std::vector<std::string> list_kernels() const; | ||
| 50 | + void print_kernel_signature(const std::string& kernel_name) const; | ||
| 51 | + Status unregister(const std::string& kernel_name); | ||
| 52 | + void shutdown(); | ||
| 53 | + | ||
| 54 | +private: | ||
| 55 | + KernelRegistry() = default; | ||
| 56 | + Status register_kernel_impl(const std::string& python_file, | ||
| 57 | + const std::string& function_name, | ||
| 58 | + const std::string& kernel_name, | ||
| 59 | + const pybind11::object& inner_jit_fn, | ||
| 60 | + bool is_autotuned); | ||
| 61 | + | ||
| 62 | + std::unordered_map<std::string, std::shared_ptr<KernelDescriptor>> registry_; | ||
| 63 | + mutable std::shared_mutex mutex_; | ||
| 64 | +}; | ||
| 65 | + | ||
| 66 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | +namespace triton_runtime { | ||
| 8 | + | ||
| 9 | +inline bool is_log_enabled() { | ||
| 10 | + static bool enabled = []() { | ||
| 11 | + const char* env = std::getenv("LOG_TORCH_TRITON_RUNTIME"); | ||
| 12 | + return env != nullptr && std::strcmp(env, "1") == 0; | ||
| 13 | + }(); | ||
| 14 | + return enabled; | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +} // namespace triton_runtime | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + do { \ | ||
| 21 | + if (::triton_runtime::is_log_enabled()) { \ | ||
| 22 | + std::fprintf(stderr, "[TRT] " fmt "\n", ##__VA_ARGS__); \ | ||
| 23 | + } \ | ||
| 24 | + } while (0) | ||
| @@ -0,0 +1,23 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +namespace triton_runtime { | ||
| 6 | + | ||
| 7 | +class PythonEnv { | ||
| 8 | +public: | ||
| 9 | + static PythonEnv& instance(); | ||
| 10 | + | ||
| 11 | + void ensure_initialized(); | ||
| 12 | + bool is_initialized() const; | ||
| 13 | + | ||
| 14 | + pybind11::object exec(const std::string& code); | ||
| 15 | + pybind11::module import(const std::string& module_name); | ||
| 16 | + | ||
| 17 | +private: | ||
| 18 | + PythonEnv() = default; | ||
| 19 | + bool initialized_ = false; | ||
| 20 | + void setup_triton_env(); | ||
| 21 | +}; | ||
| 22 | + | ||
| 23 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +namespace triton_runtime { | ||
| 5 | + | ||
| 6 | +class Status { | ||
| 7 | +public: | ||
| 8 | + static Status OK() { return Status(true, ""); } | ||
| 9 | + static Status Error(const std::string& msg) { return Status(false, msg); } | ||
| 10 | + | ||
| 11 | + bool ok() const { return ok_; } | ||
| 12 | + const std::string& error_message() const { return msg_; } | ||
| 13 | + explicit operator bool() const { return ok_; } | ||
| 14 | + | ||
| 15 | +private: | ||
| 16 | + Status(bool ok, std::string msg) : ok_(ok), msg_(std::move(msg)) {} | ||
| 17 | + bool ok_; | ||
| 18 | + std::string msg_; | ||
| 19 | +}; | ||
| 20 | + | ||
| 21 | +} // namespace triton_runtime | ||
| @@ -0,0 +1,70 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + | ||
| 12 | +namespace triton_runtime { | ||
| 13 | + | ||
| 14 | +struct KernelDescriptor; | ||
| 15 | + | ||
| 16 | +class TritonRuntime { | ||
| 17 | +public: | ||
| 18 | + static TritonRuntime& instance(); | ||
| 19 | + | ||
| 20 | + // ──── Registration Interface ──── | ||
| 21 | + | ||
| 22 | + Status register_kernel(const std::string& python_file, | ||
| 23 | + const std::string& function_name, | ||
| 24 | + const std::string& kernel_name = ""); | ||
| 25 | + | ||
| 26 | + Status register_kernel_dir(const std::string& dir_path); | ||
| 27 | + | ||
| 28 | + Status register_kernel_from_dir(const std::string& dir_path); | ||
| 29 | + | ||
| 30 | + // ──── Execution Interface ──── | ||
| 31 | + | ||
| 32 | + template<typename... Args> | ||
| 33 | + Status run(const std::string& kernel_name, | ||
| 34 | + const Grid& grid_spec, | ||
| 35 | + Args&&... args) { | ||
| 36 | + return run_impl(kernel_name, grid_spec, | ||
| 37 | + {ArgInfo(std::forward<Args>(args))...}); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // ──── Query Interface ──── | ||
| 41 | + | ||
| 42 | + bool has_kernel(const std::string& kernel_name) const; | ||
| 43 | + std::vector<std::string> list_kernels() const; | ||
| 44 | + void print_kernel_signature(const std::string& kernel_name) const; | ||
| 45 | + | ||
| 46 | + // ──── Lifecycle ──── | ||
| 47 | + | ||
| 48 | + // Actively clean up all resources (safe to call while Python/CANN is still alive). | ||
| 49 | + // If not called, resources will be automatically reclaimed by OS at process exit; | ||
| 50 | + // no cleanup during static destruction. | ||
| 51 | + void shutdown(); | ||
| 52 | + | ||
| 53 | +private: | ||
| 54 | + TritonRuntime(); | ||
| 55 | + // ~TritonRuntime() { | ||
| 56 | + // shutdown(); | ||
| 57 | + // } | ||
| 58 | + | ||
| 59 | + // Build a C++ BoundArgs map {param_name: &arg_info, ...} using the | ||
| 60 | + // kernel's param_names metadata. Pure C++, no Python. | ||
| 61 | + BoundArgs build_bound_args( | ||
| 62 | + const KernelDescriptor& desc, | ||
| 63 | + const std::vector<ArgInfo>& arg_infos); | ||
| 64 | + | ||
| 65 | + Status run_impl(const std::string& kernel_name, | ||
| 66 | + const Grid& grid_spec, | ||
| 67 | + std::vector<ArgInfo>&& arg_infos); | ||
| 68 | +}; | ||
| 69 | + | ||
| 70 | +} // namespace triton_runtime | ||