#include #include "topo_utils.h" namespace sccl { namespace hardware { namespace topology { /** * 将64位整数转换为PCI总线ID字符串 * * @param id 输入的64位整数,包含PCI总线ID信息 * @param busId 输出缓冲区,用于存储格式化后的PCI总线ID字符串(格式为"域:总线:设备.功能") * @return 返回scclSuccess表示成功 */ scclResult_t int64ToBusId(int64_t id, char* busId) { sprintf(busId, "%04lx:%02lx:%02lx.%01lx", (id) >> 20, (id & 0xff000) >> 12, (id & 0xff0) >> 4, (id & 0xf)); return scclSuccess; } /** * 将总线ID字符串转换为64位整数值 * * @param busId 输入的总线ID字符串,可能包含分隔符(.或:) * @param id 输出参数,用于存储转换后的64位整数值 * @return 返回操作结果,scclSuccess表示成功 * * @note 总线ID字符串中的非十六进制字符(0-9,a-f,A-F)和分隔符将被忽略 * 转换后的值通过strtol以16进制解析获得 */ scclResult_t busIdToInt64(const char* busId, int64_t* id) { char hexStr[17]; // Longest possible int64 hex string + null terminator. int hexOffset = 0; for(int i = 0; hexOffset < sizeof(hexStr) - 1; i++) { char c = busId[i]; if(c == '.' || c == ':') continue; if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { hexStr[hexOffset++] = busId[i]; } else break; } hexStr[hexOffset] = '\0'; *id = strtol(hexStr, NULL, 16); return scclSuccess; } #define BUSID_SIZE (sizeof("0000:00:00.0")) #define BUSID_REDUCED_SIZE (sizeof("0000:00")) static void memcpylower(char* dst, const char* src, const size_t size) { for(int i = 0; i < size; i++) dst[i] = tolower(src[i]); } /** * @brief 获取给定PCI设备的路径。 * * 此函数根据提供的PCI设备的总线ID(busId),生成该设备在系统中的实际路径。 * 它首先构造一个可能的路径字符串,然后使用`realpath`函数将其转换为实际的文件系统路径。 * 如果路径无法解析,函数将返回一个错误代码。 * * @param busId 一个C字符串,表示PCI设备的总线ID。例如:"0000:00:00.0"。 * @param path 一个指向字符指针的指针,用于存储解析后的实际路径。调用者负责释放此内存。 * * @return scclResult_t 返回操作结果。如果成功,返回`scclSuccess`;如果失败,返回`scclSystemError`。 * * @note 此函数内部使用了`realpath`函数,该函数可能因路径不存在或其他系统错误而失败。 * 在这种情况下,函数将输出一个警告信息,并返回错误代码。 */ scclResult_t getPciPath(const char* busId, char** path) { char busPath[] = "/sys/class/pci_bus/0000:00/../../0000:00:00.0"; memcpylower(busPath + sizeof("/sys/class/pci_bus/") - 1, busId, BUSID_REDUCED_SIZE - 1); memcpylower(busPath + sizeof("/sys/class/pci_bus/0000:00/../../") - 1, busId, BUSID_SIZE - 1); *path = realpath(busPath, NULL); if(*path == NULL) { WARN("Could not find real path of %s", busPath); return scclSystemError; } return scclSuccess; } // 定义一个常量,表示最大字符串长度 static constexpr int MAX_STR_LEN = 255; /** * @brief 从系统文件中读取字符串内容 * * 该函数通过拼接路径和文件名,打开指定文件并读取其内容到字符串缓冲区中。 * 如果读取失败或文件为空,会将缓冲区置为空字符串并记录警告信息。 * * @param path 文件所在目录路径 * @param fileName 要读取的文件名 * @param strValue 用于存储读取内容的字符串缓冲区 * @return scclResult_t 始终返回scclSuccess * * @note 缓冲区最大长度为MAX_STR_LEN,超出部分会被截断 * 文件内容末尾会自动添加字符串结束符'\0' */ scclResult_t scclTopoGetStrFromSys(const char* path, const char* fileName, char* strValue) { char filePath[PATH_MAX]; sprintf(filePath, "%s/%s", path, fileName); int offset = 0; FILE* file; if((file = fopen(filePath, "r")) != NULL) { while(feof(file) == 0 && ferror(file) == 0 && offset < MAX_STR_LEN) { int len = fread(strValue + offset, 1, MAX_STR_LEN - offset, file); offset += len; } fclose(file); } if(offset == 0) { strValue[0] = '\0'; INFO(SCCL_LOG_TOPO, "System detection : could not read %s, ignoring", filePath); } else { strValue[offset - 1] = '\0'; } return scclSuccess; } scclResult_t pciPathToInt64(char* path, int offset, int minOffset, int64_t* id) { char* str = path + offset; // Remove trailing "/" if(*str == '/') str--; // Find next / while(*str != '/') str--; str++; int64_t numid; SCCLCHECK(busIdToInt64(str, &numid)); // Ignore subdevice because those should use the same PCI link so we want to merge nodes. numid -= numid & 0xf; *id = numid; return scclSuccess; } } // namespace topology } // namespace hardware } // namespace sccl