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
255 lines (218 loc) · 7.71 KB
/
symbol_manager.cpp
File metadata and controls
255 lines (218 loc) · 7.71 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
250
251
252
253
254
255
/*******************************************************
* 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::getFunctionPointer;
using common::loadLibrary;
using common::loggerFactory;
using common::unloadLibrary;
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(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 paths[] = {
"", // Default paths
".", // 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 (size_t i = 0; i < extent<decltype(paths)>::value; i++) {
AF_TRACE("Attempting: {}", paths[i]);
if ((retVal = loadLibrary(join_path(paths[i], bkndLibName).c_str()))) {
AF_TRACE("Found: {}", join_path(paths[i], bkndLibName));
func count_func =
(func)getFunctionPointer(retVal, "af_get_device_count");
if (count_func) {
int count = 0;
count_func(&count);
AF_TRACE("Device Count: {}.", count);
if (count == 0) {
retVal = nullptr;
continue;
}
}
if (show_load_path) { printf("Using %s\n", bkndLibName.c_str()); }
break;
}
}
return retVal;
}
void closeDynLibrary(LibHandle handle) { unloadLibrary(handle); }
AFSymbolManager& AFSymbolManager::getInstance() {
thread_local AFSymbolManager symbolManager;
return symbolManager;
}
spdlog::logger* AFSymbolManager::getLogger() { return logger.get(); }
AFSymbolManager::AFSymbolManager()
: activeHandle(nullptr)
, 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};
// Decremeting loop. The last successful backend loaded will be the most
// prefered one.
for (int i = NUM_BACKENDS - 1; i >= 0; i--) {
int backend = order[i] >> 1; // 2 4 1 -> 1 2 0
bkndHandles[backend] = openDynLibrary(order[i]);
if (bkndHandles[backend]) {
activeHandle = bkndHandles[backend];
activeBackend = (af_backend)order[i];
numBackends++;
backendsAvailable += order[i];
}
}
if (activeBackend) {
AF_TRACE("AF_DEFAULT_BACKEND: {}",
getBackendDirectoryName(activeBackend));
}
// Keep a copy of default order handle inorder to use it in ::setBackend
// when the user passes AF_BACKEND_DEFAULT
defaultHandle = activeHandle;
defaultBackend = activeBackend;
}
AFSymbolManager::~AFSymbolManager() {
for (int i = 0; i < NUM_BACKENDS; ++i) {
if (bkndHandles[i]) { closeDynLibrary(bkndHandles[i]); }
}
}
unsigned AFSymbolManager::getBackendCount() { return numBackends; }
int AFSymbolManager::getAvailableBackends() { return backendsAvailable; }
af_err AFSymbolManager::setBackend(af::Backend bknd) {
if (bknd == AF_BACKEND_DEFAULT) {
if (defaultHandle) {
activeHandle = defaultHandle;
activeBackend = defaultBackend;
return AF_SUCCESS;
} else {
UNIFIED_ERROR_LOAD_LIB();
}
}
int idx = bknd >> 1; // Convert 1, 2, 4 -> 0, 1, 2
if (bkndHandles[idx]) {
activeHandle = bkndHandles[idx];
activeBackend = bknd;
return AF_SUCCESS;
} else {
UNIFIED_ERROR_LOAD_LIB();
}
}
bool checkArray(af_backend activeBackend, af_array a) {
// Convert af_array into int to retrieve the backend info.
// See ArrayInfo.hpp for more
af_backend backend = (af_backend)0;
// This condition is required so that the invalid args tests for unified
// backend return the expected error rather than AF_ERR_ARR_BKND_MISMATCH
// Since a = 0, does not have a backend specified, it should be a
// AF_ERR_ARG instead of AF_ERR_ARR_BKND_MISMATCH
if (a == 0) return true;
unified::AFSymbolManager::getInstance().call("af_get_backend_id", &backend,
a);
return backend == activeBackend;
}
bool checkArrays(af_backend activeBackend) {
UNUSED(activeBackend);
// Dummy
return true;
}
} // namespace unified