#include <iostream>
#include <fstream>
#include <vector>
#include <tuple>
#include <cstring>
#include <cstdint>
#include <ctime>
#include <sstream>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <dirent.h>
#include <unistd.h>
#include <dlfcn.h>
#include "ge_table_op_resource.h"
#include "graph/ascend_string.h"
#include "graph/operator_reg.h"
#include "register/op_lib_register.h"
#include "register/op_impl_registry.h"
#include "../pkg_inc/base/dlog_pub.h"
#define ASCENDC_MODULE_NAME static_cast<int32_t>(ASCENDCKERNEL)
#define LOG_ERROR(format, ...) \
do { \
dlog_error(ASCENDC_MODULE_NAME, "[%s] " format "\n", __FUNCTION__, ##__VA_ARGS__); \
} while (0)
#define LOG_WARN(format, ...) \
do { \
dlog_warn(ASCENDC_MODULE_NAME, "[%s] " format "\n", __FUNCTION__, ##__VA_ARGS__); \
} while (0)
#define LOG_INFO(format, ...) \
do { \
dlog_info(ASCENDC_MODULE_NAME, "[%s] " format "\n", __FUNCTION__, ##__VA_ARGS__); \
} while (0)
char basePathChar[PATH_MAX];
void CheckCloseDir(DIR* dir, const char* file, int line, const char* func)
{
if (closedir(dir) != 0) {
LOG_ERROR("closedir failed, [%s:%d]%s", file, line, func);
}
}
bool FileExist(const std::string& filename)
{
std::ifstream file(filename);
return file.good();
}
bool DirectoryExists(const std::string& path)
{
DIR* dir = opendir(path.c_str());
if (dir != nullptr) {
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
return true;
} else {
return false;
}
}
std::string GetCurrentTimestamp()
{
std::time_t now = std::time(nullptr);
char buf[64];
(void)std::strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", std::localtime(&now));
return std::to_string(getpid()) + "_" + std::string(buf);
}
bool CheckWritePermission(const std::string& path)
{
if (access(path.c_str(), W_OK) != 0) {
LOG_ERROR("No write permission for the path: %s, errno: %d, error: %s", path.c_str(), errno, strerror(errno));
return false;
}
return true;
}
bool GetBasePath()
{
const char *ascendWorkPathEnv = std::getenv("ASCEND_WORK_PATH");
std::string currentTimestamp = GetCurrentTimestamp();
std::string path;
if (ascendWorkPathEnv != nullptr) {
char resolvedPath[PATH_MAX];
if (realpath(ascendWorkPathEnv, resolvedPath) == nullptr) {
LOG_ERROR("Invalid ASCEND_WORK_PATH: %s", ascendWorkPathEnv);
return false;
} else {
std::string ascendWorkPath = std::string(resolvedPath);
path = ascendWorkPath + "/opp/" + currentTimestamp + "/vendors/";
if (!CheckWritePermission(ascendWorkPath)) {
return false;
}
}
} else {
path = "/tmp/opp/" + currentTimestamp + "/vendors/";
if (!CheckWritePermission("/tmp/")) {
return false;
}
}
errno_t err = strcpy_s(basePathChar, PATH_MAX, path.c_str());
if (err != 0) {
LOG_ERROR("Error copying string, error code: %d", err);
return false;
}
return true;
}
bool CreateDirectory(const std::string& path)
{
if (DirectoryExists(path)) {
return true;
} else {
char* p = const_cast<char*>(path.c_str());
char* slash = strchr(p + 1, '/');
while (slash != nullptr) {
*slash = '\0';
int status = mkdir(p, S_IRWXU | S_IRWXG);
*slash = '/';
if (status == -1 && errno != EEXIST) {
LOG_ERROR("Error create diectory failed");
return false;
}
slash = strchr(slash + 1, '/');
}
int status = mkdir(p, S_IRWXU | S_IRWXG);
if (status == -1 && errno != EEXIST) {
LOG_ERROR("Error create diectory failed, path: %s", path.c_str());
return false;
}
return true;
}
}
void WriteBinaryFile(const std::string& path, const uint8_t* start, const uint8_t* end)
{
std::ofstream outfile(path, std::ios::binary);
if (!outfile) {
LOG_ERROR("Error opening file for writing: %s", path.c_str());
return;
}
std::copy(start, end, std::ostreambuf_iterator<char>(outfile));
if (!outfile) {
LOG_ERROR("Error writing file: %s", path.c_str());
}
LOG_INFO("Successfully writing file: %s", path.c_str());
}
std::string GetParentPath(const std::string& path)
{
size_t pos = path.find_last_of("/\\");
if (pos == std::string::npos) {
return "";
}
return path.substr(0, pos);
}
bool CreateSymlink(const std::string& targetPath, const std::string& linkPath)
{
try {
if (!FileExist(targetPath)) {
throw std::runtime_error("Target file does not exist: " + targetPath);
}
std::string parentDir = GetParentPath(linkPath);
if (!DirectoryExists(parentDir)) {
if (!CreateDirectory(parentDir)) {
LOG_ERROR("Failed create directory: %s", parentDir.c_str());
return false;
}
}
if (symlink(targetPath.c_str(), linkPath.c_str()) != 0) {
LOG_ERROR("Error creating symlink failed.");
return false;
}
LOG_INFO("Successfully creating symlink: %s", linkPath.c_str());
return true;
} catch (const std::exception& e) {
LOG_ERROR("Error creating symlink: %s", e.what());
return false;
}
}
std::string GetSystemArchitecture() {
const char* systemArch = std::getenv("SYSTEM_PROCESSOR");
if (systemArch != nullptr) {
return std::string(systemArch);
} else {
struct utsname sysInfo;
if (uname(&sysInfo) == 0) {
return sysInfo.machine;
} else {
return "";
}
}
}
uint32_t ImplCustomOpRegistry(ge::AscendString& op_lib_path)
{
if (!GetBasePath()) {
return 1;
}
std::string basePath = std::string(basePathChar);
if (!CreateDirectory(basePath)) {
return 1;
}
std::string vendorName = "";
for (const auto& fileInfo : AscendC::__ascendc_op_info) {
std::string fileName = std::get<0>(fileInfo).GetString();
std::string filePath = std::get<1>(fileInfo).GetString();
const uint8_t* start = std::get<2>(fileInfo);
const uint8_t* end = std::get<3>(fileInfo);
std::string fullPath = (basePath) + "/" + filePath + "/" + fileName;
if (!CreateDirectory((basePath) + "/" + filePath)) {
LOG_ERROR("Failed to create subdirectory: %s", filePath.c_str());
return 1;
}
WriteBinaryFile(fullPath, start, end);
if (vendorName.empty()) {
size_t firstSlashPos = filePath.find('/');
if (firstSlashPos != std::string::npos) {
vendorName = filePath.substr(0, firstSlashPos);
} else {
LOG_ERROR("Failed to get vendor_name");
return 1;
}
}
}
op_lib_path = ConvertToAscendString(basePath + vendorName);
Dl_info dlInfo;
if (!dladdr((void*)&ImplCustomOpRegistry, &dlInfo)) {
LOG_ERROR("dladdr failed: %s", dlerror());
return 1;
}
std::string targetPath = dlInfo.dli_fname;
char resolvedPath[PATH_MAX];
if (realpath(targetPath.c_str(), resolvedPath) == nullptr) {
LOG_ERROR("Failed to resolve libcust_opapi.so path: %s", strerror(errno));
return 1;
}
targetPath = std::string(resolvedPath);
LOG_INFO("Resolve libcust_opapi.so path is: %s", targetPath.c_str());
std::string arch = GetSystemArchitecture();
if (arch.empty()) {
LOG_ERROR("Failed to get system architecture name");
return 1;
}
std::string opmasterPath = basePath + vendorName + "/op_impl/ai_core/tbe/op_tiling/lib/linux/" +
arch + "/libcust_opmaster_rt2.0.so";
if (!CreateSymlink(targetPath, opmasterPath)) {
LOG_ERROR("Failed to create symlink for libcust_opmaster_rt2.0.so");
return 1;
}
std::string opsprotoPath = basePath + vendorName + "/op_proto/lib/linux/" + arch + "/libcust_opsproto_rt2.0.so";
if (!CreateSymlink(targetPath, opsprotoPath)) {
LOG_ERROR("Failed to create symlink for libcust_opsproto_rt2.0.so");
return 1;
}
std::string optilingPath = basePath + vendorName + "/op_impl/ai_core/tbe/op_tiling/liboptiling.so";
if (!CreateSymlink(targetPath, optilingPath)) {
LOG_ERROR("Failed to create symlink for liboptiling.so");
return 1;
}
return 0;
}
bool RemoveDirectoryRecursively(const std::string& path)
{
DIR* dir = opendir(path.c_str());
if (dir == nullptr) {
const int32_t currentErr = errno;
if (currentErr == ENOENT) {
LOG_WARN("Directory does not exist: %s", path.c_str());
return true;
} else {
LOG_ERROR("Failed to open directory: %s", path.c_str());
return false;
}
}
dirent* entry = readdir(dir);
while (entry != nullptr) {
std::string entryPath = path + "/" + entry->d_name;
if (static_cast<int32_t>(entry->d_type) == DT_DIR) {
if (std::string(entry->d_name) != "." && std::string(entry->d_name) != "..") {
if (!RemoveDirectoryRecursively(entryPath)) {
LOG_ERROR("Failed to remove subdirectory: %s", entryPath.c_str());
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
return false;
}
LOG_INFO("Successfully remove subdirectory: %s", entryPath.c_str());
}
} else {
if (unlink(entryPath.c_str()) != 0) {
LOG_ERROR("Failed to unlink file: %s", entryPath.c_str());
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
return false;
}
LOG_INFO("Successfully remove linkpath: %s", entryPath.c_str());
}
entry = readdir(dir);
}
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
bool result = (rmdir(path.c_str()) == 0);
return result;
}
REGISTER_OP_LIB(customize).RegOpLibInit(ImplCustomOpRegistry);
bool IsDirectoryEmpty(const std::string& dirPath) {
DIR* dir = opendir(dirPath.c_str());
if (dir == nullptr) {
const int32_t currentErr = errno;
if (currentErr == ENOENT) {
LOG_WARN("Directory is already empty: %s", dirPath.c_str());
return true;
} else {
LOG_ERROR("Failed to open directory: %s", dirPath.c_str());
return false;
}
}
dirent* entry = readdir(dir);
while (entry != nullptr) {
if (strncmp(entry->d_name, ".", 1) != 0 && strncmp(entry->d_name, "..", 2) != 0) {
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
return false;
}
entry = readdir(dir);
}
CheckCloseDir(dir, __FILE__, __LINE__, __FUNCTION__);
return true;
}
__attribute__((destructor)) void DestroyCustomOpRegistry()
{
std::string basePath = std::string(basePathChar);
size_t lastSlashPos = (basePath).rfind('/');
size_t secondLastSlashPos = (basePath).rfind('/', lastSlashPos - 1u);
std::string oppBasePath = (basePath).substr(0, secondLastSlashPos);
if (!RemoveDirectoryRecursively(oppBasePath)) {
LOG_ERROR("Failed to remove directory: %s", oppBasePath.c_str());
} else {
LOG_INFO("Successfully removed directory: %s", oppBasePath.c_str());
const std::string oppSubstring = "/opp/";
size_t pos = oppBasePath.find(oppSubstring);
std::string oppDir = oppBasePath.substr(0, pos + oppSubstring.length() - 1);
if (IsDirectoryEmpty(oppDir)) {
if (rmdir(oppDir.c_str()) != 0) {
LOG_WARN("Failed to remove empty opp directory: %s", oppDir.c_str());
} else {
LOG_INFO("Successfully removed empty opp directory: %s", oppDir.c_str());
}
}
}
}