topo_utils.cpp 5.03 KB
Newer Older
lishen's avatar
lishen committed
1
2
3
4
5
6
7
#include <string.h>
#include "topo_utils.h"

namespace sccl {
namespace hardware {
namespace topology {

8
9
10
11
12
13
14
/**
 * 将64位整数转换为PCI总线ID字符串
 *
 * @param id 输入的64位整数,包含PCI总线ID信息
 * @param busId 输出缓冲区,用于存储格式化后的PCI总线ID字符串(格式为"域:总线:设备.功能")
 * @return 返回scclSuccess表示成功
 */
lishen's avatar
lishen committed
15
16
17
18
19
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;
}

20
21
22
23
24
25
26
27
28
29
/**
 * 将总线ID字符串转换为64位整数值
 *
 * @param busId 输入的总线ID字符串,可能包含分隔符(.或:)
 * @param id 输出参数,用于存储转换后的64位整数值
 * @return 返回操作结果,scclSuccess表示成功
 *
 * @note 总线ID字符串中的非十六进制字符(0-9,a-f,A-F)和分隔符将被忽略
 *       转换后的值通过strtol以16进制解析获得
 */
lishen's avatar
lishen committed
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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;
}

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#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;
}

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 定义一个常量,表示最大字符串长度
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;
}

lishen's avatar
lishen committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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