Skip to content

Commit ccd8df8

Browse files
committed
add ggml_backend_unload
1 parent d5a3beb commit ccd8df8

File tree

2 files changed

+62
-27
lines changed

2 files changed

+62
-27
lines changed

ggml/include/ggml-backend.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,10 @@ extern "C" {
222222
// = ggml_backend_dev_init(ggml_backend_dev_by_type(GPU) OR ggml_backend_dev_by_type(CPU), NULL)
223223
GGML_API ggml_backend_t ggml_backend_init_best(void);
224224

225-
// Load a backend from a dynamic library
225+
// Load a backend from a dynamic library and register it
226226
GGML_API ggml_backend_reg_t ggml_backend_load(const char * path);
227+
// Unload a backend if loaded dynamically and unregister it
228+
GGML_API void ggml_backend_unload(ggml_backend_reg_t reg);
227229
// Load all known backends from dynamic libraries
228230
GGML_API void ggml_backend_load_all(void);
229231

ggml/src/ggml-backend-reg.cpp

+59-26
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "ggml-backend-impl.h"
22
#include "ggml-backend.h"
33
#include "ggml-impl.h"
4+
#include <algorithm>
45
#include <cstring>
56
#include <vector>
67

@@ -45,8 +46,13 @@
4546
#include "ggml-kompute.h"
4647
#endif
4748

49+
struct ggml_backend_reg_entry {
50+
ggml_backend_reg_t reg;
51+
void * handle;
52+
};
53+
4854
struct ggml_backend_registry {
49-
std::vector<ggml_backend_reg_t> backends;
55+
std::vector<ggml_backend_reg_entry> backends;
5056
std::vector<ggml_backend_dev_t> devices;
5157

5258
ggml_backend_registry() {
@@ -82,7 +88,13 @@ struct ggml_backend_registry {
8288
#endif
8389
}
8490

85-
void register_backend(ggml_backend_reg_t reg) {
91+
~ggml_backend_registry() {
92+
while (!backends.empty()) {
93+
ggml_backend_unload(backends.back().reg);
94+
}
95+
}
96+
97+
void register_backend(ggml_backend_reg_t reg, void * handle = nullptr) {
8698
if (!reg) {
8799
return;
88100
}
@@ -91,7 +103,7 @@ struct ggml_backend_registry {
91103
GGML_LOG_DEBUG("%s: registered backend %s (%zu devices)\n",
92104
__func__, ggml_backend_reg_name(reg), ggml_backend_reg_dev_count(reg));
93105
#endif
94-
backends.push_back(reg);
106+
backends.push_back({ reg, handle });
95107
for (size_t i = 0; i < ggml_backend_reg_dev_count(reg); i++) {
96108
register_device(ggml_backend_reg_dev_get(reg, i));
97109
}
@@ -126,7 +138,7 @@ size_t ggml_backend_reg_count() {
126138

127139
ggml_backend_reg_t ggml_backend_reg_get(size_t index) {
128140
GGML_ASSERT(index < ggml_backend_reg_count());
129-
return get_reg().backends[index];
141+
return get_reg().backends[index].reg;
130142
}
131143

132144
ggml_backend_reg_t ggml_backend_reg_by_name(const char * name) {
@@ -136,7 +148,7 @@ ggml_backend_reg_t ggml_backend_reg_by_name(const char * name) {
136148
return reg;
137149
}
138150
}
139-
return NULL;
151+
return nullptr;
140152
}
141153

142154
// Device enumeration
@@ -156,7 +168,7 @@ ggml_backend_dev_t ggml_backend_dev_by_name(const char * name) {
156168
return dev;
157169
}
158170
}
159-
return NULL;
171+
return nullptr;
160172
}
161173

162174
ggml_backend_dev_t ggml_backend_dev_by_type(enum ggml_backend_dev_type type) {
@@ -166,22 +178,22 @@ ggml_backend_dev_t ggml_backend_dev_by_type(enum ggml_backend_dev_type type) {
166178
return dev;
167179
}
168180
}
169-
return NULL;
181+
return nullptr;
170182
}
171183

172184
// Convenience functions
173185
ggml_backend_t ggml_backend_init_by_name(const char * name, const char * params) {
174186
ggml_backend_dev_t dev = ggml_backend_dev_by_name(name);
175187
if (!dev) {
176-
return NULL;
188+
return nullptr;
177189
}
178190
return ggml_backend_dev_init(dev, params);
179191
}
180192

181193
ggml_backend_t ggml_backend_init_by_type(enum ggml_backend_dev_type type, const char * params) {
182194
ggml_backend_dev_t dev = ggml_backend_dev_by_type(type);
183195
if (!dev) {
184-
return NULL;
196+
return nullptr;
185197
}
186198
return ggml_backend_dev_init(dev, params);
187199
}
@@ -192,9 +204,9 @@ ggml_backend_t ggml_backend_init_best(void) {
192204
dev = ggml_backend_dev_by_type(GGML_BACKEND_DEVICE_TYPE_CPU);
193205
}
194206
if (!dev) {
195-
return NULL;
207+
return nullptr;
196208
}
197-
return ggml_backend_dev_init(dev, NULL);
209+
return ggml_backend_dev_init(dev, nullptr);
198210
}
199211

200212
#ifdef _WIN32
@@ -214,45 +226,66 @@ ggml_backend_reg_t ggml_backend_load(const char * path) {
214226
HMODULE handle = LoadLibraryA(path);
215227
if (!handle) {
216228
GGML_LOG_ERROR("%s: failed to load %s: %lu\n", __func__, path, GetLastError());
217-
return NULL;
229+
return nullptr;
218230
}
219231
ggml_backend_init_t backend_init = (ggml_backend_init_t) GetProcAddress(handle, "ggml_backend_init");
220232
if (!backend_init) {
221233
GGML_LOG_ERROR("%s: failed to find ggml_backend_init in %s: %lu\n", __func__, path, GetLastError());
222234
FreeLibrary(handle);
223-
return NULL;
224-
}
225-
ggml_backend_reg_t reg = backend_init();
226-
if (!reg) {
227-
GGML_LOG_ERROR("%s: failed to initialize backend from %s\n", __func__, path);
228-
FreeLibrary(handle);
229-
return NULL;
235+
return nullptr;
230236
}
231-
GGML_LOG_DEBUG("%s: loaded %s backend from %s\n", __func__, ggml_backend_reg_name(reg), path);
232-
ggml_backend_register(reg);
233-
return reg;
234237
#else
235238
void * handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
236239
if (!handle) {
237240
GGML_LOG_ERROR("%s: failed to load %s: %s\n", __func__, path, dlerror());
238-
return NULL;
241+
return nullptr;
239242
}
240243
auto * backend_init = (ggml_backend_init_t) dlsym(handle, "ggml_backend_init");
241244
if (!backend_init) {
242245
GGML_LOG_ERROR("%s: failed to find ggml_backend_init in %s: %s\n", __func__, path, dlerror());
243246
dlclose(handle);
244-
return NULL;
247+
return nullptr;
245248
}
249+
#endif
246250
ggml_backend_reg_t reg = backend_init();
247251
if (!reg) {
248252
GGML_LOG_ERROR("%s: failed to initialize backend from %s\n", __func__, path);
249253
dlclose(handle);
250-
return NULL;
254+
return nullptr;
251255
}
252256
GGML_LOG_DEBUG("%s: loaded %s backend from %s\n", __func__, ggml_backend_reg_name(reg), path);
253-
ggml_backend_register(reg);
257+
get_reg().register_backend(reg, handle);
254258
return reg;
259+
}
260+
261+
void ggml_backend_unload(ggml_backend_reg_t reg) {
262+
auto it = std::find_if(get_reg().backends.begin(), get_reg().backends.end(),
263+
[reg](ggml_backend_reg_entry entry) { return entry.reg == reg; });
264+
265+
if (it == get_reg().backends.end()) {
266+
GGML_LOG_ERROR("%s: backend not found\n", __func__);
267+
return;
268+
}
269+
270+
GGML_LOG_DEBUG("%s: unloading %s backend\n", __func__, ggml_backend_reg_name(reg));
271+
272+
// remove devices
273+
get_reg().devices.erase(
274+
std::remove_if(get_reg().devices.begin(), get_reg().devices.end(),
275+
[reg](ggml_backend_dev_t dev) { return ggml_backend_dev_backend_reg(dev) == reg; }),
276+
get_reg().devices.end());
277+
278+
// unload library
279+
if (it->handle) {
280+
#ifdef _WIN32
281+
FreeLibrary((HMODULE) it->handle);
282+
#else
283+
dlclose(it->handle);
255284
#endif
285+
}
286+
287+
// remove backend
288+
get_reg().backends.erase(it);
256289
}
257290

258291
void ggml_backend_load_all() {

0 commit comments

Comments
 (0)