22#ifdef VIENNALS_GPU_BICGSTAB
42using LibraryHandle = HMODULE;
43inline LibraryHandle openLibrary(
const char *path) {
44 return LoadLibraryA(path);
46inline void *findSymbol(LibraryHandle lib,
const char *name) {
47 return reinterpret_cast<void *
>(GetProcAddress(lib, name));
49inline std::string lastLoadError() {
50 return "LoadLibrary failed (error " + std::to_string(GetLastError()) +
")";
52inline const char *gpuLibraryName() {
return "ViennaLS_GPU.dll"; }
53inline char pathSeparator() {
return '\\'; }
55using LibraryHandle =
void *;
56inline LibraryHandle openLibrary(
const char *path) {
57 return dlopen(path, RTLD_NOW | RTLD_LOCAL);
59inline void *findSymbol(LibraryHandle lib,
const char *name) {
60 return dlsym(lib, name);
62inline std::string lastLoadError() {
63 const char *err = dlerror();
64 return err ? std::string(err) : std::string(
"unknown dynamic loader error");
66inline const char *gpuLibraryName() {
return "libViennaLS_GPU.so"; }
67inline char pathSeparator() {
return '/'; }
72inline std::string currentModuleDirectory() {
75 HMODULE module =
nullptr;
76 if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
77 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
78 reinterpret_cast<LPCSTR
>(¤tModuleDirectory),
81 char buffer[MAX_PATH] = {};
82 if (GetModuleFileNameA(module, buffer, MAX_PATH))
87 if (dladdr(
reinterpret_cast<const void *
>(¤tModuleDirectory), &info) &&
89 path = info.dli_fname;
91 const auto pos = path.find_last_of(pathSeparator());
92 return pos == std::string::npos ? std::string() : path.substr(0, pos);
99 bool available =
false;
102 int (*abiVersion)(void) =
nullptr;
103 const char *(*lastErrorMessage)(void) =
nullptr;
104 int (*diffusionSolve)(int64_t,
const int64_t *,
const int64_t *,
105 const double *,
const double *,
double *, unsigned,
106 double,
unsigned *) =
nullptr;
107 void *(*macSetup)(int64_t,
const int64_t *,
const int64_t *,
const double *,
108 int64_t, int,
const double *) =
nullptr;
109 int (*macSolve)(
void *, int64_t,
const int64_t *,
const int64_t *,
110 const double *,
const double *,
double *, unsigned, double,
111 unsigned *,
double *) =
nullptr;
112 void (*macFree)(
void *) =
nullptr;
114 GpuRuntime() { load(); }
119 std::string candidates[5];
121 if (
const char *
override = std::getenv(
"VIENNALS_GPU_LIBRARY"))
122 candidates[count++] =
override;
123 const std::string moduleDir = currentModuleDirectory();
124 if (!moduleDir.empty()) {
127 candidates[count++] = moduleDir + pathSeparator() + gpuLibraryName();
128 candidates[count++] = moduleDir + pathSeparator() +
".." +
129 pathSeparator() +
"viennals.libs" +
130 pathSeparator() + gpuLibraryName();
131 candidates[count++] = moduleDir + pathSeparator() +
".." +
132 pathSeparator() +
"lib" + pathSeparator() +
135 candidates[count++] = gpuLibraryName();
137 LibraryHandle lib =
nullptr;
138 std::string attempts;
139 for (
int i = 0; i < count && !lib; ++i) {
140 lib = openLibrary(candidates[i].c_str());
148 attempts +=
"\n " + candidates[i] +
": " + lastLoadError();
153 status =
"ViennaLS_GPU could not be loaded, so the GPU solver is "
154 "unavailable; using the CPU solver instead. Attempts:" +
159 if (!resolveAll(lib)) {
160 status =
"ViennaLS_GPU is missing expected entry points; it is probably "
161 "from a different ViennaLS version. Using the CPU solver "
167 status =
"ViennaLS_GPU reports ABI version " +
168 std::to_string(abiVersion()) +
" but ViennaLS expects " +
170 ". Using the CPU solver instead.";
175 status =
"ViennaLS_GPU loaded.";
180 bool resolveAll(LibraryHandle lib) {
181 return resolve(lib,
"viennalsGpuAbiVersion", abiVersion) &&
182 resolve(lib,
"viennalsGpuGetLastErrorMessage", lastErrorMessage) &&
183 resolve(lib,
"viennalsGpuDiffusionSolve", diffusionSolve) &&
184 resolve(lib,
"viennalsGpuMacSetup", macSetup) &&
185 resolve(lib,
"viennalsGpuMacSolve", macSolve) &&
186 resolve(lib,
"viennalsGpuMacFree", macFree);
190 static bool resolve(LibraryHandle lib,
const char *name, Fn &target) {
191 target =
reinterpret_cast<Fn
>(findSymbol(lib, name));
192 return target !=
nullptr;
199inline const GpuRuntime &runtime() {
200 static GpuRuntime instance;
208inline bool gpuRuntimeAvailable() {
return detail::runtime().available; }
211inline const char *gpuRuntimeStatusMessage() {
212 return detail::runtime().status.c_str();
217inline const char *gpuGetLastErrorMessage() {
218 const auto &rt = detail::runtime();
219 return rt.available ? rt.lastErrorMessage() : rt.status.c_str();
225inline int gpuDiffusionSolve(std::int64_t n,
const std::int64_t *ptr,
226 const std::int64_t *col,
const double *val,
227 const double *rhs,
double *x,
228 unsigned maxIterations,
double absTolerance,
229 unsigned &outIterations) {
230 const auto &rt = detail::runtime();
233 return rt.diffusionSolve(n, ptr, col, val, rhs, x, maxIterations,
234 absTolerance, &outIterations);
240inline void *gpuMacSetup(std::int64_t n,
const std::int64_t *ptr,
241 const std::int64_t *col,
const double *val,
242 std::int64_t nvel,
int dim,
const double *nullspace) {
243 const auto &rt = detail::runtime();
244 return rt.available ? rt.macSetup(n, ptr, col, val, nvel, dim, nullspace)
251inline bool gpuMacSolve(
void *handle, std::int64_t n,
const std::int64_t *ptr,
252 const std::int64_t *col,
const double *val,
253 const double *rhs,
double *x,
unsigned maxIterations,
254 double tolerance,
unsigned &outIterations,
255 double &outResidual) {
256 const auto &rt = detail::runtime();
257 return rt.available &&
258 rt.macSolve(handle, n, ptr, col, val, rhs, x, maxIterations, tolerance,
259 &outIterations, &outResidual) != 0;
263inline void gpuMacFree(
void *handle) {
264 const auto &rt = detail::runtime();
#define VIENNALS_GPU_ABI_VERSION
Definition lsOxidationGpuAbi.hpp:22
Definition lsAdvect.hpp:41