Skip to content

Commit 434c7b7

Browse files
authored
Merge pull request #25 from flagos-ai/enflame/gcu_backend_master
2 parents 74e9c02 + 06198a5 commit 434c7b7

15 files changed

Lines changed: 257 additions & 20 deletions

File tree

CMakeLists.txt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
33
# ==============================================================================
44
# Backend Selection (must be before project())
55
# ==============================================================================
6-
set(BACKEND "CUDA" CACHE STRING "Target backend: CUDA, IX, MUSA, MACA, or NPU")
7-
set_property(CACHE BACKEND PROPERTY STRINGS "CUDA" "IX" "MUSA" "MACA" "NPU")
6+
set(BACKEND "CUDA" CACHE STRING "Target backend: CUDA, IX, MUSA, MACA, NPU, or GCU")
7+
set_property(CACHE BACKEND PROPERTY STRINGS "CUDA" "IX" "MUSA" "MACA" "NPU" "GCU")
88

9-
if(NOT BACKEND MATCHES "^(CUDA|IX|MUSA|MACA|NPU)$")
10-
message(FATAL_ERROR "Invalid BACKEND: ${BACKEND}. Must be CUDA, IX, MUSA, MACA, or NPU")
9+
if(NOT BACKEND MATCHES "^(CUDA|IX|MUSA|MACA|NPU|GCU)$")
10+
message(FATAL_ERROR "Invalid BACKEND: ${BACKEND}. Must be CUDA, IX, MUSA, MACA, NPU, or GCU")
1111
endif()
1212
message(STATUS "Building with backend: ${BACKEND}")
1313

@@ -31,6 +31,8 @@ elseif(BACKEND STREQUAL "MUSA")
3131
project(TritonJIT LANGUAGES CXX VERSION 0.1.0)
3232
elseif(BACKEND STREQUAL "MACA")
3333
project(TritonJIT LANGUAGES CXX VERSION 0.1.0)
34+
elseif(BACKEND STREQUAL "GCU")
35+
project(TritonJIT LANGUAGES CXX VERSION 0.1.0)
3436
else()
3537
project(TritonJIT LANGUAGES CUDA CXX VERSION 0.1.0)
3638
endif()
@@ -50,6 +52,8 @@ elseif(BACKEND STREQUAL "MUSA")
5052
add_compile_definitions(BACKEND_MUSA)
5153
elseif(BACKEND STREQUAL "MACA")
5254
add_compile_definitions(BACKEND_MACA USE_MACA)
55+
elseif(BACKEND STREQUAL "GCU")
56+
add_compile_definitions(BACKEND_GCU)
5357
endif()
5458

5559
# String macro for Python runtime
@@ -67,7 +71,7 @@ add_compile_definitions(BACKEND_NAME="${TRITON_BACKEND_NAME}")
6771
set(CMAKE_CXX_STANDARD 20)
6872
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6973
set(CMAKE_CXX_EXTENSIONS OFF)
70-
if(NOT (BACKEND STREQUAL "NPU" OR BACKEND STREQUAL "MUSA"))
74+
if(NOT (BACKEND STREQUAL "NPU" OR BACKEND STREQUAL "MUSA" OR BACKEND STREQUAL "GCU"))
7175
set(CMAKE_CUDA_STANDARD 17)
7276
endif()
7377
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -166,6 +170,8 @@ elseif(BACKEND STREQUAL "MUSA")
166170
include(BackendMUSA)
167171
elseif(BACKEND STREQUAL "MACA")
168172
include(BackendMACA)
173+
elseif(BACKEND STREQUAL "GCU")
174+
include(BackendGCU)
169175
endif()
170176

171177
# ==============================================================================

cmake/BackendGCU.cmake

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# ==============================================================================
2+
# GCU (Enflame) Backend Configuration
3+
# ==============================================================================
4+
5+
message(STATUS "Configuring GCU backend...")
6+
7+
set(TOPS_ROOT "/opt/tops" CACHE PATH "Enflame TOPS SDK root directory")
8+
9+
if(NOT EXISTS ${TOPS_ROOT}/include/tops_runtime_api.h)
10+
message(FATAL_ERROR "TOPS SDK not found at ${TOPS_ROOT}. "
11+
"Please set -DTOPS_ROOT to the correct TOPS SDK installation path.")
12+
endif()
13+
14+
find_library(TOPSRT_LIBRARY
15+
NAMES topsrt
16+
PATHS ${TOPS_ROOT}/lib
17+
NO_DEFAULT_PATH
18+
)
19+
20+
if(NOT TOPSRT_LIBRARY)
21+
message(FATAL_ERROR "libtopsrt.so not found in ${TOPS_ROOT}/lib")
22+
endif()
23+
24+
if(NOT TARGET GCU::efrt)
25+
add_library(GCU::efrt SHARED IMPORTED)
26+
set_target_properties(GCU::efrt PROPERTIES
27+
IMPORTED_LOCATION "${TOPSRT_LIBRARY}"
28+
INTERFACE_INCLUDE_DIRECTORIES "${TOPS_ROOT}/include"
29+
)
30+
endif()
31+
32+
function(target_link_gcu_libraries target_name)
33+
target_include_directories(${target_name} PUBLIC ${TOPS_ROOT}/include)
34+
target_link_libraries(${target_name} PUBLIC GCU::efrt)
35+
endfunction()
36+
37+
message(STATUS "GCU backend configuration complete")
38+
message(STATUS " TOPS SDK: ${TOPS_ROOT}")
39+
message(STATUS " libtopsrt: ${TOPSRT_LIBRARY}")

examples/arg_handle/test_axpy.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,19 @@ static at::Device test_device() {
88
return at::Device("npu:0");
99
#elif defined(BACKEND_MUSA)
1010
return at::Device("musa:0");
11+
#elif defined(BACKEND_GCU)
12+
return at::Device("gcu:0");
1113
#else
1214
return at::kCUDA;
1315
#endif
1416
}
1517

18+
#ifdef BACKEND_GCU
19+
static c10::Scalar make_float_scalar(double v) { return c10::Scalar(static_cast<float>(v)); }
20+
#else
21+
static c10::Scalar make_float_scalar(double v) { return c10::Scalar(v); }
22+
#endif
23+
1624
TEST(axpy_test, scalar_int) {
1725
at::Tensor a = at::rand({128 * 1024}, test_device());
1826
at::Tensor b = at::rand({128 * 1024}, test_device());
@@ -26,8 +34,9 @@ TEST(axpy_test, scalar_double) {
2634
at::Tensor a = at::rand({128 * 1024}, test_device());
2735
at::Tensor b = at::rand({128 * 1024}, test_device());
2836

29-
at::Tensor result = my_ops::axpy(a, b, c10::Scalar(3.14));
30-
at::Tensor expected = at::add(c10::Scalar(3.14) * a, b);
37+
auto alpha = make_float_scalar(3.14);
38+
at::Tensor result = my_ops::axpy(a, b, alpha);
39+
at::Tensor expected = at::add(alpha * a, b);
3140
EXPECT_TRUE(torch::allclose(result, expected));
3241
}
3342

@@ -44,7 +53,7 @@ TEST(axpy_test, optional_scalar_has_value) {
4453
at::Tensor a = at::rand({128 * 1024}, test_device());
4554
at::Tensor b = at::rand({128 * 1024}, test_device());
4655

47-
std::optional<c10::Scalar> alpha = c10::Scalar(3.14);
56+
std::optional<c10::Scalar> alpha = make_float_scalar(3.14);
4857
at::Tensor result = my_ops::axpy2(a, b, alpha);
4958
at::Tensor expected = at::add(alpha.value() * a, b);
5059
EXPECT_TRUE(torch::allclose(result, expected));
@@ -54,7 +63,7 @@ TEST(axpy_test, optional_tensor_has_value) {
5463
at::Tensor a = at::rand({128 * 1024}, test_device());
5564
std::optional<at::Tensor> b = at::rand({128 * 1024}, test_device());
5665

57-
c10::Scalar alpha(3.14);
66+
c10::Scalar alpha = make_float_scalar(3.14);
5867
at::Tensor result = my_ops::axpy3(a, b, alpha);
5968
at::Tensor expected = at::add(alpha * a, b.value());
6069
EXPECT_TRUE(torch::allclose(result, expected));
@@ -64,7 +73,7 @@ TEST(axpy_test, optional_tensor_nullopt) {
6473
at::Tensor a = at::rand({128 * 1024}, test_device());
6574
std::optional<at::Tensor> b = std::nullopt;
6675

67-
c10::Scalar alpha(3.14);
76+
c10::Scalar alpha = make_float_scalar(3.14);
6877
at::Tensor result = my_ops::axpy3(a, b, alpha);
6978
at::Tensor expected = alpha * a;
7079
EXPECT_TRUE(torch::allclose(result, expected));

examples/common/backend_ops.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#elif defined(BACKEND_MACA)
2121
#include <mcr/mc_runtime.h>
2222
#include "c10/cuda/CUDAStream.h"
23+
#elif defined(BACKEND_GCU)
24+
#include <tops_runtime_api.h>
2325
#else
2426
#include "c10/cuda/CUDAStream.h"
2527
#endif
@@ -33,6 +35,8 @@ using RawStream = aclrtStream;
3335
using RawStream = musaStream_t;
3436
#elif defined(BACKEND_MACA)
3537
using RawStream = mcStream_t;
38+
#elif defined(BACKEND_GCU)
39+
using RawStream = topsStream_t;
3640
#else
3741
using RawStream = CUstream;
3842
#endif
@@ -49,6 +53,8 @@ inline RawStream get_device_stream([[maybe_unused]] const at::Tensor& t) {
4953
return nullptr;
5054
#elif defined(BACKEND_MACA)
5155
return reinterpret_cast<mcStream_t>(c10::cuda::getCurrentCUDAStream(t.device().index()).stream());
56+
#elif defined(BACKEND_GCU)
57+
return nullptr;
5258
#else
5359
return static_cast<CUstream>(c10::cuda::getCurrentCUDAStream(t.device().index()).stream());
5460
#endif

examples/common/op_registration.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <torch/torch.h>
44

5-
#if defined(BACKEND_NPU) || defined(BACKEND_MUSA)
5+
#if defined(BACKEND_NPU) || defined(BACKEND_MUSA) || defined(BACKEND_GCU)
66
#define TRITON_DISPATCH_KEY PrivateUse1
77
#else
88
#define TRITON_DISPATCH_KEY CUDA

examples/pointwise/test_add.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
#include "add_op.h"
33
#include "torch/torch.h"
44
#include "triton_jit/backend_config.h"
5-
65
static at::Device test_device() {
76
#if defined(BACKEND_NPU)
87
return at::Device("npu:0");
98
#elif defined(BACKEND_MUSA)
109
return at::Device("musa:0");
10+
#elif defined(BACKEND_GCU)
11+
return at::Device("gcu:0");
1112
#else
1213
return at::kCUDA;
1314
#endif

examples/reduce/test_sum.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
#include "sum_op.h"
33
#include "torch/torch.h"
44
#include "triton_jit/backend_config.h"
5-
65
static at::Device test_device() {
76
#if defined(BACKEND_NPU)
87
return at::Device("npu:0");
98
#elif defined(BACKEND_MUSA)
109
return at::Device("musa:0");
10+
#elif defined(BACKEND_GCU)
11+
return at::Device("gcu:0");
1112
#else
1213
return at::kCUDA;
1314
#endif

include/triton_jit/backend_config.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "triton_jit/backends/maca_backend.h"
99
#elif defined(BACKEND_IX)
1010
#include "triton_jit/backends/ix_backend.h"
11+
#elif defined(BACKEND_GCU)
12+
#include "triton_jit/backends/gcu_backend.h"
1113
#else
1214
#include "triton_jit/backends/cuda_backend.h"
1315
#endif
@@ -34,6 +36,10 @@ using DefaultBackend = CudaBackend;
3436
/// Default backend for IX (Tianshu)
3537
using DefaultBackend = IxBackend;
3638

39+
#elif defined(BACKEND_GCU)
40+
/// Default backend for GCU (Enflame)
41+
using DefaultBackend = GcuBackend;
42+
3743
#else
3844
// Default to CUDA if no backend specified
3945
#warning "No backend specified, defaulting to CUDA. Use -DBACKEND=CUDA explicitly."
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#pragma once
2+
3+
#include <mutex>
4+
#include <stdexcept>
5+
#include <string>
6+
#include <unordered_map>
7+
8+
#include "c10/util/Logging.h"
9+
#include "tops_runtime_api.h"
10+
#include "fmt/core.h"
11+
#include "triton_jit/backend_policy.h"
12+
#include "triton_jit/kernel_metadata.h"
13+
14+
namespace triton_jit {
15+
16+
struct GcuBackend {
17+
using StreamType = topsStream_t;
18+
using ContextType = void*;
19+
using KernelHandle = topsFunction_t;
20+
21+
// GCU blockDimX = num_warps directly, so WARP_SIZE = 1
22+
static constexpr unsigned int WARP_SIZE = 1;
23+
24+
struct LaunchOptions {
25+
unsigned int shared_memory = 0;
26+
};
27+
28+
static inline std::unordered_map<std::string, std::pair<topsModule_t, topsFunction_t>> module_cache_;
29+
static inline std::mutex cache_mutex_;
30+
31+
static LaunchOptions prepare_launch(const std::string& dir,
32+
const std::string& name,
33+
unsigned int shared_mem,
34+
const std::string& sig,
35+
size_t num_args) {
36+
return {.shared_memory = shared_mem};
37+
}
38+
39+
static void launch_kernel(topsStream_t stream,
40+
topsFunction_t kernel,
41+
unsigned grid_x,
42+
unsigned grid_y,
43+
unsigned grid_z,
44+
unsigned block_x,
45+
unsigned block_y,
46+
unsigned block_z,
47+
void** args,
48+
const LaunchOptions& opts) {
49+
LOG(INFO) << fmt::format("topsModuleLaunchKernelEx: grid=({},{},{}), num_warps={}, shmem={}",
50+
grid_x, grid_y, grid_z, block_x, opts.shared_memory);
51+
52+
topsLaunchConfig_t config;
53+
memset(&config, 0, sizeof(config));
54+
config.gridDim = dim3(grid_x, grid_y, grid_z);
55+
config.blockDim = dim3(1, 1, 1);
56+
config.dynamicSmemBytes = opts.shared_memory;
57+
config.stream = stream;
58+
59+
topsLaunchAttribute_t att;
60+
att.id = topsLaunchAttributeThreadDimension;
61+
att.val.ThreadDim.x = block_x;
62+
att.val.ThreadDim.y = 1;
63+
att.val.ThreadDim.z = 1;
64+
config.attrs = &att;
65+
config.numAttrs = 1;
66+
67+
topsError_t result = topsModuleLaunchKernelEx(&config, kernel, args, nullptr);
68+
69+
if (result != topsSuccess) {
70+
throw std::runtime_error(fmt::format("GCU kernel launch failed: {} (error code {})",
71+
topsGetErrorString(result), static_cast<int>(result)));
72+
}
73+
}
74+
75+
static void ensure_context() {
76+
// GCU uses tops runtime which manages context implicitly via topsSetDevice
77+
}
78+
79+
static int get_device_index() {
80+
int device_id = 0;
81+
topsError_t result = topsGetDevice(&device_id);
82+
83+
if (result != topsSuccess) {
84+
throw std::runtime_error(fmt::format("Failed to get GCU device index: {} (error code {})",
85+
topsGetErrorString(result), static_cast<int>(result)));
86+
}
87+
return device_id;
88+
}
89+
90+
static topsFunction_t load_kernel(const std::string& dir, const std::string& kernel_name) {
91+
std::string key = fmt::format("{}::{}", dir, kernel_name);
92+
std::lock_guard<std::mutex> lock(cache_mutex_);
93+
94+
auto it = module_cache_.find(key);
95+
if (it != module_cache_.end()) {
96+
return it->second.second;
97+
}
98+
99+
LOG(INFO) << fmt::format("Loading GCU kernel {}", kernel_name);
100+
101+
std::string fatbin_path = fmt::format("{}/{}.fatbin", dir, kernel_name);
102+
LOG(INFO) << fmt::format("Loading fatbin from {}", fatbin_path);
103+
104+
topsModule_t module;
105+
topsError_t err = topsModuleLoad(&module, fatbin_path.c_str());
106+
if (err != topsSuccess) {
107+
throw std::runtime_error(fmt::format("Failed to load GCU module from: {} ({}, error {})",
108+
fatbin_path, topsGetErrorString(err), static_cast<int>(err)));
109+
}
110+
111+
topsFunction_t function;
112+
err = topsModuleGetFunction(&function, module, kernel_name.c_str());
113+
if (err != topsSuccess) {
114+
topsModuleUnload(module);
115+
throw std::runtime_error(fmt::format("Failed to get function '{}' from module ({}, error {})",
116+
kernel_name, topsGetErrorString(err), static_cast<int>(err)));
117+
}
118+
119+
module_cache_[key] = {module, function};
120+
return function;
121+
}
122+
123+
static unsigned int get_shared_memory(const std::string& dir, const std::string& kernel_name) {
124+
return load_shared_memory(dir, kernel_name);
125+
}
126+
};
127+
128+
static_assert(BackendPolicy<GcuBackend>, "GcuBackend must satisfy BackendPolicy concept");
129+
130+
} // namespace triton_jit

include/triton_jit/jit_utils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <musa.h>
1717
#elif defined(BACKEND_MACA)
1818
#include <mcr/mc_runtime.h>
19+
#elif defined(BACKEND_GCU)
1920
#else
2021
#include "cuda.h"
2122
#endif
@@ -166,6 +167,8 @@ inline void __checkMacaErrors(mcError_t code, const char* file, const int line)
166167
throw std::runtime_error(error_string ? error_string : "Unknown MACA error");
167168
}
168169
}
170+
#elif defined(BACKEND_GCU)
171+
// GCU error handling is done inline in gcu_backend.h
169172
#else
170173
void ensure_cuda_context();
171174

0 commit comments

Comments
 (0)