Skip to content

Commit

Permalink
[Android] Try to enhance GPU detection
Browse files Browse the repository at this point in the history
Signed-off-by: Vitalii Koshura <[email protected]>
  • Loading branch information
AenBleidd committed Aug 23, 2023
1 parent a490b80 commit a5b5871
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 4 deletions.
1 change: 0 additions & 1 deletion android/BOINC/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

251 changes: 249 additions & 2 deletions client/gpu_opencl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,73 @@ int compareOSVersionTo(int toMajor, int toMinor) {
}
#endif

#ifdef ANDROID
#include <android/dlext.h>
void* (*p_android_dlopen_ext)(const char*, int, const android_dlextinfo*);
struct android_namespace_t* (*p_android_create_namespace)(const char*, const char*, const char*, uint64_t, const char*, struct android_namespace_t*);
struct android_namespace_t* (*p_android_get_exported_namespace)(const char*);

struct android_namespace_t* get_android_namespace(vector<string>& warnings) {
p_android_get_exported_namespace = (struct android_namespace_t*(*)(const char*)) dlsym(RTLD_DEFAULT, "android_get_exported_namespace");
if (!p_android_get_exported_namespace) {
gpu_warning(warnings, "No android_get_exported_namespace()");
}
if (!p_android_get_exported_namespace) {
p_android_get_exported_namespace = (struct android_namespace_t*(*)(const char*)) dlsym(RTLD_DEFAULT, "__loader_android_get_exported_namespace");
if (!p_android_get_exported_namespace) {
gpu_warning(warnings, "No __loader_android_get_exported_namespace()");
}
}
if (p_android_get_exported_namespace) {
return (*p_android_get_exported_namespace)("vndk");
}

p_android_create_namespace = (struct android_namespace_t*(*)(const char*, const char*, const char*, uint64_t, const char*, struct android_namespace_t*)) dlsym(RTLD_DEFAULT, "android_create_namespace");
if (!p_android_create_namespace) {
gpu_warning(warnings, "No android_create_namespace()");
return NULL;
}
string lib_path;
if (sizeof(void*) == 8) {
lib_path = "/system/lib64/";
}
else {
lib_path = "/system/lib/";
}
#define ANDROID_NAMESPACE_TYPE_ISOLATED 1
#define ANDROID_NAMESPACE_TYPE_SHARED 2
return (*p_android_create_namespace)("trustme", lib_path.c_str(), lib_path.c_str(), ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED, "/system/:/data/:/vendor/", NULL);
}

void* android_dlopen(const char* filename, vector<string>& warnings) {
char buf[256];
gpu_warning(warnings, "Trying dlopen()");
void* handle = dlopen(filename, RTLD_NOW);
if (handle) {
return handle;
}

gpu_warning(warnings, "Go rogue...");
p_android_dlopen_ext = (void*(*)(const char*, int, const android_dlextinfo*)) dlsym(RTLD_DEFAULT, "android_dlopen_ext");
if (!p_android_dlopen_ext) {
gpu_warning(warnings, "No android_dlopen_ext()");
return NULL;
}

struct android_namespace_t* ns = get_android_namespace(warnings);
if (!ns) {
gpu_warning(warnings, "No namespace");
return NULL;
}

const android_dlextinfo dlextinfo = {
.flags = ANDROID_DLEXT_USE_NAMESPACE,
.library_namespace = ns,
};
gpu_warning(warnings, "Trying android_dlopen_ext()");
return (*p_android_dlopen_ext)(filename, RTLD_NOW, &dlextinfo);
}
#endif

// OpenCL interfaces are documented here:
// http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/ and
Expand Down Expand Up @@ -219,17 +286,77 @@ void COPROCS::get_opencl(
#else
#ifdef __APPLE__
opencl_lib = dlopen("/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL", RTLD_NOW);
#elif defined ANDROID
std::string libarch_name;
if (sizeof(void*) == 8) {
libarch_name = "lib64";
}
else {
libarch_name = "lib";
}

std::string opencl_lib_path;
androidretry:
if (opencl_lib_path.empty()) {
opencl_lib_path = "libOpenCL.so";
}
else if (opencl_lib_path == "libOpenCL.so") {
opencl_lib_path = "libOpenCL.so.1";
}
else if (opencl_lib_path == "libOpenCL.so.1") {
opencl_lib_path = "/vendor/" + libarch_name + "/libOpenCL.so";
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/libOpenCL.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/egl/libGLES_mali.so";
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/egl/libGLES_mali.so") {
opencl_lib_path = "/system_ext/" + libarch_name + "/libOpenCL_system.so";
}
else if (opencl_lib_path == "/system_ext/" + libarch_name + "/libOpenCL_system.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/libGLES_adreno.so"; // wrong
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/libGLES_adreno.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/libGLESv2_adreno.so"; // wrong
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/libGLESv2_adreno.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/libGLESv3_adreno.so"; // wrong
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/libGLESv3_adreno.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/egl/libGLES_adreno.so"; // wrong
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/egl/libGLES_adreno.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/egl/libGLESv2_adreno.so"; // wrong
}
else if (opencl_lib_path == "/vendor/" + libarch_name + "/egl/libGLESv2_adreno.so") {
opencl_lib_path = "/vendor/" + libarch_name + "/egl/libGLESv3_adreno.so"; // wrong
}
else {
snprintf(buf, sizeof(buf), "OpenCL: %s", dlerror());
gpu_warning(warnings, buf);
goto leave;
}

snprintf(buf, sizeof(buf), "Opening OpenCL: %s", opencl_lib_path.c_str());
gpu_warning(warnings, buf);
opencl_lib = android_dlopen(opencl_lib_path.c_str(), warnings);
if (!opencl_lib) {
snprintf(buf, sizeof(buf), "OpenCL: %s", dlerror());
gpu_warning(warnings, buf);
goto androidretry;
}
#else
opencl_lib = dlopen("libOpenCL.so", RTLD_NOW);
if (!opencl_lib) {
opencl_lib = dlopen("libOpenCL.so.1", RTLD_NOW);
}
#endif
#ifndef ANDROID
if (!opencl_lib) {
snprintf(buf, sizeof(buf), "OpenCL: %s", dlerror());
gpu_warning(warnings, buf);
return;
}
#endif
p_clGetPlatformIDs = (cl_int(*)(cl_uint, cl_platform_id*, cl_uint*)) dlsym( opencl_lib, "clGetPlatformIDs" );
p_clGetPlatformInfo = (cl_int(*)(cl_platform_id, cl_platform_info, size_t, void*, size_t*)) dlsym( opencl_lib, "clGetPlatformInfo" );
p_clGetDeviceIDs = (cl_int(*)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*)) dlsym( opencl_lib, "clGetDeviceIDs" );
Expand All @@ -238,27 +365,52 @@ void COPROCS::get_opencl(

if (!p_clGetPlatformIDs) {
gpu_warning(warnings, "clGetPlatformIDs() missing from OpenCL library");
#ifdef ANDROID
goto androidretry;
#else
goto leave;
#endif
}
if (!p_clGetPlatformInfo) {
gpu_warning(warnings, "clGetPlatformInfo() missing from OpenCL library");
#ifdef ANDROID
goto androidretry;
#else
goto leave;
#endif
}
if (!p_clGetDeviceIDs) {
gpu_warning(warnings, "clGetDeviceIDs() missing from OpenCL library");
#ifdef ANDROID
goto androidretry;
#else
goto leave;
#endif
}
if (!p_clGetDeviceInfo) {
gpu_warning(warnings, "clGetDeviceInfo() missing from OpenCL library");
#ifdef ANDROID
goto androidretry;
#else
goto leave;
#endif
}

ciErrNum = (*p_clGetPlatformIDs)(MAX_OPENCL_PLATFORMS, platforms, &num_platforms);
if ((ciErrNum != CL_SUCCESS) || (num_platforms == 0)) {
snprintf(buf, sizeof(buf), "clGetPlatformIDs() failed; error %d, num_platforms %d", ciErrNum, num_platforms);
gpu_warning(warnings, buf);
gpu_warning(warnings, "clGetPlatformIDs() failed to return any OpenCL platforms");
#ifdef ANDROID
goto androidretry;
#else
goto leave;
#endif
}

snprintf(buf, sizeof(buf), "Found %d OpenCL platforms", num_platforms);
gpu_warning(warnings, buf);

if (nvidia_gpus.size()) {
for (int i=0; i<(int)nvidia_gpus.size(); ++i) {
devnums_pci_slot_sort.push_back(i);
Expand Down Expand Up @@ -316,6 +468,9 @@ void COPROCS::get_opencl(
}
}

snprintf(buf, sizeof(buf), "Found %d CPU devices for platform #%u", num_devices, platform_index);
gpu_warning(warnings, buf);

for (device_index=0; device_index<num_devices; ++device_index) {
prop.clear();
prop.device_id = devices[device_index];
Expand All @@ -338,14 +493,93 @@ void COPROCS::get_opencl(

//////////// GPUs and Accelerators //////////////

// ciErrNum = (*p_clGetDeviceIDs)(
// platforms[platform_index],
// (CL_DEVICE_TYPE_CPU),
// MAX_COPROC_INSTANCES, devices, &num_devices
// );
// snprintf(buf, sizeof(buf), "clGetDeviceIDs() [CPU] returned %d", ciErrNum);
// gpu_warning(warnings, buf);

// ciErrNum = (*p_clGetDeviceIDs)(
// platforms[platform_index],
// (CL_DEVICE_TYPE_GPU),
// MAX_COPROC_INSTANCES, devices, &num_devices
// );
// snprintf(buf, sizeof(buf), "clGetDeviceIDs() [GPU] returned %d", ciErrNum);
// gpu_warning(warnings, buf);


// ciErrNum = (*p_clGetDeviceIDs)(
// platforms[platform_index],
// (CL_DEVICE_TYPE_ACCELERATOR),
// MAX_COPROC_INSTANCES, devices, &num_devices
// );
// snprintf(buf, sizeof(buf), "clGetDeviceIDs() [ACC] returned %d", ciErrNum);
// gpu_warning(warnings, buf);

// ciErrNum = (*p_clGetDeviceIDs)(
// platforms[platform_index],
// (CL_DEVICE_TYPE_CUSTOM),
// MAX_COPROC_INSTANCES, devices, &num_devices
// );
// snprintf(buf, sizeof(buf), "clGetDeviceIDs() [CTM] returned %d", ciErrNum);
// gpu_warning(warnings, buf);

// ciErrNum = (*p_clGetDeviceIDs)(
// platforms[platform_index],
// (CL_DEVICE_TYPE_DEFAULT),
// MAX_COPROC_INSTANCES, devices, &num_devices
// );
// snprintf(buf, sizeof(buf), "clGetDeviceIDs() [DLT] returned %d", ciErrNum);
// gpu_warning(warnings, buf);

// Looks like implementation of Qualcomm has some problems with clGetDeviceIDs
// It returns CL_DEVICE_NOT_FOUND for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR combined
// But it returns CL_SUCCESS when asking separately for CL_DEVICE_TYPE_GPU or CL_DEVICE_TYPE_ACCELERATOR
// So we will ask for CL_DEVICE_TYPE_GPU and CL_DEVICE_TYPE_ACCELERATOR separately
#ifdef ANDROID
cl_device_id android_gpu[MAX_COPROC_INSTANCES];
cl_uint num_android_gpu = 0;
ciErrNum = (*p_clGetDeviceIDs)(
platforms[platform_index],
(CL_DEVICE_TYPE_GPU),
MAX_COPROC_INSTANCES, android_gpu, &num_android_gpu
);
if (ciErrNum == CL_SUCCESS && num_android_gpu > 0) {
for (int i=0; i<num_android_gpu; ++i) {
devices[i] = android_gpu[i];
}
num_devices = num_android_gpu;
}

cl_device_id android_acc[MAX_COPROC_INSTANCES];
cl_uint num_android_acc = 0;
ciErrNum = (*p_clGetDeviceIDs)(
platforms[platform_index],
(CL_DEVICE_TYPE_ACCELERATOR),
MAX_COPROC_INSTANCES - num_devices, android_acc, &num_android_acc
);
if (ciErrNum == CL_SUCCESS && num_android_acc > 0) {
for (int i=0; i<num_android_acc; ++i) {
devices[num_devices+i] = android_acc[i];
}
num_devices += num_android_acc;
}
#else
ciErrNum = (*p_clGetDeviceIDs)(
platforms[platform_index],
(CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR),
MAX_COPROC_INSTANCES, devices, &num_devices
);

if (ciErrNum == CL_DEVICE_NOT_FOUND) continue; // No devices
if (num_devices == 0) continue; // No devices
snprintf(buf, sizeof(buf), "clGetDeviceIDs() returned %d", ciErrNum);
gpu_warning(warnings, buf);

if (ciErrNum == CL_DEVICE_NOT_FOUND) {
gpu_warning(warnings, "No OpenCL GPUs or Accelerators found");
continue; // No devices
}

if (ciErrNum != CL_SUCCESS) {
snprintf(buf, sizeof(buf),
Expand All @@ -355,6 +589,11 @@ void COPROCS::get_opencl(
gpu_warning(warnings, buf);
continue;
}
#endif
if (num_devices == 0) continue; // No devices

snprintf(buf, sizeof(buf), "Found %d OpenCL GPUs or Accelerators for platform #%u", num_devices, platform_index);
gpu_warning(warnings, buf);

// Mac OpenCL does not recognize all NVIDIA GPUs returned by CUDA
// Fortunately, CUDA and OpenCL return the same GPU model name on
Expand All @@ -378,6 +617,10 @@ void COPROCS::get_opencl(
//
current_CAL_index = 0;
min_CAL_target = 0;

snprintf(buf, sizeof(buf), "Found platform vendor %s", platform_vendor);
gpu_warning(warnings, buf);

if (is_AMD(platform_vendor) && (num_CAL_devices > 0)) {
while (1) {
int numToMatch = 0;
Expand Down Expand Up @@ -665,6 +908,10 @@ void COPROCS::get_opencl(
(other_opencls.size() == 0)
) {
gpu_warning(warnings, "OpenCL library present but no OpenCL-capable devices found");
#ifdef ANDROID
gpu_warning(warnings, "OpenCL: trying alternate library");
goto androidretry;
#endif
}
leave:
#ifdef _WIN32
Expand Down
1 change: 1 addition & 0 deletions lib/cl_boinc.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ typedef cl_bitfield cl_command_queue_properties;
#define CL_DEVICE_TYPE_CPU (1 << 1)
#define CL_DEVICE_TYPE_GPU (1 << 2)
#define CL_DEVICE_TYPE_ACCELERATOR (1 << 3)
#define CL_DEVICE_TYPE_CUSTOM (1 << 4)
#define CL_DEVICE_TYPE_ALL 0xFFFFFFFF

/* cl_device_info */
Expand Down
2 changes: 1 addition & 1 deletion lib/opencl_boinc.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ struct OPENCL_DEVICE_PROP {
int get_device_version_int(); // call this to encode
int opencl_driver_revision; // OpenCL runtime revision is available
int get_opencl_driver_revision(); // call this to encode
char opencl_driver_version[32]; // For example: "CLH 1.0"
char opencl_driver_version[1024]; // For example: "CLH 1.0"
int device_num; // temp used in scan process
double peak_flops; // temp used in scan process
COPROC_USAGE is_used; // temp used in scan process
Expand Down

0 comments on commit a5b5871

Please sign in to comment.