mirror of https://github.com/BOINC/boinc.git
321 lines
11 KiB
C++
321 lines
11 KiB
C++
// This file is part of BOINC.
|
|
// http://boinc.berkeley.edu
|
|
// Copyright (C) 2011 University of California
|
|
//
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
// under the terms of the GNU Lesser General Public License
|
|
// as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// BOINC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// BOINC API for OpenCL
|
|
//
|
|
// To get the cl_device_id and cl_platform_id for the OpenCL GPU
|
|
// assigned to your application call this function:
|
|
// int boinc_get_opencl_ids(int argc, char** argv, char *type, cl_device_id* device, cl_platform_id* platform);
|
|
//
|
|
// To use this function, link your application with libboinc_opencl.a
|
|
//
|
|
|
|
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
|
|
#include "boinc_win.h"
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#include "win_util.h"
|
|
#else
|
|
#include <string>
|
|
#endif
|
|
|
|
#include "error_numbers.h"
|
|
#include "coproc.h"
|
|
#include "str_replace.h"
|
|
#include "boinc_api.h"
|
|
|
|
#include "boinc_opencl.h"
|
|
|
|
static int compareBOINCVersionTo(int toMajor, int toMinor, int toRelease);
|
|
|
|
// A few complicating factors:
|
|
// Windows & Linux have a separate OpenCL platform for each vendor
|
|
// (NVIDIA, AMD, Intel).
|
|
// Mac has only one platform (Apple) which reports GPUs from all vendors.
|
|
//
|
|
// In all systems, opencl_device_indexes start at 0 for each platform
|
|
// and device_nums start at 0 for each vendor.
|
|
//
|
|
// On Macs, OpenCL does not always recognize all GPU models detected by
|
|
// CUDA, so a device_num may not correspond to its opencl_device_index
|
|
// even if all GPUs are from NVIDIA.
|
|
//
|
|
int get_vendor(cl_device_id device_id, char* vendor, int len) {
|
|
int retval = 0;
|
|
|
|
retval = clGetDeviceInfo(
|
|
device_id, CL_DEVICE_VENDOR, len, vendor, NULL
|
|
);
|
|
if (retval != CL_SUCCESS) return retval;
|
|
if (!strlen(vendor)) return CL_INVALID_DEVICE_TYPE;
|
|
|
|
if ((strstr(vendor, "AMD")) ||
|
|
(strstr(vendor, "Advanced Micro Devices, Inc."))
|
|
) {
|
|
strlcpy(vendor, GPU_TYPE_ATI, len); // "ATI"
|
|
}
|
|
|
|
if (strcasestr(vendor, "nvidia")) {
|
|
strlcpy(vendor, GPU_TYPE_NVIDIA, len); // "NVIDIA"
|
|
}
|
|
|
|
if (strcasestr(vendor, "intel")) {
|
|
strlcpy(vendor, GPU_TYPE_INTEL, len); // "intel_gpu"
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// returns an OpenCL error num or zero
|
|
//
|
|
int boinc_get_opencl_ids_aux(
|
|
char* type, int opencl_device_index, int device_num,
|
|
cl_device_id* device, cl_platform_id* platform
|
|
) {
|
|
cl_platform_id platforms[MAX_OPENCL_PLATFORMS];
|
|
cl_uint num_platforms, platform_index, num_devices;
|
|
cl_device_id devices[MAX_COPROC_INSTANCES];
|
|
char vendor[256]; // Device vendor (NVIDIA, ATI, AMD, etc.)
|
|
int retval = 0;
|
|
cl_device_id device_id;
|
|
int device_num_for_type = -1;
|
|
int device_index;
|
|
|
|
if ((!type) || (!strlen(type))) return CL_INVALID_DEVICE_TYPE;
|
|
|
|
retval = clGetPlatformIDs(MAX_OPENCL_PLATFORMS, platforms, &num_platforms);
|
|
if (num_platforms == 0) return CL_DEVICE_NOT_FOUND;
|
|
if (retval != CL_SUCCESS) return retval;
|
|
|
|
for (platform_index=0; platform_index<num_platforms; ++platform_index) {
|
|
retval = clGetDeviceIDs(
|
|
platforms[platform_index], CL_DEVICE_TYPE_GPU,
|
|
MAX_COPROC_INSTANCES, devices, &num_devices
|
|
);
|
|
if (retval != CL_SUCCESS) continue;
|
|
|
|
// Use gpu_opencl_dev_index if available
|
|
if (opencl_device_index >= 0) {
|
|
if (opencl_device_index < (int)num_devices) {
|
|
device_id = devices[opencl_device_index];
|
|
retval = get_vendor(device_id, vendor, sizeof(vendor));
|
|
if (retval != CL_SUCCESS) continue;
|
|
|
|
if (!strcmp(vendor, type)) {
|
|
*device = device_id;
|
|
*platform = platforms[platform_index];
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Older versions of init_data.xml don't have the gpu_opencl_dev_index
|
|
// field so use the value of gpu_device_num.
|
|
// NOTE: This may return the wrong device on older versions of BOINC if
|
|
// OpenCL does not recognize all GPU models detected by CUDA or CAL
|
|
for (device_index=0; device_index<(int)num_devices; ++device_index) {
|
|
device_id = devices[device_index];
|
|
|
|
retval = get_vendor(device_id, vendor, sizeof(vendor));
|
|
if (retval != CL_SUCCESS) continue;
|
|
|
|
if (!strcmp(vendor, type)) {
|
|
if(++device_num_for_type == device_num) {
|
|
*device = device_id;
|
|
*platform = platforms[platform_index];
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "GPU not found: type=%s, opencl_device_index=%d, device_num=%d\n",
|
|
type, opencl_device_index, device_num);
|
|
|
|
return CL_DEVICE_NOT_FOUND;
|
|
}
|
|
|
|
|
|
// This version is compatible with older clients.
|
|
// Usage:
|
|
// Pass the argc and argv received from the BOINC client
|
|
// type: may be PROC_TYPE_NVIDIA_GPU, PROC_TYPE_AMD_GPU or PROC_TYPE_INTEL_GPU
|
|
// (it may also be 0, but then it will fail on older clients.)
|
|
//
|
|
// The argc, argv and type arguments are ignored for 6.13.3 or later clients.
|
|
//
|
|
// returns
|
|
// - 0 if success
|
|
// - ERR_FOPEN if init_data.xml missing
|
|
// - ERR_XML_PARSE if can't parse init_data.xml
|
|
// - CL_INVALID_DEVICE_TYPE if unable to get gpu_type information
|
|
// - CL_INVALID_DEVICE if unable to get opencl_device_index or gpu device_num
|
|
// - CL_DEVICE_NOT_FOUND if the requested device was not found
|
|
// - an OpenCL error number if OpenCL error
|
|
//
|
|
int boinc_get_opencl_ids(
|
|
int argc, char** argv, int type,
|
|
cl_device_id* device, cl_platform_id* platform
|
|
){
|
|
int retval;
|
|
APP_INIT_DATA aid;
|
|
char *gpu_type = NULL;
|
|
int gpu_device_num = -1;
|
|
int i;
|
|
|
|
retval = boinc_parse_init_data_file();
|
|
if (retval) return retval;
|
|
boinc_get_init_data(aid);
|
|
|
|
if (strlen(aid.gpu_type)) {
|
|
gpu_type = aid.gpu_type;
|
|
} else {
|
|
switch (type) {
|
|
case PROC_TYPE_NVIDIA_GPU:
|
|
gpu_type = (char *)GPU_TYPE_NVIDIA;
|
|
break;
|
|
case PROC_TYPE_AMD_GPU:
|
|
gpu_type = (char *)GPU_TYPE_ATI;
|
|
break;
|
|
case PROC_TYPE_INTEL_GPU:
|
|
gpu_type = (char *)GPU_TYPE_INTEL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((!gpu_type) || !strlen(gpu_type)) {
|
|
fprintf(stderr, "GPU type not found in %s\n", INIT_DATA_FILE);
|
|
return CL_INVALID_DEVICE_TYPE;
|
|
}
|
|
|
|
if (aid.gpu_opencl_dev_index < 0) {
|
|
if (compareBOINCVersionTo(7,0,12) >= 0) {
|
|
// gpu_opencl_dev_index was added in BOINC version 7.0.12.
|
|
// A gpu_opencl_dev_index value of -1 in version 7.0.12 or later
|
|
// means BOINC client did not assign an OpenCL GPU to this task.
|
|
fprintf(stderr, "Illegal value for gpu_opencl_dev_index: %d in BOINC Client %d.%d.%d\n",
|
|
aid.gpu_opencl_dev_index, aid.major_version, aid.minor_version, aid.release);
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
// Older versions of init_data.xml don't have the gpu_opencl_dev_index
|
|
// field so use the value of gpu_device_num if available.
|
|
gpu_device_num = aid.gpu_device_num;
|
|
if (gpu_device_num < 0) {
|
|
if (compareBOINCVersionTo(6,13,3) < 0) {
|
|
// gpu_device_num and gpu_type fields were added in BOINC version 6.13.3.
|
|
// Very old versions of init_data.xml don't have gpu_device_num field
|
|
// but instead pass the device number as a command-line argument.
|
|
for (i=0; i<argc-1; i++) {
|
|
if ((!strcmp(argv[i], "--device")) || (!strcmp(argv[i], "-device"))) {
|
|
gpu_device_num = atoi(argv[i+1]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gpu_device_num < 0) {
|
|
// BOINC client apparently did not assign a GPU to this task.
|
|
fprintf(stderr, "Illegal value for gpu_device_num: %d in BOINC Client %d.%d.%d\n",
|
|
aid.gpu_device_num, aid.major_version, aid.minor_version, aid.release);
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
} // End if (aid.gpu_opencl_dev_index < 0)
|
|
|
|
retval = boinc_get_opencl_ids_aux(
|
|
gpu_type, aid.gpu_opencl_dev_index, gpu_device_num, device, platform
|
|
);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
// Deprecated: use the version above instead
|
|
//
|
|
// returns
|
|
// - 0 if success
|
|
// - ERR_FOPEN if init_data.xml missing
|
|
// - ERR_XML_PARSE if can't parse init_data.xml
|
|
// - CL_INVALID_DEVICE_TYPE if unable to get gpu_type information
|
|
// - CL_INVALID_DEVICE if unable to get opencl_device_index or gpu device_num
|
|
// - CL_DEVICE_NOT_FOUND if the requested device was not found
|
|
// - an OpenCL error number if OpenCL error
|
|
//
|
|
int boinc_get_opencl_ids(cl_device_id* device, cl_platform_id* platform) {
|
|
int retval;
|
|
APP_INIT_DATA aid;
|
|
|
|
retval = boinc_parse_init_data_file();
|
|
if (retval) return retval;
|
|
boinc_get_init_data(aid);
|
|
|
|
if (!strlen(aid.gpu_type)) {
|
|
fprintf(stderr, "GPU type not found in %s\n", INIT_DATA_FILE);
|
|
return CL_INVALID_DEVICE_TYPE;
|
|
}
|
|
|
|
if (aid.gpu_opencl_dev_index < 0) {
|
|
if (compareBOINCVersionTo(7,0,12) >= 0) {
|
|
// gpu_opencl_dev_index was added in BOINC version 7.0.12.
|
|
// A gpu_opencl_dev_index value of -1 in version 7.0.12 or
|
|
// later means BOINC did not assign an OpenCL GPU to this task.
|
|
fprintf(stderr, "Illegal value for gpu_opencl_dev_index: %d in BOINC Client %d.%d.%d\n",
|
|
aid.gpu_opencl_dev_index, aid.major_version, aid.minor_version, aid.release);
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
|
|
if (aid.gpu_device_num < 0) {
|
|
if (compareBOINCVersionTo(6,13,3) >= 0) {
|
|
// gpu_device_num and gpu_type fields were added in BOINC version 6.13.3.
|
|
// A gpu_device_num value of -1 in version 6.13.3 or later means
|
|
// BOINC did not assign a GPU to this task.
|
|
fprintf(stderr, "Illegal value for gpu_device_num: %d in BOINC Client %d.%d.%d\n",
|
|
aid.gpu_device_num, aid.major_version, aid.minor_version, aid.release);
|
|
return CL_INVALID_DEVICE;
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = boinc_get_opencl_ids_aux(
|
|
aid.gpu_type, aid.gpu_opencl_dev_index, aid.gpu_device_num, device, platform
|
|
);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int compareBOINCVersionTo(int toMajor, int toMinor, int toRelease) {
|
|
APP_INIT_DATA aid;
|
|
|
|
boinc_get_init_data(aid);
|
|
|
|
if (aid.major_version < toMajor) return -1;
|
|
if (aid.major_version > toMajor) return 1;
|
|
if (aid.minor_version < toMinor) return -1;
|
|
if (aid.minor_version > toMinor) return 1;
|
|
if (aid.release < toRelease) return -1;
|
|
if (aid.release > toRelease) return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|