char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

alex-spacemitggml-cpu: Add IME2 Instruction Support for the SpacemiT Backend (#22863)81b0d882a

char/aliceai-t5-moe
11.9 KiB320 linesraw
1#include "ime_env.h"
2
3#include "ggml-impl.h"
4#include "spine_mem_pool.h"
5
6#include <fcntl.h>
7#include <unistd.h>
8
9#include <algorithm>
10#include <array>
11#include <cctype>
12#include <fstream>
13#include <string>
14#include <thread>
15#include <unordered_map>
16
17namespace ggml::cpu::riscv64_spacemit {
18bool spine_core_info::get_spine_core_info(std::vector<spine_core_info> & result) {
19    static std::unordered_map<uint64_t, spine_core_arch_id> spine_march_mapping_ = {
20        {0x8000000058000001,  spine_core_arch_id::core_arch_x60 },
21        { 0x8000000041000001, spine_core_arch_id::core_arch_a60 },
22        { 0x8000000058000002, spine_core_arch_id::core_arch_x100},
23        { 0x8000000041000002, spine_core_arch_id::core_arch_a100},
24    };
25
26    result.clear();
27    std::ifstream file("/proc/cpuinfo");
28    std::string   line;
29
30    std::vector<std::array<uint64_t, 2>> cpu_info_list;
31
32    uint64_t current_processor = spine_invalid_core_id;
33    uint64_t current_marchid   = 0;
34    bool     has_processor     = false;
35    bool     has_marchid       = false;
36
37    if (!file.is_open()) {
38        return false;
39    }
40
41    while (std::getline(file, line)) {
42        if (line.substr(0, 9) == "processor") {
43            if (has_processor && has_marchid) {
44                cpu_info_list.push_back({ current_processor, current_marchid });
45            }
46
47            size_t colon_pos = line.find(':');
48            if (colon_pos != std::string::npos) {
49                current_processor = std::stoi(line.substr(colon_pos + 1));
50                has_processor     = true;
51            }
52
53            has_marchid = false;
54        } else if (line.substr(0, 7) == "marchid") {
55            size_t colon_pos = line.find(':');
56            if (colon_pos != std::string::npos) {
57                std::string marchid_str = line.substr(colon_pos + 1);
58                marchid_str.erase(std::remove_if(marchid_str.begin(), marchid_str.end(), isspace), marchid_str.end());
59                current_marchid = std::stoull(marchid_str, nullptr, 16);
60                has_marchid     = true;
61            }
62        }
63    }
64
65    if (has_processor && has_marchid) {
66        cpu_info_list.push_back({ current_processor, current_marchid });
67    }
68
69    if (has_processor && has_marchid) {
70        for (auto & cpu_info : cpu_info_list) {
71            if (cpu_info[0] != spine_invalid_core_id &&
72                spine_march_mapping_.find(cpu_info[1]) != spine_march_mapping_.end()) {
73                auto core_info    = spine_core_info();
74                core_info.core_id = cpu_info[0];
75                core_info.arch_id = spine_core_arch_id(spine_march_mapping_[cpu_info[1]]);
76
77                result.push_back(core_info);
78            }
79        }
80    }
81
82    return has_processor && has_marchid;
83}
84
85namespace {
86uint16_t hex_string_to_u16(const std::string & hex_str) {
87    try {
88        size_t pos = 0;
89        if (hex_str.substr(0, 2) == "0x" || hex_str.substr(0, 2) == "0X") {
90            pos = 2;
91        }
92        unsigned long result = std::stoul(hex_str.substr(pos), nullptr, 16);
93        if (result > std::numeric_limits<uint16_t>::max()) {
94            throw std::out_of_range("Converted value is out of range for uint16_t");
95        }
96        return static_cast<uint16_t>(result);
97    } catch (const std::invalid_argument & e) {
98        throw std::invalid_argument("Invalid hexadecimal string");
99    } catch (const std::out_of_range & e) {
100        throw;
101    }
102}
103
104const char * spine_mem_pool_backend_to_string(spine_mem_pool_backend backend) {
105    switch (backend) {
106        case spine_mem_pool_backend::none:
107            return "NONE";
108        case spine_mem_pool_backend::posix_memalign:
109            return "POSIX";
110        case spine_mem_pool_backend::transparent_hugepage:
111            return "HPAGE";
112        case spine_mem_pool_backend::hugetlb_1g:
113            return "HPAGE1GB";
114    }
115
116    return "unknown";
117}
118
119spine_mem_pool_backend parse_mem_backend(const char * mem_backend_str) {
120    if (mem_backend_str == nullptr || mem_backend_str[0] == '\0') {
121        return spine_mem_pool_backend::transparent_hugepage;
122    }
123
124    std::string value(mem_backend_str);
125    std::transform(value.begin(), value.end(), value.begin(),
126                   [](unsigned char ch) { return static_cast<char>(std::tolower(ch)); });
127
128    if (value == "none") {
129        return spine_mem_pool_backend::none;
130    }
131
132    if (value == "posix") {
133        return spine_mem_pool_backend::posix_memalign;
134    }
135
136    if (value == "hpage") {
137        return spine_mem_pool_backend::transparent_hugepage;
138    }
139
140    if (value == "hpage1gb") {
141        return spine_mem_pool_backend::hugetlb_1g;
142    }
143
144    throw std::runtime_error("invalid SPACEMIT_MEM_BACKEND: " + value + ", expected NONE, POSIX, HPAGE or HPAGE1GB");
145}
146}  // namespace
147
148spine_env_info::spine_env_info() {
149    num_cores = static_cast<int>(std::thread::hardware_concurrency());
150    spine_core_info::get_spine_core_info(core_info_list);
151
152    // special for x60 K1
153    if (core_info_list.size() == 8 && core_info_list[0].arch_id == spine_core_arch_id::core_arch_x60) {
154        for (int i = 0; i < 4; i++) {
155            core_info_list[i].arch_id = spine_core_arch_id::core_arch_a60;
156        }
157    }
158
159    // special for qemu
160    if (core_info_list.size() == 0) {
161        char * spine_core_arch_str = getenv("SPACEMIT_CORE_ARCH");
162        if (spine_core_arch_str != nullptr) {
163            auto arch_id = hex_string_to_u16(spine_core_arch_str);
164            for (int i = 0; i < num_cores; i++) {
165                auto core_info    = spine_core_info();
166                core_info.core_id = i;
167                core_info.arch_id = spine_core_arch_id{ arch_id };
168                core_info_list.push_back(core_info);
169            }
170        }
171    }
172
173    if (core_info_list.size() == 0) {
174        throw std::runtime_error(
175            "Failed to get SPACEMIT_CORE_ARCH from environment or failed to parse it from /proc/cpuinfo");
176    }
177
178    char * spine_perfer_core_arch_str = getenv("SPACEMIT_PERFER_CORE_ARCH");
179    if (spine_perfer_core_arch_str != nullptr && spine_perfer_core_arch_str != "") {
180        perfer_core_arch_id = spine_core_arch_id{ hex_string_to_u16(spine_perfer_core_arch_str) };
181    }
182
183    char *           spine_perfer_core_id_str = getenv("SPACEMIT_PERFER_CORE_ID");
184    std::vector<int> perfer_core_id_vec;
185    if (spine_perfer_core_id_str != nullptr && spine_perfer_core_id_str != "") {
186        std::string perfer_core_id_str(spine_perfer_core_id_str);
187        size_t      start = 0;
188        size_t      end   = 0;
189        while ((end = perfer_core_id_str.find(',', start)) != std::string::npos) {
190            std::string core_id_substr = perfer_core_id_str.substr(start, end - start);
191            perfer_core_id_vec.push_back(std::stoi(core_id_substr));
192            start = end + 1;
193        }
194        std::string core_id_substr = perfer_core_id_str.substr(start);
195        perfer_core_id_vec.push_back(std::stoi(core_id_substr));
196    }
197
198    perfer_core_ids.reserve(num_cores);
199    if (perfer_core_arch_id == spine_core_arch_id::core_arch_none) {
200        for (auto & core_info : core_info_list) {
201            auto core_arch_id   = core_info.arch_id;
202            auto core_arch_head = (uint16_t) (core_arch_id) >> 12;
203            if (core_arch_head == 0xA) {
204                num_perfer_cores++;
205                perfer_core_arch_id = core_arch_id;
206                cpu_mask |= (1ULL << core_info.core_id);
207                perfer_core_ids.push_back(core_info.core_id);
208            }
209        }
210    } else {
211        for (auto & core_info : core_info_list) {
212            auto core_arch_id = core_info.arch_id;
213            if (core_arch_id == perfer_core_arch_id) {
214                num_perfer_cores++;
215                cpu_mask |= (1ULL << core_info.core_id);
216
217                auto core_arch_head = (uint16_t) (core_arch_id) >> 12;
218                if (core_arch_head == 0xA) {
219                    perfer_core_ids.push_back(core_info.core_id);
220                }
221            }
222        }
223        if (num_perfer_cores == 0) {
224            GGML_ABORT("can not find core with arch id %x for SPACEMIT_PERFER_CORE_ARCH in core info list\n",
225                       (uint16_t) perfer_core_arch_id);
226        }
227    }
228
229    if (perfer_core_id_vec.size() > 0) {
230        perfer_core_ids.clear();
231        cpu_mask         = 0;
232        num_perfer_cores = 0;
233        for (int core_id : perfer_core_id_vec) {
234            if (core_id < 0 || core_id >= num_cores) {
235                GGML_ABORT("invalid core id in SPACEMIT_PERFER_CORE_ID: %d, should be between 0 and %d\n", core_id,
236                           num_cores - 1);
237            }
238            auto core_info    = core_info_list[core_id];
239            auto core_arch_id = core_info.arch_id;
240            if (core_arch_id == perfer_core_arch_id) {
241                cpu_mask |= (1ULL << core_id);
242                perfer_core_ids.push_back(core_id);
243            } else {
244                GGML_ABORT(
245                    "core id %d in SPACEMIT_PERFER_CORE_ID has arch id %x which does not match "
246                    "SPACEMIT_PERFER_CORE_ARCH %x\n",
247                    core_id, (uint16_t) core_arch_id, (uint16_t) perfer_core_arch_id);
248            }
249        }
250        std::string perfer_core_id_vec_str;
251        for (int core_id : perfer_core_id_vec) {
252            perfer_core_id_vec_str += std::to_string(core_id) + ",";
253        }
254        perfer_core_id_vec_str.pop_back();
255        GGML_LOG_DEBUG("SPACEMIT_PERFER_CORE_ID is set, perferred core ids: %s\n", perfer_core_id_vec_str.c_str());
256        num_perfer_cores = static_cast<int>(perfer_core_id_vec.size());
257    }
258
259    use_ime1 = perfer_core_arch_id == spine_core_arch_id::core_arch_a60 ||
260               perfer_core_arch_id == spine_core_arch_id::core_arch_x100;
261
262    use_ime2 = perfer_core_arch_id == spine_core_arch_id::core_arch_a100;
263
264    mem_backend                  = parse_mem_backend(getenv("SPACEMIT_MEM_BACKEND"));
265    char * spine_disable_tcm_str = getenv("SPACEMIT_DISABLE_TCM");
266    auto   user_disable_tcm      = spine_disable_tcm_str != nullptr && strcmp(spine_disable_tcm_str, "0") != 0;
267
268    if (!user_disable_tcm) {
269        spine_mem_pool_tcm_info tcm_info;
270        if (spine_mem_pool_tcm_init(&tcm_info)) {
271            use_tcm      = tcm_info.available;
272            tcm_blk_size = tcm_info.blk_size;
273            GGML_LOG_DEBUG("CPU_RISCV64_SPACEMIT: tcm is available, blk_size: %zu, blk_num: %zu, is_fake_tcm: %d\n",
274                           tcm_info.blk_size, tcm_info.blk_num, tcm_info.is_fake_tcm);
275
276            for (auto & core_info : core_info_list) {
277                auto core_arch_head = (uint16_t) (core_info.arch_id) >> 12;
278                if (core_arch_head != 0xA) {
279                    aicpu_id_offset++;
280                } else {
281                    break;
282                }
283            }
284        }
285    }
286
287    GGML_LOG_DEBUG(
288        "CPU_RISCV64_SPACEMIT: num_cores: %d, num_perfer_cores: %d, perfer_core_arch_id: %x, exclude_main_thread: %d, "
289        "use_ime1: %d, use_ime2: %d, mem_backend: %s, cpu_mask: %lx, aicpu_id_offset: %d\n",
290        num_cores, num_perfer_cores, (uint16_t) perfer_core_arch_id, exclude_main_thread, use_ime1, use_ime2,
291        spine_mem_pool_backend_to_string(mem_backend), cpu_mask, aicpu_id_offset);
292
293    const size_t init_barrier_size = sizeof(spine_barrier_t) * spine_init_barrier_count;
294    init_barrier =
295        static_cast<spine_barrier_t *>(spine_mem_pool_shared_mem_alloc(init_barrier_size, alignof(spine_barrier_t)));
296    if (init_barrier != nullptr) {
297        init_barrier_is_shared_mem = true;
298    } else {
299        GGML_LOG_WARN("CPU_RISCV64_SPACEMIT: failed to allocate init_barrier from shared mem, falling back to heap\n",
300                      __func__);
301        init_barrier = new spine_barrier_t[spine_init_barrier_count];
302    }
303
304    spine_barrier_init(init_barrier, spine_init_barrier_count, 2);
305}
306
307spine_env_info::~spine_env_info() {
308    if (init_barrier_is_shared_mem) {
309        spine_mem_pool_shared_mem_free(init_barrier);
310    } else {
311        delete[] init_barrier;
312    }
313
314    init_barrier               = nullptr;
315    init_barrier_is_shared_mem = false;
316}
317
318spine_env_info global_spine_env_info;
319
320}  // namespace ggml::cpu::riscv64_spacemit