/* | |
* Copyright (c) 2023-2024 The ggml authors | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to | |
* deal in the Software without restriction, including without limitation the | |
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | |
* sell copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | |
* IN THE SOFTWARE. | |
*/ | |
/** | |
* @brief Handles CANN-related errors by printing an error message and | |
* terminating the program. | |
* @param stmt The statement that caused the error. | |
* @param func The function in which the error occurred. | |
* @param file The file in which the error occurred. | |
* @param line The line number at which the error occurred. | |
* @param msg The error message. | |
*/ | |
[[noreturn]] void ggml_cann_error(const char* stmt, const char* func, | |
const char* file, int line, const char* msg); | |
/** | |
* @brief Checks the result of a CANN function call and invokes the error | |
* handler if the call fails. | |
* @param stmt The CANN function call to check. | |
* @param success The success code that indicates the call was successful. | |
* @param error_fn The function to call to retrieve the error message. | |
*/ | |
/** | |
* @brief Contains information about CANN devices. | |
*/ | |
struct ggml_cann_device_info { | |
/** | |
* @brief Number of CANN devices available. | |
*/ | |
int32_t device_count; | |
/** | |
* @brief Information about a single CANN device. | |
*/ | |
struct cann_device_info { | |
int cc; /**< Compute capability. */ | |
size_t smpb; /**< Maximum shared memory per block. */ | |
bool vmm; /**< Virtual memory support. */ | |
size_t vmm_granularity; /**< Granularity of virtual memory. */ | |
size_t total_vram; /**< Total video RAM available on the device. */ | |
}; | |
cann_device_info devices[GGML_CANN_MAX_DEVICES] = | |
{}; /**< Array of CANN device information. */ | |
}; | |
const ggml_cann_device_info& ggml_cann_info(); | |
void ggml_cann_set_device(int32_t device); | |
int32_t ggml_cann_get_device(); | |
/** | |
* @brief Abstract base class for memory pools used by CANN. | |
*/ | |
struct ggml_cann_pool { | |
/** | |
* @brief Virtual destructor for the memory pool. | |
*/ | |
virtual ~ggml_cann_pool() = default; | |
/** | |
* @brief Allocates memory from the pool. | |
* | |
* @param size The size of the memory block to allocate. | |
* @param actual_size Pointer to a variable where the actual allocated size | |
* will be stored. | |
* @return Pointer to the allocated memory block. | |
*/ | |
virtual void* alloc(size_t size, size_t* actual_size) = 0; | |
/** | |
* @brief Frees a previously allocated memory block. | |
* | |
* @param ptr Pointer to the memory block to free. | |
* @param size Size of the memory block to free. | |
* @note Note that all CANN opertors are running async. Make sure memory is | |
* still avaiable before this operator finished. | |
*/ | |
virtual void free(void* ptr, size_t size) = 0; | |
}; | |
/** | |
* @brief RAII wrapper for managing memory allocations from a CANN memory pool. | |
*/ | |
struct ggml_cann_pool_alloc { | |
ggml_cann_pool* pool = nullptr; /**< Pointer to the memory pool. */ | |
void* ptr = nullptr; /**< Pointer to the allocated memory block. */ | |
size_t actual_size = 0; /**< Actual size of the allocated memory block. */ | |
/** | |
* @brief Default constructor. | |
*/ | |
ggml_cann_pool_alloc() = default; | |
/** | |
* @brief Constructor that initializes the memory pool. | |
* @param pool Reference to the memory pool. | |
*/ | |
explicit ggml_cann_pool_alloc(ggml_cann_pool& pool) : pool(&pool) {} | |
/** | |
* @brief Constructor that initializes the memory pool and allocates memory. | |
* @param pool Reference to the memory pool. | |
* @param size Size of the memory block to allocate. | |
*/ | |
ggml_cann_pool_alloc(ggml_cann_pool& pool, size_t size) : pool(&pool) { | |
alloc(size); | |
} | |
/** | |
* @brief Destructor that frees the allocated memory block. | |
*/ | |
~ggml_cann_pool_alloc() { | |
if (ptr != nullptr) { | |
pool->free(ptr, actual_size); | |
} | |
} | |
/** | |
* @brief Allocates memory from the pool. | |
* @param size Size of the memory block to allocate. | |
* @return Pointer to the allocated memory block. | |
*/ | |
void* alloc(size_t size) { | |
GGML_ASSERT(pool != nullptr); | |
GGML_ASSERT(ptr == nullptr); | |
ptr = pool->alloc(size, &this->actual_size); | |
return ptr; | |
} | |
/** | |
* @brief Allocates memory from a specific memory pool. | |
* @param pool Reference to the memory pool. | |
* @param size Size of the memory block to allocate. | |
* @return Pointer to the allocated memory block. | |
*/ | |
void* alloc(ggml_cann_pool& pool, size_t size) { | |
this->pool = &pool; | |
return alloc(size); | |
} | |
/** | |
* @brief Gets the pointer to the allocated memory block. | |
* @return Pointer to the allocated memory block. | |
*/ | |
void* get() { return ptr; } | |
// Deleted copy constructor | |
ggml_cann_pool_alloc(const ggml_cann_pool_alloc&) = delete; | |
// Deleted move constructor | |
ggml_cann_pool_alloc(ggml_cann_pool_alloc&&) = delete; | |
// Deleted copy assignment operator | |
ggml_cann_pool_alloc& operator=(const ggml_cann_pool_alloc&) = delete; | |
// Deleted move assignment operator | |
ggml_cann_pool_alloc& operator=(ggml_cann_pool_alloc&&) = delete; | |
}; | |
/** | |
* @brief Context for managing CANN backend operations. | |
*/ | |
struct ggml_backend_cann_context { | |
int32_t device; /**< Device ID. */ | |
std::string name; /**< Name of the device. */ | |
std::string description; /**< Description of the device. */ | |
aclrtEvent copy_event = nullptr; /**< Event for managing copy operations. */ | |
aclrtStream streams[GGML_CANN_MAX_STREAMS] = {nullptr}; /**< Array of streams for the device. */ | |
/** | |
* @brief Constructor for initializing the context with a given device. | |
* @param device Device ID. | |
*/ | |
explicit ggml_backend_cann_context(int device) | |
: device(device), name("CANN" + std::to_string(device)) { | |
ggml_cann_set_device(device); | |
description = aclrtGetSocName(); | |
} | |
/** | |
* @brief Destructor for cleaning up resources. | |
*/ | |
~ggml_backend_cann_context() { | |
ggml_cann_set_device(device); | |
if (copy_event != nullptr) { | |
ACL_CHECK(aclrtDestroyEvent(copy_event)); | |
} | |
for (int i = 0; i < GGML_CANN_MAX_STREAMS; ++i) { | |
if (streams[i] != nullptr) { | |
ACL_CHECK(aclrtDestroyStream(streams[i])); | |
} | |
} | |
} | |
/** | |
* @brief Get or create a stream for a given index. | |
* @param stream Index of the stream. | |
* @return The stream corresponding to the given index. | |
*/ | |
aclrtStream stream(int stream) { | |
if (streams[stream] == nullptr) { | |
ggml_cann_set_device(device); | |
ACL_CHECK(aclrtCreateStream(&streams[stream])); | |
} | |
return streams[stream]; | |
} | |
/** | |
* @brief Get or create the default stream (index 0). | |
* @return The default stream. | |
*/ | |
aclrtStream stream() { return stream(0); } | |
// TODO: each stream should have a memory pool. | |
std::unique_ptr<ggml_cann_pool> | |
mem_pool; /**< Memory pool for the device. */ | |
/** | |
* @brief Create a new memory pool for a given device. | |
* @param device Device ID. | |
* @return A unique pointer to the new memory pool. | |
*/ | |
static std::unique_ptr<ggml_cann_pool> new_pool_for_device(int device); | |
/** | |
* @brief Get or create the memory pool for the context. | |
* @return Reference to the memory pool. | |
*/ | |
ggml_cann_pool& pool() { | |
if (mem_pool == nullptr) { | |
mem_pool = new_pool_for_device(device); | |
} | |
return *mem_pool; | |
} | |
}; | |