forked from arrayfire/arrayfire
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsymbol_manager.cpp
More file actions
249 lines (216 loc) · 7.73 KB
/
symbol_manager.cpp
File metadata and controls
249 lines (216 loc) · 7.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/*******************************************************
* Copyright (c) 2015, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include "symbol_manager.hpp"
#include <af/version.h>
#include <common/Logger.hpp>
#include <common/module_loading.hpp>
#include <spdlog/spdlog.h>
#include <cmath>
#include <functional>
#include <string>
#include <type_traits>
#ifdef OS_WIN
#include <Windows.h>
#else
#include <dlfcn.h>
#endif
using common::getErrorMessage;
using common::getFunctionPointer;
using common::loadLibrary;
using common::loggerFactory;
using std::extent;
using std::function;
using std::string;
namespace unified {
#if defined(OS_WIN)
static const char* LIB_AF_BKND_PREFIX = "";
static const char* LIB_AF_BKND_SUFFIX = ".dll";
#define PATH_SEPARATOR "\\"
#define RTLD_LAZY 0
#else
#if defined(__APPLE__)
#define SO_SUFFIX_HELPER(VER) "." #VER ".dylib"
#else
#define SO_SUFFIX_HELPER(VER) ".so." #VER
#endif
static const char* LIB_AF_BKND_PREFIX = "lib";
#define PATH_SEPARATOR "/"
#define GET_SO_SUFFIX(VER) SO_SUFFIX_HELPER(VER)
static const char* LIB_AF_BKND_SUFFIX = GET_SO_SUFFIX(AF_VERSION_MAJOR);
#endif
string getBkndLibName(const af_backend backend) {
string ret;
switch (backend) {
case AF_BACKEND_CUDA:
ret = string(LIB_AF_BKND_PREFIX) + "afcuda" + LIB_AF_BKND_SUFFIX;
break;
case AF_BACKEND_OPENCL:
ret = string(LIB_AF_BKND_PREFIX) + "afopencl" + LIB_AF_BKND_SUFFIX;
break;
case AF_BACKEND_CPU:
ret = string(LIB_AF_BKND_PREFIX) + "afcpu" + LIB_AF_BKND_SUFFIX;
break;
default: assert(1 != 1 && "Invalid backend");
}
return ret;
}
string getBackendDirectoryName(const af_backend backend) {
string ret;
switch (backend) {
case AF_BACKEND_CUDA: ret = "cuda"; break;
case AF_BACKEND_OPENCL: ret = "opencl"; break;
case AF_BACKEND_CPU: ret = "cpu"; break;
default: assert(1 != 1 && "Invalid backend");
}
return ret;
}
string join_path(string first) { return first; }
template<typename... ARGS>
string join_path(const string& first, ARGS... args) {
if (first.empty()) {
return join_path(args...);
} else {
return first + PATH_SEPARATOR + join_path(args...);
}
}
/*flag parameter is not used on windows platform */
LibHandle openDynLibrary(const af_backend bknd_idx) {
// The default search path is the colon separated list of paths stored in
// the environment variables:
string bkndLibName = getBkndLibName(bknd_idx);
string show_flag = getEnvVar("AF_SHOW_LOAD_PATH");
bool show_load_path = show_flag == "1";
// FIXME(umar): avoid this if at all possible
auto getLogger = [&] { return spdlog::get("unified"); };
string pathPrefixes[] = {
"", // empty prefix i.e. just the library name will enable search in
// system default paths such as LD_LIBRARY_PATH, Program
// Files(Windows) etc.
".", // Shared libraries in current directory
// Running from the CMake Build directory
join_path(".", "src", "backend", getBackendDirectoryName(bknd_idx)),
// Running from the test directory
join_path("..", "src", "backend", getBackendDirectoryName(bknd_idx)),
// Environment variable PATHS
join_path(getEnvVar("AF_BUILD_PATH"), "src", "backend",
getBackendDirectoryName(bknd_idx)),
join_path(getEnvVar("AF_PATH"), "lib"),
join_path(getEnvVar("AF_PATH"), "lib64"),
getEnvVar("AF_BUILD_LIB_CUSTOM_PATH"),
// Common install paths
#if !defined(OS_WIN)
"/opt/arrayfire-3/lib/",
"/opt/arrayfire/lib/",
"/usr/local/lib/",
"/usr/local/arrayfire/lib/"
#else
join_path(getEnvVar("ProgramFiles"), "ArrayFire", "lib"),
join_path(getEnvVar("ProgramFiles"), "ArrayFire", "v3", "lib")
#endif
};
typedef af_err (*func)(int*);
LibHandle retVal = nullptr;
for (auto& pathPrefixe : pathPrefixes) {
AF_TRACE("Attempting: {}",
(pathPrefixe.empty() ? "Default System Paths" : pathPrefixe));
if ((retVal =
loadLibrary(join_path(pathPrefixe, bkndLibName).c_str()))) {
AF_TRACE("Found: {}", join_path(pathPrefixe, bkndLibName));
func count_func = reinterpret_cast<func>(
getFunctionPointer(retVal, "af_get_device_count"));
if (count_func) {
int count = 0;
count_func(&count);
AF_TRACE("Device Count: {}.", count);
if (count == 0) {
AF_TRACE("Skipping: No devices found for {}", bkndLibName);
retVal = nullptr;
continue;
}
}
if (show_load_path) { printf("Using %s\n", bkndLibName.c_str()); }
break;
} else {
AF_TRACE("Failed to load {}", getErrorMessage());
}
}
return retVal;
}
spdlog::logger* AFSymbolManager::getLogger() { return logger.get(); }
af::Backend& getActiveBackend() {
thread_local af_backend activeBackend =
AFSymbolManager::getInstance().getDefaultBackend();
return activeBackend;
}
LibHandle& getActiveHandle() {
thread_local LibHandle activeHandle =
AFSymbolManager::getInstance().getDefaultHandle();
return activeHandle;
}
AFSymbolManager::AFSymbolManager()
: defaultHandle(nullptr)
, numBackends(0)
, backendsAvailable(0)
, logger(loggerFactory("unified")) {
// In order of priority.
static const af_backend order[] = {AF_BACKEND_CUDA, AF_BACKEND_OPENCL,
AF_BACKEND_CPU};
LibHandle handle = nullptr;
af::Backend backend = AF_BACKEND_DEFAULT;
// Decremeting loop. The last successful backend loaded will be the most
// prefered one.
for (int i = NUM_BACKENDS - 1; i >= 0; i--) {
int backend_index = order[i] >> 1U; // 2 4 1 -> 1 2 0
bkndHandles[backend_index] = openDynLibrary(order[i]);
if (bkndHandles[backend_index]) {
handle = bkndHandles[backend_index];
backend = order[i];
numBackends++;
backendsAvailable += order[i];
}
}
if (backend) {
AF_TRACE("AF_DEFAULT_BACKEND: {}", getBackendDirectoryName(backend));
defaultBackend = backend;
} else {
logger->error("Backend was not found");
defaultBackend = AF_BACKEND_DEFAULT;
}
// Keep a copy of default order handle inorder to use it in ::setBackend
// when the user passes AF_BACKEND_DEFAULT
defaultHandle = handle;
}
AFSymbolManager::~AFSymbolManager() {
for (auto& bkndHandle : bkndHandles) {
if (bkndHandle) { common::unloadLibrary(bkndHandle); }
}
}
unsigned AFSymbolManager::getBackendCount() const { return numBackends; }
int AFSymbolManager::getAvailableBackends() const { return backendsAvailable; }
af_err setBackend(af::Backend bknd) {
auto& instance = AFSymbolManager::getInstance();
if (bknd == AF_BACKEND_DEFAULT) {
if (instance.getDefaultHandle()) {
getActiveHandle() = instance.getDefaultHandle();
getActiveBackend() = instance.getDefaultBackend();
return AF_SUCCESS;
} else {
UNIFIED_ERROR_LOAD_LIB();
}
}
int idx = bknd >> 1U; // Convert 1, 2, 4 -> 0, 1, 2
if (instance.getHandle(idx)) {
getActiveHandle() = instance.getHandle(idx);
getActiveBackend() = bknd;
return AF_SUCCESS;
} else {
UNIFIED_ERROR_LOAD_LIB();
}
}
} // namespace unified