-
Notifications
You must be signed in to change notification settings - Fork 16
Move bmm calls to stable cshim #220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
69463cb
19635e8
bab7e4d
387ecf7
d2eac4e
ee1829c
e4df36c
4e3dcc8
7399be6
99d06ea
4314273
cc02c70
62eae5c
15f766a
e644be8
157de65
9ab016f
64af319
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,141 +1,73 @@ | ||
| #pragma once | ||
|
|
||
| #include <array> | ||
| #include <cstdint> | ||
| #include <memory> | ||
| #include <stdexcept> | ||
| #include <type_traits> | ||
|
|
||
| #ifdef CUDA_BACKEND | ||
| #include "cublas_v2.h" | ||
| #include <cuda_runtime.h> | ||
| #include <torch/csrc/inductor/aoti_torch/generated/c_shim_cuda.h> | ||
|
|
||
| struct BlasHandle { | ||
| cublasHandle_t handle; | ||
| BlasHandle() { | ||
| if (cublasCreate(&handle) != CUBLAS_STATUS_SUCCESS) | ||
| throw std::logic_error("CUBLAS initialization failed"); | ||
| } | ||
| ~BlasHandle() { cublasDestroy(handle); } | ||
| }; | ||
| #elif defined(HIP_BACKEND) | ||
| #include "rocblas/rocblas.h" | ||
| #include <hip/hip_runtime.h> | ||
|
|
||
| struct BlasHandle { | ||
| rocblas_handle handle; | ||
| BlasHandle() { | ||
| if (rocblas_create_handle(&handle) != rocblas_status_success) | ||
| throw std::logic_error("rocBLAS initialization failed"); | ||
| } | ||
| ~BlasHandle() { rocblas_destroy_handle(handle); } | ||
| }; | ||
| #endif | ||
| namespace oeq { | ||
|
|
||
| inline BlasHandle& get_blas_handle() { | ||
| static BlasHandle handle; | ||
| return handle; | ||
| inline void check_group_mm_shim(AOTITorchError status) { | ||
| if (status != AOTI_TORCH_SUCCESS) | ||
| throw std::runtime_error("group_gemm: PyTorch C shim failed"); | ||
| } | ||
|
|
||
| template<typename T> | ||
| void group_gemm_blas(void* A_raw, void* B_raw, void* C_raw, | ||
| int64_t* ragged_counts, int num_W, int batch_size, int m, int k, int ragged_inner) { | ||
| using GroupMMTensor = std::unique_ptr< | ||
| std::remove_pointer_t<AtenTensorHandle>, | ||
| decltype(&aoti_torch_delete_tensor_object)>; | ||
|
|
||
| inline GroupMMTensor group_mm_view( | ||
| AtenTensorHandle tensor, std::array<int64_t, 3> sizes, | ||
| std::array<int64_t, 3> strides, int64_t offset) { | ||
| AtenTensorHandle view = nullptr; | ||
| check_group_mm_shim(aoti_torch__reinterpret_tensor( | ||
| tensor, 3, sizes.data(), strides.data(), offset, &view)); | ||
| return GroupMMTensor(view, aoti_torch_delete_tensor_object); | ||
| } | ||
|
|
||
| auto& blas = get_blas_handle(); | ||
| T alpha = 1.0, beta = 0.0; | ||
| T* A_base = reinterpret_cast<T*>(A_raw); | ||
| T* B_base = reinterpret_cast<T*>(B_raw); | ||
| T* C_base = reinterpret_cast<T*>(C_raw); | ||
| inline void group_gemm_torch( | ||
| AtenTensorHandle A, AtenTensorHandle B, AtenTensorHandle C, | ||
| const int64_t* ragged_counts, int64_t num_W, int64_t batch_size, | ||
| int64_t m, int64_t k, int64_t ragged_inner) { | ||
| if (batch_size == 0 || m == 0 || k == 0) | ||
| return; | ||
|
|
||
| int64_t ragged_offset = 0; | ||
| for (int i = 0; i < num_W; i++) { | ||
| int M, K, N, lda, ldb, ldc, strideA, strideB, strideC; | ||
| T *A, *B, *C; | ||
| #ifdef CUDA_BACKEND | ||
| cublasOperation_t transa, transb; | ||
| #elif defined(HIP_BACKEND) | ||
| rocblas_operation transa, transb; | ||
| #endif | ||
| int64_t offset = 0; | ||
| for (int64_t i = 0; i < num_W; ++i) { | ||
| const int64_t n = ragged_counts[i]; | ||
| if (n == 0) | ||
| continue; | ||
|
|
||
| if (ragged_inner == 0) { | ||
| M = m; K = k; N = static_cast<int>(ragged_counts[i]); | ||
| A = A_base + (m * k * batch_size * i); | ||
| lda = k; strideA = M * K; | ||
| B = B_base + (k * batch_size * ragged_offset); | ||
| ldb = K * batch_size; strideB = K; | ||
| C = C_base + (m * batch_size * ragged_offset); | ||
| ldc = M * batch_size; strideC = M; | ||
| #ifdef CUDA_BACKEND | ||
| transa = CUBLAS_OP_T; transb = CUBLAS_OP_N; | ||
| #elif defined(HIP_BACKEND) | ||
| transa = rocblas_operation_transpose; transb = rocblas_operation_none; | ||
| #endif | ||
| auto input = group_mm_view(B, | ||
| {batch_size, n, k}, {k, batch_size * k, 1}, | ||
| offset * batch_size * k); | ||
| auto weight = group_mm_view(A, | ||
| {batch_size, k, m}, {m * k, 1, k}, | ||
| i * batch_size * m * k); | ||
| auto output = group_mm_view(C, | ||
| {batch_size, n, m}, {m, batch_size * m, 1}, | ||
| offset * batch_size * m); | ||
| check_group_mm_shim(aoti_torch_cuda_bmm_out( | ||
| output.get(), input.get(), weight.get())); | ||
| } else { | ||
| M = k; K = static_cast<int>(ragged_counts[i]); N = m; | ||
| A = B_base + (k * batch_size * ragged_offset); | ||
| lda = k * batch_size; strideA = M; | ||
| B = A_base + (m * batch_size * ragged_offset); | ||
| ldb = m * batch_size; strideB = N; | ||
| C = C_base + (m * k * batch_size * i); | ||
| ldc = k; strideC = M * N; | ||
| #ifdef CUDA_BACKEND | ||
| transa = CUBLAS_OP_N; transb = CUBLAS_OP_T; | ||
| #elif defined(HIP_BACKEND) | ||
| transa = rocblas_operation_none; transb = rocblas_operation_transpose; | ||
| #endif | ||
| } | ||
| ragged_offset += ragged_counts[i]; | ||
|
|
||
| if (ragged_counts[i] > 0) { | ||
| #ifdef CUDA_BACKEND | ||
| cublasStatus_t stat; | ||
| if (std::is_same<T, float>::value) { | ||
| stat = cublasSgemmStridedBatched(blas.handle, | ||
| transa, transb, M, N, K, | ||
| reinterpret_cast<float*>(&alpha), | ||
| reinterpret_cast<float*>(A), lda, strideA, | ||
| reinterpret_cast<float*>(B), ldb, strideB, | ||
| reinterpret_cast<float*>(&beta), | ||
| reinterpret_cast<float*>(C), ldc, strideC, | ||
| batch_size); | ||
| } else if (std::is_same<T, double>::value) { | ||
| stat = cublasDgemmStridedBatched(blas.handle, | ||
| transa, transb, M, N, K, | ||
| reinterpret_cast<double*>(&alpha), | ||
| reinterpret_cast<double*>(A), lda, strideA, | ||
| reinterpret_cast<double*>(B), ldb, strideB, | ||
| reinterpret_cast<double*>(&beta), | ||
| reinterpret_cast<double*>(C), ldc, strideC, | ||
| batch_size); | ||
| } else { | ||
| throw std::logic_error("Unsupported datatype for grouped GEMM!"); | ||
| } | ||
| if (stat != CUBLAS_STATUS_SUCCESS) | ||
| throw std::logic_error("Grouped GEMM failed!"); | ||
| #elif defined(HIP_BACKEND) | ||
| rocblas_status stat; | ||
| if (std::is_same<T, float>::value) { | ||
| stat = rocblas_sgemm_strided_batched(blas.handle, | ||
| transa, transb, M, N, K, | ||
| reinterpret_cast<float*>(&alpha), | ||
| reinterpret_cast<float*>(A), lda, strideA, | ||
| reinterpret_cast<float*>(B), ldb, strideB, | ||
| reinterpret_cast<float*>(&beta), | ||
| reinterpret_cast<float*>(C), ldc, strideC, | ||
| batch_size); | ||
| } else if (std::is_same<T, double>::value) { | ||
| stat = rocblas_dgemm_strided_batched(blas.handle, | ||
| transa, transb, M, N, K, | ||
| reinterpret_cast<double*>(&alpha), | ||
| reinterpret_cast<double*>(A), lda, strideA, | ||
| reinterpret_cast<double*>(B), ldb, strideB, | ||
| reinterpret_cast<double*>(&beta), | ||
| reinterpret_cast<double*>(C), ldc, strideC, | ||
| batch_size); | ||
| } else { | ||
| throw std::logic_error("Unsupported datatype for grouped GEMM!"); | ||
| } | ||
| if (stat != rocblas_status_success) | ||
| throw std::logic_error("Grouped GEMM failed!"); | ||
| #endif | ||
| auto left = group_mm_view(A, | ||
| {batch_size, m, n}, {m, 1, batch_size * m}, | ||
| offset * batch_size * m); | ||
| auto right = group_mm_view(B, | ||
| {batch_size, n, k}, {k, batch_size * k, 1}, | ||
| offset * batch_size * k); | ||
| auto output = group_mm_view(C, | ||
| {batch_size, m, k}, {m * k, k, 1}, | ||
| i * batch_size * m * k); | ||
| check_group_mm_shim(aoti_torch_cuda_bmm_out( | ||
| output.get(), left.get(), right.get())); | ||
| } | ||
| offset += n; | ||
| } | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,20 @@ constexpr Dtype kByte = torch::headeronly::ScalarType::Byte; | |
| #define REGISTER_LIBRARY_IMPL STABLE_TORCH_LIBRARY_IMPL | ||
| #define REGISTER_LIBRARY STABLE_TORCH_LIBRARY | ||
|
|
||
| namespace { | ||
|
|
||
| class TensorDeviceGuard { | ||
| torch::stable::accelerator::DeviceGuard guard; | ||
| public: | ||
| explicit TensorDeviceGuard(const Tensor& tensor) : guard(tensor.get_device_index()) {} | ||
| }; | ||
|
|
||
| AtenTensorHandle tensor_handle(Tensor& tensor) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm - actually what is the purpose of this namespace and the wrapper for tensor.get(), not 100% sure what's going on here (namespace collision?). Might be necessary but I don't understand it atm |
||
| return tensor.get(); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| #include "torch_core.hpp" | ||
|
|
||
| Tensor tensor_to_cpu_contiguous(const Tensor &tensor) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,15 @@ | ||
| #define USE_CUDA | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remind me why this DEFINE is here? |
||
|
|
||
| #include <cstdint> | ||
| #include <torch/csrc/inductor/aoti_torch/c/shim.h> | ||
| #include <torch/csrc/inductor/aoti_torch/generated/c_shim_cuda.h> | ||
|
|
||
| extern "C" { | ||
| AOTITorchError aoti_torch_get_current_cuda_stream(int32_t device_index, void** ret_stream) { | ||
| return 0; | ||
| return AOTI_TORCH_FAILURE; | ||
| } | ||
|
|
||
| AOTITorchError aoti_torch_cuda_bmm_out( | ||
| AtenTensorHandle out, AtenTensorHandle self, AtenTensorHandle mat2) { | ||
| return AOTI_TORCH_FAILURE; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm - library_paths("cuda") on the hip branch looks weird, but I'm hoping this does the appropriate thing on AMD (that CUDA is just being used as a standin for hip.