26#ifdef VIENNALS_GPU_BICGSTAB
46static constexpr uint32_t kNoNode = 0xFFFFFFFFu;
50struct GpuBiCGSTABBuffers;
55using LibraryHandle = HMODULE;
56inline LibraryHandle openLibrary(
const char *path) {
57 return LoadLibraryA(path);
59inline void *findSymbol(LibraryHandle lib,
const char *name) {
60 return reinterpret_cast<void *
>(GetProcAddress(lib, name));
62inline std::string lastLoadError() {
63 return "LoadLibrary failed (error " + std::to_string(GetLastError()) +
")";
65inline const char *gpuLibraryName() {
return "ViennaLS_GPU.dll"; }
66inline char pathSeparator() {
return '\\'; }
68using LibraryHandle =
void *;
69inline LibraryHandle openLibrary(
const char *path) {
70 return dlopen(path, RTLD_NOW | RTLD_LOCAL);
72inline void *findSymbol(LibraryHandle lib,
const char *name) {
73 return dlsym(lib, name);
75inline std::string lastLoadError() {
76 const char *err = dlerror();
77 return err ? std::string(err) : std::string(
"unknown dynamic loader error");
79inline const char *gpuLibraryName() {
return "libViennaLS_GPU.so"; }
80inline char pathSeparator() {
return '/'; }
85inline std::string currentModuleDirectory() {
88 HMODULE module =
nullptr;
89 if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
90 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
91 reinterpret_cast<LPCSTR
>(¤tModuleDirectory),
94 char buffer[MAX_PATH] = {};
95 if (GetModuleFileNameA(module, buffer, MAX_PATH))
100 if (dladdr(
reinterpret_cast<const void *
>(¤tModuleDirectory), &info) &&
102 path = info.dli_fname;
104 const auto pos = path.find_last_of(pathSeparator());
105 return pos == std::string::npos ? std::string() : path.substr(0, pos);
112 bool available =
false;
115 int (*abiVersion)(void) =
nullptr;
116 void *(*allocBuffers)(uint32_t, int, int) =
nullptr;
117 void (*freeBuffers)(
void *) =
nullptr;
118 int (*isValid)(
const void *) =
nullptr;
119 const char *(*lastErrorMessage)(void) =
nullptr;
120 int (*uploadNeighborIds)(
void *,
const uint32_t *, std::size_t) =
nullptr;
121 int (*setupCSR)(
void *,
const uint32_t *, uint32_t, int) =
nullptr;
122 int (*uploadSolverArrays)(
void *,
const double *,
const double *,
123 const double *, uint32_t, std::size_t) =
nullptr;
124 int (*uploadRhs)(
void *,
const double *, uint32_t) =
nullptr;
125 int (*solveBiCGSTAB)(
void *,
double *, double, unsigned, double,
unsigned *,
128 GpuRuntime() { load(); }
133 std::string candidates[5];
135 if (
const char *
override = std::getenv(
"VIENNALS_GPU_LIBRARY"))
136 candidates[count++] =
override;
137 const std::string moduleDir = currentModuleDirectory();
138 if (!moduleDir.empty()) {
141 candidates[count++] = moduleDir + pathSeparator() + gpuLibraryName();
142 candidates[count++] = moduleDir + pathSeparator() +
".." +
143 pathSeparator() +
"viennals.libs" +
144 pathSeparator() + gpuLibraryName();
145 candidates[count++] = moduleDir + pathSeparator() +
".." +
146 pathSeparator() +
"lib" + pathSeparator() +
149 candidates[count++] = gpuLibraryName();
151 LibraryHandle lib =
nullptr;
152 std::string attempts;
153 for (
int i = 0; i < count && !lib; ++i) {
154 lib = openLibrary(candidates[i].c_str());
162 attempts +=
"\n " + candidates[i] +
": " + lastLoadError();
167 status =
"ViennaLS_GPU could not be loaded, so the GPU solver is "
168 "unavailable; using the CPU solver instead. Attempts:" +
173 if (!resolveAll(lib)) {
174 status =
"ViennaLS_GPU is missing expected entry points; it is probably "
175 "from a different ViennaLS version. Using the CPU solver "
181 status =
"ViennaLS_GPU reports ABI version " +
182 std::to_string(abiVersion()) +
" but ViennaLS expects " +
184 ". Using the CPU solver instead.";
189 status =
"ViennaLS_GPU loaded.";
194 bool resolveAll(LibraryHandle lib) {
195 return resolve(lib,
"viennalsGpuAbiVersion", abiVersion) &&
196 resolve(lib,
"viennalsGpuAllocBuffers", allocBuffers) &&
197 resolve(lib,
"viennalsGpuFreeBuffers", freeBuffers) &&
198 resolve(lib,
"viennalsGpuIsValid", isValid) &&
199 resolve(lib,
"viennalsGpuGetLastErrorMessage", lastErrorMessage) &&
200 resolve(lib,
"viennalsGpuUploadNeighborIds", uploadNeighborIds) &&
201 resolve(lib,
"viennalsGpuSetupCSR", setupCSR) &&
202 resolve(lib,
"viennalsGpuUploadSolverArrays", uploadSolverArrays) &&
203 resolve(lib,
"viennalsGpuUploadRhs", uploadRhs) &&
204 resolve(lib,
"viennalsGpuSolveBiCGSTAB", solveBiCGSTAB);
208 static bool resolve(LibraryHandle lib,
const char *name, Fn &target) {
209 target =
reinterpret_cast<Fn
>(findSymbol(lib, name));
210 return target !=
nullptr;
217inline const GpuRuntime &runtime() {
218 static GpuRuntime instance;
222inline void *toHandle(GpuBiCGSTABBuffers *gpu) {
223 return reinterpret_cast<void *
>(gpu);
225inline const void *toHandle(
const GpuBiCGSTABBuffers *gpu) {
226 return reinterpret_cast<const void *
>(gpu);
233inline bool gpuRuntimeAvailable() {
return detail::runtime().available; }
236inline const char *gpuRuntimeStatusMessage() {
237 return detail::runtime().status.c_str();
242inline GpuBiCGSTABBuffers *allocGpuBuffers(uint32_t n,
int nFaces,
243 bool useIlu0Preconditioner) {
244 const auto &rt = detail::runtime();
247 return reinterpret_cast<GpuBiCGSTABBuffers *
>(
248 rt.allocBuffers(n, nFaces, useIlu0Preconditioner ? 1 : 0));
252inline void freeGpuBuffers(GpuBiCGSTABBuffers *gpu) {
253 const auto &rt = detail::runtime();
255 rt.freeBuffers(detail::toHandle(gpu));
260inline const char *gpuGetLastErrorMessage() {
261 const auto &rt = detail::runtime();
262 return rt.available ? rt.lastErrorMessage() : rt.status.c_str();
266inline bool gpuIsValid(
const GpuBiCGSTABBuffers *gpu) {
267 const auto &rt = detail::runtime();
268 return rt.available && rt.isValid(detail::toHandle(gpu)) != 0;
273inline bool gpuUploadNeighborIds(GpuBiCGSTABBuffers *gpu,
const uint32_t *nb,
275 const auto &rt = detail::runtime();
276 return rt.available &&
277 rt.uploadNeighborIds(detail::toHandle(gpu), nb, count) != 0;
284inline bool gpuSetupCSR(GpuBiCGSTABBuffers *gpu,
const uint32_t *h_nb,
285 uint32_t n,
int nFaces) {
286 const auto &rt = detail::runtime();
287 return rt.available &&
288 rt.setupCSR(detail::toHandle(gpu), h_nb, n, nFaces) != 0;
293inline bool gpuUploadSolverArrays(GpuBiCGSTABBuffers *gpu,
const double *diag,
294 const double *b,
const double *coeff,
295 uint32_t diagLen, std::size_t coeffLen) {
296 const auto &rt = detail::runtime();
297 return rt.available && rt.uploadSolverArrays(detail::toHandle(gpu), diag, b,
298 coeff, diagLen, coeffLen) != 0;
304inline bool gpuUploadRhs(GpuBiCGSTABBuffers *gpu,
const double *b, uint32_t n) {
305 const auto &rt = detail::runtime();
306 return rt.available && rt.uploadRhs(detail::toHandle(gpu), b, n) != 0;
313inline bool gpuSolveBiCGSTAB(GpuBiCGSTABBuffers *gpu,
double *x,
double diagEps,
314 unsigned maxIter,
double tolerance,
315 unsigned &outIterations,
double &outResidual) {
316 const auto &rt = detail::runtime();
317 return rt.available &&
318 rt.solveBiCGSTAB(detail::toHandle(gpu), x, diagEps, maxIter, tolerance,
319 &outIterations, &outResidual) != 0;
#define VIENNALS_GPU_ABI_VERSION
Definition lsOxidationBiCGSTABAbi.hpp:22
Definition lsAdvect.hpp:41