| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 20982df commit b68c968
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,6 +16,78 @@ will return in an exception. | |||
| 16 | 16 | ||
| 17 | 17 | ======================================================================= | |
| 18 | 18 | ||
| 19 | + \defgroup unified_func_addbackendlibrary af_add_backend_library | ||
| 20 | + | ||
| 21 | + \brief Adds a new backend library from an arbitrary path on the file system | ||
| 22 | + | ||
| 23 | + This function simply registers a new backend library located anywhere in the | ||
| 24 | + file system, given the path of that library (can be a `.so`, `.dll`, or | ||
| 25 | + `.dylib` file, depending on the operating system being used). | ||
| 26 | + | ||
| 27 | + Once registered, \ref af_set_backend_library() can be called to activate the | ||
| 28 | + backend library in a program. The order in which a library is added determines | ||
| 29 | + the index to be passed in \ref af_set_backend_library() to activate the desired | ||
| 30 | + library. The number of libraries that can be registered and activated is limited | ||
| 31 | + to 7. | ||
| 32 | + | ||
| 33 | + This function, together with \ref af_set_backend_library() can be used to load | ||
| 34 | + different versions of the ArrayFire library at runtime. | ||
| 35 | + | ||
| 36 | + This is a noop when using any one of the standalone CPU, CUDA, or OpenCL | ||
| 37 | + backends. | ||
| 38 | + | ||
| 39 | + The following is an example of how this can be used: | ||
| 40 | + \code | ||
| 41 | + af_add_backend_library("/path/to/custom/1/afcpu.so"); | ||
| 42 | + af_add_backend_library("/path/to/custom/2/afcpu.so"); | ||
| 43 | + | ||
| 44 | + af_set_backend_library(0); // Activates .../1/afcpu.so | ||
| 45 | + af_set_backend_library(1); // Activates .../2/afcpu.so | ||
| 46 | + \endcode | ||
| 47 | + | ||
| 48 | + \ingroup unified_func | ||
| 49 | + \ingroup arrayfire_func | ||
| 50 | + | ||
| 51 | + ======================================================================= | ||
| 52 | + | ||
| 53 | + \defgroup unified_func_setbackendlibrary af_set_backend_library | ||
| 54 | + | ||
| 55 | + \brief Activates an ArrayFire library located in an arbitrary path for use | ||
| 56 | + | ||
| 57 | + This function is used after the ArrayFire library has been registered through | ||
| 58 | + \ref af_add_backend_library(). The index to be passed in must be the order of | ||
| 59 | + when \ref af_add_backend_library() was called for the target library. This is | ||
| 60 | + can be used to load different versions of the ArrayFire library at runtime. | ||
| 61 | + | ||
| 62 | + This is a noop when using any one of the standalone CPU, CUDA, or OpenCL backends. | ||
| 63 | + | ||
| 64 | + The following is an example of how this can be used: | ||
| 65 | + \code | ||
| 66 | + af_add_backend_library("/path/to/custom/1/afcpu.so"); | ||
| 67 | + af_add_backend_library("/path/to/custom/2/afcpu.so"); | ||
| 68 | + | ||
| 69 | + af_set_backend_library(0); // Activates .../1/afcpu.so | ||
| 70 | + af_set_backend_library(1); // Activates .../2/afcpu.so | ||
| 71 | + \endcode | ||
| 72 | + | ||
| 73 | + \ingroup unified_func | ||
| 74 | + \ingroup arrayfire_func | ||
| 75 | + | ||
| 76 | + ======================================================================= | ||
| 77 | + | ||
| 78 | + \defgroup unified_func_checkunifiedbackend af_check_unified_backend | ||
| 79 | + | ||
| 80 | + \brief Returns `true` if the unified backend is used to call ArrayFire functions | ||
| 81 | + | ||
| 82 | + This function returns `true` if the unified backend is being used to call the | ||
| 83 | + ArrayFire functions. If the binary is linked directly to one of the backend | ||
| 84 | + libraries, this function returns `false`. | ||
| 85 | + | ||
| 86 | + \ingroup unified_func | ||
| 87 | + \ingroup arrayfire_func | ||
| 88 | + | ||
| 89 | + ======================================================================= | ||
| 90 | + | ||
| 19 | 91 | \defgroup unified_func_getbackendcount getBackendCount | |
| 20 | 92 | ||
| 21 | 93 | \brief Get the number of backends whose libraries were successfully loaded. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,6 +24,46 @@ extern "C" { | |||
| 24 | 24 | AFAPI af_err af_set_backend(const af_backend bknd); | |
| 25 | 25 | #endif | |
| 26 | 26 | ||
| 27 | + #if AF_API_VERSION >= 39 | ||
| 28 | + /** | ||
| 29 | + Adds a new backend library from an arbitrary path on the file system | ||
| 30 | + | ||
| 31 | + \param[in] lib_path is the path of the custom arrayfire library to | ||
| 32 | + be registered | ||
| 33 | + \returns \ref af_err error code | ||
| 34 | + | ||
| 35 | + \ingroup unified_func_addbackendlibrary | ||
| 36 | + */ | ||
| 37 | + AFAPI af_err af_add_backend_library(const char *lib_path); | ||
| 38 | + #endif | ||
| 39 | + | ||
| 40 | + #if AF_API_VERSION >= 39 | ||
| 41 | + /** | ||
| 42 | + Activates an ArrayFire library located in an arbitrary path for use | ||
| 43 | + | ||
| 44 | + \param[in] lib_idx is the index of a registered custom arrayfire library to | ||
| 45 | + be activated for use. Must match the order of when the library | ||
| 46 | + was registered | ||
| 47 | + \returns \ref af_err error code | ||
| 48 | + | ||
| 49 | + \ingroup unified_func_setbackendlibrary | ||
| 50 | + */ | ||
| 51 | + AFAPI af_err af_set_backend_library(int lib_idx); | ||
| 52 | + #endif | ||
| 53 | + | ||
| 54 | + #if AF_API_VERSION >= 39 | ||
| 55 | + /** | ||
| 56 | + Returns true if the unified backend is used to call ArrayFire functions | ||
| 57 | + | ||
| 58 | + \param[out] result reports whether the application is using the unified | ||
| 59 | + backend or not | ||
| 60 | + \returns \ref af_err error code | ||
| 61 | + | ||
| 62 | + \ingroup unified_func_checkunifiedbackend | ||
| 63 | + */ | ||
| 64 | + AFAPI af_err af_check_unified_backend(bool *result); | ||
| 65 | + #endif | ||
| 66 | + | ||
| 27 | 67 | #if AF_API_VERSION >= 32 | |
| 28 | 68 | /** | |
| 29 | 69 | \param[out] num_backends Number of available backends | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -193,6 +193,48 @@ typedef enum { | |||
| 193 | 193 | , AF_ERR_ARR_BKND_MISMATCH = 503 | |
| 194 | 194 | #endif | |
| 195 | 195 | ||
| 196 | + #if AF_API_VERSION >= 39 | ||
| 197 | + /// | ||
| 198 | + /// No active backend | ||
| 199 | + /// | ||
| 200 | + , AF_ERR_NO_ACTIVE_BKND = 504 | ||
| 201 | + #endif | ||
| 202 | + | ||
| 203 | + #if AF_API_VERSION >= 39 | ||
| 204 | + /// | ||
| 205 | + /// No available devices for this backend | ||
| 206 | + /// | ||
| 207 | + , AF_ERR_BKND_NO_DEVICE = 505 | ||
| 208 | + #endif | ||
| 209 | + | ||
| 210 | + #if AF_API_VERSION >= 39 | ||
| 211 | + /// | ||
| 212 | + /// Target backend library not available | ||
| 213 | + /// | ||
| 214 | + , AF_ERR_NO_TGT_BKND_LIB = 507 | ||
| 215 | + #endif | ||
| 216 | + | ||
| 217 | + #if AF_API_VERSION >= 39 | ||
| 218 | + /// | ||
| 219 | + /// Loaded backend library is invalid | ||
| 220 | + /// | ||
| 221 | + , AF_ERR_BKND_LIB_INVALID = 508 | ||
| 222 | + #endif | ||
| 223 | + | ||
| 224 | + #if AF_API_VERSION >= 39 | ||
| 225 | + /// | ||
| 226 | + /// Backend library list full | ||
| 227 | + /// | ||
| 228 | + , AF_ERR_BKND_LIB_LIST_FULL = 509 | ||
| 229 | + #endif | ||
| 230 | + | ||
| 231 | + #if AF_API_VERSION >= 39 | ||
| 232 | + /// | ||
| 233 | + /// Backend library index out of bounds | ||
| 234 | + /// | ||
| 235 | + , AF_ERR_BKND_LIB_IDX_INVALID = 510 | ||
| 236 | + #endif | ||
| 237 | + | ||
| 196 | 238 | // 900-999 Errors from upstream libraries and runtimes | |
| 197 | 239 | ||
| 198 | 240 | /// | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -59,6 +59,15 @@ af_err af_set_backend(const af_backend bknd) { | |||
| 59 | 59 | return AF_SUCCESS; | |
| 60 | 60 | } | |
| 61 | 61 | ||
| 62 | + af_err af_add_backend_library(const char* lib_path) { return AF_SUCCESS; } | ||
| 63 | + | ||
| 64 | + af_err af_set_backend_library(int lib_idx) { return AF_SUCCESS; } | ||
| 65 | + | ||
| 66 | + af_err af_check_unified_backend(bool* result) { | ||
| 67 | + *result = false; | ||
| 68 | + return AF_SUCCESS; | ||
| 69 | + } | ||
| 70 | + | ||
| 62 | 71 | af_err af_get_backend_count(unsigned* num_backends) { | |
| 63 | 72 | *num_backends = 1; | |
| 64 | 73 | return AF_SUCCESS; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,6 +17,19 @@ af_err af_set_backend(const af_backend bknd) { | |||
| 17 | 17 | return unified::setBackend(bknd); | |
| 18 | 18 | } | |
| 19 | 19 | ||
| 20 | + af_err af_add_backend_library(const char *lib_path) { | ||
| 21 | + return unified::AFSymbolManager::getInstance().addBackendLibrary(lib_path); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + af_err af_set_backend_library(int lib_idx) { | ||
| 25 | + return unified::AFSymbolManager::getInstance().setBackendLibrary(lib_idx); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + af_err af_check_unified_backend(bool *result) { | ||
| 29 | + *result = true; | ||
| 30 | + return AF_SUCCESS; | ||
| 31 | + } | ||
| 32 | + | ||
| 20 | 33 | af_err af_get_backend_count(unsigned *num_backends) { | |
| 21 | 34 | *num_backends = unified::AFSymbolManager::getInstance().getBackendCount(); | |
| 22 | 35 | return AF_SUCCESS; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -179,10 +179,19 @@ LibHandle& getActiveHandle() { | |||
| 179 | 179 | return activeHandle; | |
| 180 | 180 | } | |
| 181 | 181 | ||
| 182 | + LibHandle& getPreviousHandle() { | ||
| 183 | + thread_local LibHandle previousHandle = | ||
| 184 | + AFSymbolManager::getInstance().getDefaultHandle(); | ||
| 185 | + return previousHandle; | ||
| 186 | + } | ||
| 187 | + | ||
| 182 | 188 | AFSymbolManager::AFSymbolManager() | |
| 183 | - : defaultHandle(nullptr) | ||
| 189 | + : bkndHandles{} | ||
| 190 | + , defaultHandle(nullptr) | ||
| 184 | 191 | , numBackends(0) | |
| 192 | + , newCustomHandleIndex(NUM_BACKENDS) | ||
| 185 | 193 | , backendsAvailable(0) | |
| 194 | + , defaultBackend(AF_BACKEND_DEFAULT) | ||
| 186 | 195 | , logger(loggerFactory("unified")) { | |
| 187 | 196 | // In order of priority. | |
| 188 | 197 | static const af_backend order[] = {AF_BACKEND_CUDA, AF_BACKEND_OPENCL, | |
@@ -229,20 +238,87 @@ af_err setBackend(af::Backend bknd) { | |||
| 229 | 238 | auto& instance = AFSymbolManager::getInstance(); | |
| 230 | 239 | if (bknd == AF_BACKEND_DEFAULT) { | |
| 231 | 240 | if (instance.getDefaultHandle()) { | |
| 232 | - getActiveHandle() = instance.getDefaultHandle(); | ||
| 233 | - getActiveBackend() = instance.getDefaultBackend(); | ||
| 241 | + getPreviousHandle() = getActiveHandle(); | ||
| 242 | + getActiveHandle() = instance.getDefaultHandle(); | ||
| 243 | + getActiveBackend() = instance.getDefaultBackend(); | ||
| 234 | 244 | return AF_SUCCESS; | |
| 235 | 245 | } else { | |
| 236 | - UNIFIED_ERROR_LOAD_LIB(); | ||
| 246 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_NO_TGT_BKND_LIB); | ||
| 237 | 247 | } | |
| 238 | 248 | } | |
| 239 | 249 | int idx = bknd >> 1U; // Convert 1, 2, 4 -> 0, 1, 2 | |
| 240 | 250 | if (instance.getHandle(idx)) { | |
| 241 | - getActiveHandle() = instance.getHandle(idx); | ||
| 251 | + getPreviousHandle() = getActiveHandle(); | ||
| 252 | + getActiveHandle() = instance.getHandle(idx); | ||
| 253 | + getActiveBackend() = bknd; | ||
| 254 | + return AF_SUCCESS; | ||
| 255 | + } else { | ||
| 256 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_NO_TGT_BKND_LIB); | ||
| 257 | + } | ||
| 258 | + } | ||
| 259 | + | ||
| 260 | + af_err AFSymbolManager::addBackendLibrary(const char* lib_path) { | ||
| 261 | + if ((newCustomHandleIndex + 1) > MAX_BKND_HANDLES) { | ||
| 262 | + // No more space for an additional handle | ||
| 263 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_BKND_LIB_LIST_FULL); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + string show_flag = getEnvVar("AF_SHOW_LOAD_PATH"); | ||
| 267 | + bool show_load_path = show_flag == "1"; | ||
| 268 | + | ||
| 269 | + typedef af_err (*func)(int*); | ||
| 270 | + LibHandle handle = nullptr; | ||
| 271 | + if ((handle = loadLibrary(lib_path))) { | ||
| 272 | + func count_func = | ||
| 273 | + (func)getFunctionPointer(handle, "af_get_device_count"); | ||
| 274 | + if (count_func) { | ||
| 275 | + int count = 0; | ||
| 276 | + count_func(&count); | ||
| 277 | + AF_TRACE("Device Count: {}.", count); | ||
| 278 | + if (count == 0) { | ||
| 279 | + // No available device for this backend | ||
| 280 | + handle = nullptr; | ||
| 281 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_BKND_NO_DEVICE); | ||
| 282 | + } | ||
| 283 | + } else { | ||
| 284 | + // Loaded library is invalid | ||
| 285 | + handle = nullptr; | ||
| 286 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_BKND_LIB_INVALID); | ||
| 287 | + } | ||
| 288 | + | ||
| 289 | + if (show_load_path) { printf("Using %s\n", lib_path); } | ||
| 290 | + | ||
| 291 | + bkndHandles[newCustomHandleIndex] = handle; | ||
| 292 | + newCustomHandleIndex++; | ||
| 293 | + | ||
| 294 | + return AF_SUCCESS; | ||
| 295 | + } else { | ||
| 296 | + // loadLibrary failed, maybe because path is invalid or another reason | ||
| 297 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_LOAD_LIB); | ||
| 298 | + } | ||
| 299 | + } | ||
| 300 | + | ||
| 301 | + af_err AFSymbolManager::setBackendLibrary(int lib_idx) { | ||
| 302 | + typedef af_err (*func)(af_backend*); | ||
| 303 | + int actual_idx = lib_idx + NUM_BACKENDS; | ||
| 304 | + | ||
| 305 | + if (actual_idx >= MAX_BKND_HANDLES) { | ||
| 306 | + // lib_idx more than the capacity of bkndHandles | ||
| 307 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_BKND_LIB_IDX_INVALID); | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + if (bkndHandles[actual_idx]) { | ||
| 311 | + getPreviousHandle() = getActiveHandle(); | ||
| 312 | + getActiveHandle() = getHandle(actual_idx); | ||
| 313 | + af_backend bknd = (af_backend)0; | ||
| 314 | + func get_backend_func = (func)getFunctionPointer( | ||
| 315 | + getActiveHandle(), "af_get_active_backend"); | ||
| 316 | + if (get_backend_func) { get_backend_func(&bknd); } | ||
| 242 | 317 | getActiveBackend() = bknd; | |
| 243 | 318 | return AF_SUCCESS; | |
| 244 | 319 | } else { | |
| 245 | - UNIFIED_ERROR_LOAD_LIB(); | ||
| 320 | + // lib_idx not pointing to a library yet | ||
| 321 | + UNIFIED_ERROR_LOAD_LIB(AF_ERR_NO_TGT_BKND_LIB); | ||
| 246 | 322 | } | |
| 247 | 323 | } | |
| 248 | 324 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -23,14 +23,15 @@ | |||
| 23 | 23 | ||
| 24 | 24 | namespace unified { | |
| 25 | 25 | ||
| 26 | - const int NUM_BACKENDS = 3; | ||
| 26 | + const int NUM_BACKENDS = 3; | ||
| 27 | + const int MAX_BKND_HANDLES = 10; | ||
| 27 | 28 | ||
| 28 | - #define UNIFIED_ERROR_LOAD_LIB() \ | ||
| 29 | + #define UNIFIED_ERROR_LOAD_LIB(AF_ERR) \ | ||
| 29 | 30 | AF_RETURN_ERROR( \ | |
| 30 | 31 | "Failed to load dynamic library. " \ | |
| 31 | 32 | "See http://www.arrayfire.com/docs/unifiedbackend.htm " \ | |
| 32 | 33 | "for instructions to set up environment for Unified backend.", \ | |
| 33 | - AF_ERR_LOAD_LIB) | ||
| 34 | + AF_ERR) | ||
| 34 | 35 | ||
| 35 | 36 | static inline int backend_index(af::Backend be) { | |
| 36 | 37 | switch (be) { | |
@@ -55,6 +56,9 @@ class AFSymbolManager { | |||
| 55 | 56 | af::Backend getDefaultBackend() { return defaultBackend; } | |
| 56 | 57 | LibHandle getDefaultHandle() { return defaultHandle; } | |
| 57 | 58 | ||
| 59 | + af_err addBackendLibrary(const char* lib_path); | ||
| 60 | + af_err setBackendLibrary(int lib_idx); | ||
| 61 | + | ||
| 58 | 62 | spdlog::logger* getLogger(); | |
| 59 | 63 | LibHandle getHandle(int idx) { return bkndHandles[idx]; } | |
| 60 | 64 | ||
@@ -69,10 +73,11 @@ class AFSymbolManager { | |||
| 69 | 73 | void operator=(AFSymbolManager const&); | |
| 70 | 74 | ||
| 71 | 75 | private: | |
| 72 | - LibHandle bkndHandles[NUM_BACKENDS]{}; | ||
| 76 | + LibHandle bkndHandles[MAX_BKND_HANDLES]{}; | ||
| 73 | 77 | ||
| 74 | 78 | LibHandle defaultHandle; | |
| 75 | 79 | unsigned numBackends; | |
| 80 | + unsigned newCustomHandleIndex; | ||
| 76 | 81 | int backendsAvailable; | |
| 77 | 82 | af_backend defaultBackend; | |
| 78 | 83 | std::shared_ptr<spdlog::logger> logger; | |
@@ -84,6 +89,8 @@ af::Backend& getActiveBackend(); | |||
| 84 | 89 | ||
| 85 | 90 | LibHandle& getActiveHandle(); | |
| 86 | 91 | ||
| 92 | + LibHandle& getPreviousHandle(); | ||
| 93 | + | ||
| 87 | 94 | namespace { | |
| 88 | 95 | bool checkArray(af_backend activeBackend, const af_array a) { | |
| 89 | 96 | // Convert af_array into int to retrieve the backend info. | |
@@ -144,7 +151,8 @@ bool checkArrays(af_backend activeBackend, T a, Args... arg) { | |||
| 144 | 151 | if (unified::getActiveHandle()) { \ | |
| 145 | 152 | thread_local af_func func = (af_func)common::getFunctionPointer( \ | |
| 146 | 153 | unified::getActiveHandle(), __func__); \ | |
| 147 | - if (!func) { \ | ||
| 154 | + if (!func && \ | ||
| 155 | + unified::getActiveHandle() != unified::getPreviousHandle()) { \ | ||
| 148 | 156 | AF_RETURN_ERROR( \ | |
| 149 | 157 | "requested symbol name could not be found in loaded library.", \ | |
| 150 | 158 | AF_ERR_LOAD_LIB); \ | |
@@ -156,8 +164,8 @@ bool checkArrays(af_backend activeBackend, T a, Args... arg) { | |||
| 156 | 164 | } \ | |
| 157 | 165 | return func(__VA_ARGS__); \ | |
| 158 | 166 | } else { \ | |
| 159 | - AF_RETURN_ERROR("ArrayFire couldn't locate any backends.", \ | ||
| 160 | - AF_ERR_LOAD_LIB); \ | ||
| 167 | + AF_RETURN_ERROR("ArrayFire couldn't load active backend", \ | ||
| 168 | + AF_ERR_NO_ACTIVE_BKND); \ | ||
| 161 | 169 | } | |
| 162 | 170 | ||
| 163 | 171 | #define CALL_NO_PARAMS(FUNCTION) CALL(FUNCTION) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments