1
// This file is part of BOINC.
2
// http://boinc.berkeley.edu
3
// Copyright (C) 2009 University of California
5
// BOINC is free software; you can redistribute it and/or modify it
6
// under the terms of the GNU Lesser General Public License
7
// as published by the Free Software Foundation,
8
// either version 3 of the License, or (at your option) any later version.
10
// BOINC is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU Lesser General Public License for more details.
15
// You should have received a copy of the GNU Lesser General Public License
16
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
19
// client-specific GPU code. Mostly GPU detection
24
#include "boinc_win.h"
30
// Suppress obsolete warning when building for OS 10.3.9
31
#define DLOPEN_NO_WARN
43
#include "client_state.h"
44
#include "client_msgs.h"
49
//#define MEASURE_AVAILABLE_RAM
51
static bool in_vector(int n, vector<int>& v) {
52
for (unsigned int i=0; i<v.size(); i++) {
53
if (v[i] == n) return true;
61
void segv_handler(int) {
66
void COPROC::print_available_ram() {
67
#ifdef MEASURE_AVAILABLE_RAM
68
if (gstate.now - last_print_time < 60) return;
69
last_print_time = gstate.now;
71
for (int i=0; i<count; i++) {
72
if (available_ram_unknown[i]) {
73
if (log_flags.coproc_debug) {
74
msg_printf(0, MSG_INFO,
75
"[coproc] %s device %d: available RAM unknown",
80
if (log_flags.coproc_debug) {
81
msg_printf(0, MSG_INFO,
82
"[coproc] %s device %d: available RAM %d MB",
84
(int)(available_ram[i]/MEGA)
93
bool use_all, vector<string>&descs, vector<string>&warnings,
94
vector<int>& ignore_cuda_dev,
95
vector<int>& ignore_ati_dev
100
cuda.get(use_all, descs, warnings, ignore_cuda_dev);
103
warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection");
106
ati.get(use_all, descs, warnings, ignore_ati_dev);
109
warnings.push_back("Caught SIGSEGV in ATI GPU detection");
112
void (*old_sig)(int) = signal(SIGSEGV, segv_handler);
113
if (setjmp(resume)) {
114
warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection");
116
cuda.get(use_all, descs, warnings, ignore_cuda_dev);
118
#ifndef __APPLE__ // ATI does not yet support CAL on Macs
119
if (setjmp(resume)) {
120
warnings.push_back("Caught SIGSEGV in ATI GPU detection");
122
ati.get(use_all, descs, warnings, ignore_ati_dev);
125
signal(SIGSEGV, old_sig);
129
// return 1/-1/0 if device 1 is more/less/same capable than device 2.
130
// factors (decreasing priority):
131
// - compute capability
132
// - software version
136
// If "loose", ignore FLOPS and tolerate small memory diff
138
int cuda_compare(COPROC_CUDA& c1, COPROC_CUDA& c2, bool loose) {
139
if (c1.prop.major > c2.prop.major) return 1;
140
if (c1.prop.major < c2.prop.major) return -1;
141
if (c1.prop.minor > c2.prop.minor) return 1;
142
if (c1.prop.minor < c2.prop.minor) return -1;
143
if (c1.cuda_version > c2.cuda_version) return 1;
144
if (c1.cuda_version < c2.cuda_version) return -1;
146
if (c1.prop.totalGlobalMem > 1.4*c2.prop.totalGlobalMem) return 1;
147
if (c1.prop.totalGlobalMem < .7* c2.prop.totalGlobalMem) return -1;
150
if (c1.prop.totalGlobalMem > c2.prop.totalGlobalMem) return 1;
151
if (c1.prop.totalGlobalMem < c2.prop.totalGlobalMem) return -1;
152
double s1 = c1.peak_flops();
153
double s2 = c2.peak_flops();
154
if (s1 > s2) return 1;
155
if (s1 < s2) return -1;
159
enum CUdevice_attribute_enum {
160
CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK = 1,
161
CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X = 2,
162
CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y = 3,
163
CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z = 4,
164
CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X = 5,
165
CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y = 6,
166
CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z = 7,
167
CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK = 8,
168
CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY = 9,
169
CU_DEVICE_ATTRIBUTE_WARP_SIZE = 10,
170
CU_DEVICE_ATTRIBUTE_MAX_PITCH = 11,
171
CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK = 12,
172
CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13,
173
CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT = 14,
174
CU_DEVICE_ATTRIBUTE_GPU_OVERLAP = 15,
175
CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16,
176
CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT = 17,
177
CU_DEVICE_ATTRIBUTE_INTEGRATED = 18,
178
CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY = 19,
179
CU_DEVICE_ATTRIBUTE_COMPUTE_MODE = 20
183
typedef int (__stdcall *CUDA_GDC)(int *count);
184
typedef int (__stdcall *CUDA_GDV)(int* version);
185
typedef int (__stdcall *CUDA_GDI)(int);
186
typedef int (__stdcall *CUDA_GDG)(int*, int);
187
typedef int (__stdcall *CUDA_GDA)(int*, int, int);
188
typedef int (__stdcall *CUDA_GDN)(char*, int, int);
189
typedef int (__stdcall *CUDA_GDM)(unsigned int*, int);
190
typedef int (__stdcall *CUDA_GDCC)(int*, int*, int);
191
typedef int (__stdcall *CUDA_CC)(unsigned int*, unsigned int, unsigned int);
192
typedef int (__stdcall *CUDA_CD)(unsigned int);
193
typedef int (__stdcall *CUDA_MA)(unsigned int*, unsigned int);
194
typedef int (__stdcall *CUDA_MF)(unsigned int);
195
typedef int (__stdcall *CUDA_MGI)(unsigned int*, unsigned int*);
197
CUDA_GDC __cuDeviceGetCount = NULL;
198
CUDA_GDV __cuDriverGetVersion = NULL;
199
CUDA_GDI __cuInit = NULL;
200
CUDA_GDG __cuDeviceGet = NULL;
201
CUDA_GDA __cuDeviceGetAttribute = NULL;
202
CUDA_GDN __cuDeviceGetName = NULL;
203
CUDA_GDM __cuDeviceTotalMem = NULL;
204
CUDA_GDCC __cuDeviceComputeCapability = NULL;
205
CUDA_CC __cuCtxCreate = NULL;
206
CUDA_CD __cuCtxDestroy = NULL;
207
CUDA_MA __cuMemAlloc = NULL;
208
CUDA_MF __cuMemFree = NULL;
209
CUDA_MGI __cuMemGetInfo = NULL;
212
int (*__cuInit)(int);
213
int (*__cuDeviceGetCount)(int*);
214
int (*__cuDriverGetVersion)(int*);
215
int (*__cuDeviceGet)(int*, int);
216
int (*__cuDeviceGetAttribute)(int*, int, int);
217
int (*__cuDeviceGetName)(char*, int, int);
218
int (*__cuDeviceTotalMem)(unsigned int*, int);
219
int (*__cuDeviceComputeCapability)(int*, int*, int);
220
int (*__cuCtxCreate)(unsigned int*, unsigned int, unsigned int);
221
int (*__cuCtxDestroy)(unsigned int);
222
int (*__cuMemAlloc)(unsigned int*, unsigned int);
223
int (*__cuMemFree)(unsigned int);
224
int (*__cuMemGetInfo)(unsigned int*, unsigned int*);
227
// NVIDIA interfaces are documented here:
228
// http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/online/index.html
230
void COPROC_CUDA::get(
231
bool use_all, // if false, use only those equivalent to most capable
232
vector<string>& descs,
233
vector<string>& warnings,
234
vector<int>& ignore_devs
240
HMODULE cudalib = LoadLibrary("nvcuda.dll");
242
warnings.push_back("No NVIDIA library found");
245
__cuDeviceGetCount = (CUDA_GDC)GetProcAddress( cudalib, "cuDeviceGetCount" );
246
__cuDriverGetVersion = (CUDA_GDV)GetProcAddress( cudalib, "cuDriverGetVersion" );
247
__cuInit = (CUDA_GDI)GetProcAddress( cudalib, "cuInit" );
248
__cuDeviceGet = (CUDA_GDG)GetProcAddress( cudalib, "cuDeviceGet" );
249
__cuDeviceGetAttribute = (CUDA_GDA)GetProcAddress( cudalib, "cuDeviceGetAttribute" );
250
__cuDeviceGetName = (CUDA_GDN)GetProcAddress( cudalib, "cuDeviceGetName" );
251
__cuDeviceTotalMem = (CUDA_GDM)GetProcAddress( cudalib, "cuDeviceTotalMem" );
252
__cuDeviceComputeCapability = (CUDA_GDCC)GetProcAddress( cudalib, "cuDeviceComputeCapability" );
253
__cuCtxCreate = (CUDA_CC)GetProcAddress( cudalib, "cuCtxCreate" );
254
__cuCtxDestroy = (CUDA_CD)GetProcAddress( cudalib, "cuCtxDestroy" );
255
__cuMemAlloc = (CUDA_MA)GetProcAddress( cudalib, "cuMemAlloc" );
256
__cuMemFree = (CUDA_MF)GetProcAddress( cudalib, "cuMemFree" );
257
__cuMemGetInfo = (CUDA_MGI)GetProcAddress( cudalib, "cuMemGetInfo" );
260
NvAPI_Status nvapiStatus;
261
NvDisplayHandle hDisplay;
262
NV_DISPLAY_DRIVER_VERSION Version;
263
memset(&Version, 0, sizeof(Version));
264
Version.version = NV_DISPLAY_DRIVER_VERSION_VER;
267
for (int i=0; ; i++) {
268
nvapiStatus = NvAPI_EnumNvidiaDisplayHandle(i, &hDisplay);
269
if (nvapiStatus != NVAPI_OK) break;
270
nvapiStatus = NvAPI_GetDisplayDriverVersion(hDisplay, &Version);
271
if (nvapiStatus == NVAPI_OK) break;
277
cudalib = dlopen("/usr/local/cuda/lib/libcuda.dylib", RTLD_NOW);
279
cudalib = dlopen("libcuda.so", RTLD_NOW);
282
warnings.push_back("No NVIDIA library found");
285
__cuDeviceGetCount = (int(*)(int*)) dlsym(cudalib, "cuDeviceGetCount");
286
__cuDriverGetVersion = (int(*)(int*)) dlsym( cudalib, "cuDriverGetVersion" );
287
__cuInit = (int(*)(int)) dlsym( cudalib, "cuInit" );
288
__cuDeviceGet = (int(*)(int*, int)) dlsym( cudalib, "cuDeviceGet" );
289
__cuDeviceGetAttribute = (int(*)(int*, int, int)) dlsym( cudalib, "cuDeviceGetAttribute" );
290
__cuDeviceGetName = (int(*)(char*, int, int)) dlsym( cudalib, "cuDeviceGetName" );
291
__cuDeviceTotalMem = (int(*)(unsigned int*, int)) dlsym( cudalib, "cuDeviceTotalMem" );
292
__cuDeviceComputeCapability = (int(*)(int*, int*, int)) dlsym( cudalib, "cuDeviceComputeCapability" );
293
__cuCtxCreate = (int(*)(unsigned int*, unsigned int, unsigned int)) dlsym( cudalib, "cuCtxCreate" );
294
__cuCtxDestroy = (int(*)(unsigned int)) dlsym( cudalib, "cuCtxDestroy" );
295
__cuMemAlloc = (int(*)(unsigned int*, unsigned int)) dlsym( cudalib, "cuMemAlloc" );
296
__cuMemFree = (int(*)(unsigned int)) dlsym( cudalib, "cuMemFree" );
297
__cuMemGetInfo = (int(*)(unsigned int*, unsigned int*)) dlsym( cudalib, "cuMemGetInfo" );
300
if (!__cuDriverGetVersion) {
301
warnings.push_back("cuDriverGetVersion() missing from NVIDIA library");
305
warnings.push_back("cuInit() missing from NVIDIA library");
308
if (!__cuDeviceGetCount) {
309
warnings.push_back("cuDeviceGetCount() missing from NVIDIA library");
312
if (!__cuDeviceGet) {
313
warnings.push_back("cuDeviceGet() missing from NVIDIA library");
316
if (!__cuDeviceGetAttribute) {
317
warnings.push_back("cuDeviceGetAttribute() missing from NVIDIA library");
320
if (!__cuDeviceTotalMem) {
321
warnings.push_back("cuDeviceTotalMem() missing from NVIDIA library");
324
if (!__cuDeviceComputeCapability) {
325
warnings.push_back("cuDeviceComputeCapability() missing from NVIDIA library");
328
if (!__cuCtxCreate) {
329
warnings.push_back("cuCtxCreate() missing from NVIDIA library");
332
if (!__cuCtxDestroy) {
333
warnings.push_back("cuCtxDestroy() missing from NVIDIA library");
337
warnings.push_back("cuMemAlloc() missing from NVIDIA library");
341
warnings.push_back("cuMemFree() missing from NVIDIA library");
344
if (!__cuMemGetInfo) {
345
warnings.push_back("cuMemGetInfo() missing from NVIDIA library");
349
retval = (*__cuInit)(0);
351
sprintf(buf, "NVIDIA drivers present but no GPUs found");
352
warnings.push_back(buf);
357
retval = (*__cuDriverGetVersion)(&cuda_version);
359
sprintf(buf, "cuDriverGetVersion() returned %d", retval);
360
warnings.push_back(buf);
364
vector<COPROC_CUDA> gpus;
365
retval = (*__cuDeviceGetCount)(&count);
367
sprintf(buf, "cuDeviceGetCount() returned %d", retval);
368
warnings.push_back(buf);
371
sprintf(buf, "NVIDIA library reports %d GPU%s", count, (count==1)?"":"s");
372
warnings.push_back(buf);
378
for (j=0; j<count; j++) {
379
memset(&cc.prop, 0, sizeof(cc.prop));
381
retval = (*__cuDeviceGet)(&device, j);
383
sprintf(buf, "cuDeviceGet(%d) returned %d", j, retval);
384
warnings.push_back(buf);
387
(*__cuDeviceGetName)(cc.prop.name, 256, device);
389
sprintf(buf, "cuDeviceGetName(%d) returned %d", j, retval);
390
warnings.push_back(buf);
393
(*__cuDeviceComputeCapability)(&cc.prop.major, &cc.prop.minor, device);
394
(*__cuDeviceTotalMem)(&cc.prop.totalGlobalMem, device);
395
(*__cuDeviceGetAttribute)(&cc.prop.sharedMemPerBlock, CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK, device);
396
(*__cuDeviceGetAttribute)(&cc.prop.regsPerBlock, CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK, device);
397
(*__cuDeviceGetAttribute)(&cc.prop.warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, device);
398
(*__cuDeviceGetAttribute)(&cc.prop.memPitch, CU_DEVICE_ATTRIBUTE_MAX_PITCH, device);
399
retval = (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsPerBlock, CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK, device);
400
retval = (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[0], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, device);
401
(*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[1], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y, device);
402
(*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[2], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z, device);
403
(*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[0], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, device);
404
(*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[1], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y, device);
405
(*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[2], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z, device);
406
(*__cuDeviceGetAttribute)(&cc.prop.clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, device);
407
(*__cuDeviceGetAttribute)(&cc.prop.totalConstMem, CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY, device);
408
(*__cuDeviceGetAttribute)(&cc.prop.textureAlignment, CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT, device);
409
(*__cuDeviceGetAttribute)(&cc.prop.deviceOverlap, CU_DEVICE_ATTRIBUTE_GPU_OVERLAP, device);
410
retval = (*__cuDeviceGetAttribute)(&cc.prop.multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, device);
411
//retval = (*__cuDeviceGetProperties)(&cc.prop, device);
412
if (cc.prop.major <= 0) continue; // major == 0 means emulation
413
if (cc.prop.major > 100) continue; // e.g. 9999 is an error
414
#if defined(_WIN32) && !defined(SIM)
415
cc.display_driver_version = Version.drvVersion;
417
cc.display_driver_version = 0;
419
cc.cuda_version = cuda_version;
425
warnings.push_back("No CUDA-capable NVIDIA GPUs found");
429
// identify the most capable non-ignored instance
433
for (i=0; i<gpus.size(); i++) {
434
if (in_vector(gpus[i].device_num, ignore_devs)) continue;
438
} else if (cuda_compare(gpus[i], best, false) > 0) {
443
// see which other instances are equivalent,
444
// and set the "count" and "device_nums" fields
447
for (i=0; i<gpus.size(); i++) {
449
gpus[i].description(buf);
450
if (in_vector(gpus[i].device_num, ignore_devs)) {
451
sprintf(buf2, "NVIDIA GPU %d (ignored by config): %s", gpus[i].device_num, buf);
452
} else if (use_all || !cuda_compare(gpus[i], best, true)) {
453
best.device_nums[best.count] = gpus[i].device_num;
455
sprintf(buf2, "NVIDIA GPU %d: %s", gpus[i].device_num, buf);
457
sprintf(buf2, "NVIDIA GPU %d (not used): %s", gpus[i].device_num, buf);
459
descs.push_back(string(buf2));
467
// fake a NVIDIA GPU (for debugging)
469
void COPROC_CUDA::fake(int driver_version, double ram, int n) {
470
strcpy(type, "CUDA");
472
for (int i=0; i<count; i++) {
475
display_driver_version = driver_version;
477
strcpy(prop.name, "Fake NVIDIA GPU");
478
prop.totalGlobalMem = (unsigned int)ram;
479
prop.sharedMemPerBlock = 100;
480
prop.regsPerBlock = 8;
483
prop.maxThreadsPerBlock = 20;
484
prop.maxThreadsDim[0] = 2;
485
prop.maxThreadsDim[1] = 2;
486
prop.maxThreadsDim[2] = 2;
487
prop.maxGridSize[0] = 10;
488
prop.maxGridSize[1] = 10;
489
prop.maxGridSize[2] = 10;
490
prop.totalConstMem = 10;
493
prop.clockRate = 1250000;
494
prop.textureAlignment = 1000;
495
prop.multiProcessorCount = 14;
498
// See how much RAM is available on each GPU.
499
// If this fails, set "available_ram_unknown"
501
void COPROC_CUDA::get_available_ram() {
502
#ifdef MEASURE_AVAILABLE_RAM
503
int device, i, retval;
504
unsigned int memfree, memtotal;
507
// avoid crash if faked GPU
509
if (!__cuDeviceGet) {
510
for (i=0; i<count; i++) {
511
available_ram[i] = available_ram_fake[i];
512
available_ram_unknown[i] = false;
516
for (i=0; i<count; i++) {
517
int devnum = device_nums[i];
518
available_ram[i] = 0;
519
available_ram_unknown[i] = true;
520
retval = (*__cuDeviceGet)(&device, devnum);
522
if (log_flags.coproc_debug) {
523
msg_printf(0, MSG_INFO,
524
"[coproc] cuDeviceGet(%d) returned %d", devnum, retval
529
retval = (*__cuCtxCreate)(&ctx, 0, device);
531
if (log_flags.coproc_debug) {
532
msg_printf(0, MSG_INFO,
533
"[coproc] cuCtxCreate(%d) returned %d", devnum, retval
538
retval = (*__cuMemGetInfo)(&memfree, &memtotal);
540
if (log_flags.coproc_debug) {
541
msg_printf(0, MSG_INFO,
542
"[coproc] cuMemGetInfo(%d) returned %d", devnum, retval
545
(*__cuCtxDestroy)(ctx);
548
(*__cuCtxDestroy)(ctx);
549
available_ram[i] = (double) memfree;
550
available_ram_unknown[i] = false;
553
for (int i=0; i<count; i++) {
554
available_ram_unknown[i] = false;
555
available_ram[i] = prop.totalGlobalMem;
560
// check whether each GPU is running a graphics app (assume yes)
561
// return true if there's been a change since last time
563
bool COPROC_CUDA::check_running_graphics_app() {
566
for (j=0; j<count; j++) {
568
int device, kernel_timeout;
569
retval = (*__cuDeviceGet)(&device, j);
571
retval = (*__cuDeviceGetAttribute)(&kernel_timeout, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, device);
572
if (!retval && !kernel_timeout) {
576
if (new_val != running_graphics_app[j]) {
579
running_graphics_app[j] = new_val;
584
////////////////// ATI STARTS HERE /////////////////
587
// http://developer.amd.com/gpu_assets/Stream_Computing_User_Guide.pdf
588
// ?? why don't they have HTML docs??
592
// - double precision support
596
int ati_compare(COPROC_ATI& c1, COPROC_ATI& c2, bool loose) {
597
if (c1.attribs.doublePrecision && !c2.attribs.doublePrecision) return 1;
598
if (!c1.attribs.doublePrecision && c2.attribs.doublePrecision) return -1;
600
if (c1.attribs.localRAM> 1.4*c2.attribs.localRAM) return 1;
601
if (c1.attribs.localRAM< .7* c2.attribs.localRAM) return -1;
604
if (c1.attribs.localRAM > c2.attribs.localRAM) return 1;
605
if (c1.attribs.localRAM < c2.attribs.localRAM) return -1;
606
double s1 = c1.peak_flops();
607
double s2 = c2.peak_flops();
608
if (s1 > s2) return 1;
609
if (s1 < s2) return -1;
614
typedef int (__stdcall *ATI_ATTRIBS) (CALdeviceattribs *attribs, CALuint ordinal);
615
typedef int (__stdcall *ATI_CLOSE)(void);
616
typedef int (__stdcall *ATI_GDC)(CALuint *numDevices);
617
typedef int (__stdcall *ATI_GDI)(void);
618
typedef int (__stdcall *ATI_INFO) (CALdeviceinfo *info, CALuint ordinal);
619
typedef int (__stdcall *ATI_VER) (CALuint *cal_major, CALuint *cal_minor, CALuint *cal_imp);
620
typedef int (__stdcall *ATI_STATUS) (CALdevicestatus*, CALdevice);
621
typedef int (__stdcall *ATI_DEVICEOPEN) (CALdevice*, CALuint);
622
typedef int (__stdcall *ATI_DEVICECLOSE) (CALdevice);
624
ATI_ATTRIBS __calDeviceGetAttribs = NULL;
625
ATI_CLOSE __calShutdown = NULL;
626
ATI_GDC __calDeviceGetCount = NULL;
627
ATI_GDI __calInit = NULL;
628
ATI_INFO __calDeviceGetInfo = NULL;
629
ATI_VER __calGetVersion = NULL;
630
ATI_STATUS __calDeviceGetStatus = NULL;
631
ATI_DEVICEOPEN __calDeviceOpen = NULL;
632
ATI_DEVICECLOSE __calDeviceClose = NULL;
637
int (*__calGetVersion)(CALuint*, CALuint*, CALuint*);
638
int (*__calDeviceGetCount)(CALuint*);
639
int (*__calDeviceGetAttribs)(CALdeviceattribs*, CALuint);
640
int (*__calShutdown)();
641
int (*__calDeviceGetInfo)(CALdeviceinfo*, CALuint);
642
int (*__calDeviceGetStatus)(CALdevicestatus*, CALdevice);
643
int (*__calDeviceOpen)(CALdevice*, CALuint);
644
int (*__calDeviceClose)(CALdevice);
648
void COPROC_ATI::get(
650
vector<string>& descs, vector<string>& warnings, vector<int>& ignore_devs
652
CALuint numDevices, cal_major, cal_minor, cal_imp;
655
CALdeviceattribs attribs;
657
bool amdrt_detected = false;
658
bool atirt_detected = false;
662
attribs.struct_size = sizeof(CALdeviceattribs);
669
const char* atilib_name = "aticalrt64.dll";
670
const char* amdlib_name = "amdcalrt64.dll";
672
const char* atilib_name = "aticalrt.dll";
673
const char* amdlib_name = "amdcalrt.dll";
676
HINSTANCE callib = LoadLibrary(atilib_name);
678
atirt_detected = true;
680
callib = LoadLibrary(amdlib_name);
682
amdrt_detected = true;
687
warnings.push_back("No ATI library found.");
691
__calInit = (ATI_GDI)GetProcAddress(callib, "calInit" );
692
__calGetVersion = (ATI_VER)GetProcAddress(callib, "calGetVersion" );
693
__calDeviceGetCount = (ATI_GDC)GetProcAddress(callib, "calDeviceGetCount" );
694
__calDeviceGetAttribs =(ATI_ATTRIBS)GetProcAddress(callib, "calDeviceGetAttribs" );
695
__calShutdown = (ATI_CLOSE)GetProcAddress(callib, "calShutdown" );
696
__calDeviceGetInfo = (ATI_INFO)GetProcAddress(callib, "calDeviceGetInfo" );
697
__calDeviceGetStatus = (ATI_STATUS)GetProcAddress(callib, "calDeviceGetStatus" );
698
__calDeviceOpen = (ATI_DEVICEOPEN)GetProcAddress(callib, "calDeviceOpen" );
699
__calDeviceClose = (ATI_DEVICECLOSE)GetProcAddress(callib, "calDeviceClose" );
705
callib = dlopen("libaticalrt.so", RTLD_NOW);
707
warnings.push_back("No ATI library found");
711
atirt_detected = true;
713
__calInit = (int(*)()) dlsym(callib, "calInit");
714
__calGetVersion = (int(*)(CALuint*, CALuint*, CALuint*)) dlsym(callib, "calGetVersion");
715
__calDeviceGetCount = (int(*)(CALuint*)) dlsym(callib, "calDeviceGetCount");
716
__calDeviceGetAttribs = (int(*)(CALdeviceattribs*, CALuint)) dlsym(callib, "calDeviceGetAttribs");
717
__calShutdown = (int(*)()) dlsym(callib, "calShutdown");
718
__calDeviceGetInfo = (int(*)(CALdeviceinfo*, CALuint)) dlsym(callib, "calDeviceGetInfo");
719
__calDeviceGetStatus = (int(*)(CALdevicestatus*, CALdevice)) dlsym(callib, "calDeviceGetStatus");
720
__calDeviceOpen = (int(*)(CALdevice*, CALuint)) dlsym(callib, "calDeviceOpen");
721
__calDeviceClose = (int(*)(CALdevice)) dlsym(callib, "calDeviceClose");
726
warnings.push_back("calInit() missing from CAL library");
729
if (!__calGetVersion) {
730
warnings.push_back("calGetVersion() missing from CAL library");
733
if (!__calDeviceGetCount) {
734
warnings.push_back("calDeviceGetCount() missing from CAL library");
737
if (!__calDeviceGetAttribs) {
738
warnings.push_back("calDeviceGetAttribs() missing from CAL library");
741
if (!__calDeviceGetInfo) {
742
warnings.push_back("calDeviceGetInfo() missing from CAL library");
745
if (!__calDeviceGetStatus) {
746
warnings.push_back("calDeviceGetStatus() missing from CAL library");
749
if (!__calDeviceOpen) {
750
warnings.push_back("calDeviceOpen() missing from CAL library");
753
if (!__calDeviceClose) {
754
warnings.push_back("calDeviceClose() missing from CAL library");
758
retval = (*__calInit)();
759
if (retval != CAL_RESULT_OK) {
760
sprintf(buf, "calInit() returned %d", retval);
761
warnings.push_back(buf);
764
retval = (*__calDeviceGetCount)(&numDevices);
765
if (retval != CAL_RESULT_OK) {
766
sprintf(buf, "calDeviceGetCount() returned %d", retval);
767
warnings.push_back(buf);
770
retval = (*__calGetVersion)(&cal_major, &cal_minor, &cal_imp);
771
if (retval != CAL_RESULT_OK) {
772
sprintf(buf, "calGetVersion() returned %d", retval);
773
warnings.push_back(buf);
778
warnings.push_back("No usable CAL devices found");
784
vector<COPROC_ATI> gpus;
785
for (CALuint i=0; i<numDevices; i++) {
786
retval = (*__calDeviceGetInfo)(&info, i);
787
if (retval != CAL_RESULT_OK) {
788
sprintf(buf, "calDeviceGetInfo() returned %d", retval);
789
warnings.push_back(buf);
792
retval = (*__calDeviceGetAttribs)(&attribs, i);
793
if (retval != CAL_RESULT_OK) {
794
sprintf(buf, "calDeviceGetAttribs() returned %d", retval);
795
warnings.push_back(buf);
798
switch ((int)attribs.target) {
800
gpu_name="ATI Radeon HD 2900 (RV600)";
803
gpu_name="ATI Radeon HD 2300/2400/3200 (RV610)";
804
attribs.numberOfSIMD=1; // set correct values (reported wrong by driver)
805
attribs.wavefrontSize=32;
808
gpu_name="ATI Radeon HD 2600 (RV630)";
809
// set correct values (reported wrong by driver)
810
attribs.numberOfSIMD=3;
811
attribs.wavefrontSize=32;
814
gpu_name="ATI Radeon HD 3800 (RV670)";
817
gpu_name="ATI Radeon HD 4350/4550 (R710)";
820
gpu_name="ATI Radeon HD 4600 series (R730)";
823
gpu_name="ATI Radeon (RV700 class)";
826
gpu_name="ATI Radeon HD 4700/4800 (RV740/RV770)";
829
gpu_name="ATI Radeon HD5800 series (Cypress)";
832
gpu_name="ATI Radeon HD5700 series (Juniper)";
835
gpu_name="ATI Radeon HD5x00 series (Redwood)";
838
gpu_name="ATI Radeon HD5x00 series (Cedar)";
841
gpu_name="ATI unknown";
844
cc.attribs = attribs;
846
strcpy(cc.name, gpu_name.c_str());
847
sprintf(cc.version, "%d.%d.%d", cal_major, cal_minor, cal_imp);
848
cc.amdrt_detected = amdrt_detected;
849
cc.atirt_detected = atirt_detected;
854
// shut down, otherwise Lenovo won't be able to switch to low-power GPU
856
retval = (*__calShutdown)();
859
warnings.push_back("No ATI GPUs found");
865
for (i=0; i<gpus.size(); i++) {
866
if (in_vector(gpus[i].device_num, ignore_devs)) continue;
870
} else if (ati_compare(gpus[i], best, false) > 0) {
876
for (i=0; i<gpus.size(); i++) {
877
char buf[256], buf2[256];
878
gpus[i].description(buf);
879
if (in_vector(gpus[i].device_num, ignore_devs)) {
880
sprintf(buf2, "ATI GPU %d (ignored by config): %s", gpus[i].device_num, buf);
881
} else if (use_all || !ati_compare(gpus[i], best, true)) {
882
best.device_nums[best.count] = gpus[i].device_num;
884
sprintf(buf2, "ATI GPU %d: %s", gpus[i].device_num, buf);
886
sprintf(buf2, "ATI GPU %d: (not used) %s", gpus[i].device_num, buf);
888
descs.push_back(string(buf2));
896
void COPROC_ATI::fake(double ram, int n) {
898
strcpy(version, "1.4.3");
899
strcpy(name, "foobar");
901
memset(&attribs, 0, sizeof(attribs));
902
memset(&info, 0, sizeof(info));
903
attribs.localRAM = (int)(ram/MEGA);
904
attribs.numberOfSIMD = 32;
905
attribs.wavefrontSize = 32;
906
attribs.engineClock = 50;
907
for (int i=0; i<count; i++) {
912
void COPROC_ATI::get_available_ram() {
913
#ifdef MEASURE_AVAILABLE_RAM
918
st.struct_size = sizeof(CALdevicestatus);
920
// avoid crash if faked GPU
922
for (i=0; i<count; i++) {
923
available_ram[i] = available_ram_fake[i];
924
available_ram_unknown[i] = false;
928
for (i=0; i<count; i++) {
929
available_ram[i] = 0;
930
available_ram_unknown[i] = true;
932
retval = (*__calInit)();
934
if (log_flags.coproc_debug) {
935
msg_printf(0, MSG_INFO,
936
"[coproc] calInit() returned %d", retval
942
for (i=0; i<count; i++) {
943
int devnum = device_nums[i];
944
retval = (*__calDeviceOpen)(&dev, devnum);
946
if (log_flags.coproc_debug) {
947
msg_printf(0, MSG_INFO,
948
"[coproc] calDeviceOpen(%d) returned %d", devnum, retval
953
retval = (*__calDeviceGetStatus)(&st, dev);
955
if (log_flags.coproc_debug) {
956
msg_printf(0, MSG_INFO,
957
"[coproc] calDeviceGetStatus(%d) returned %d",
961
(*__calDeviceClose)(dev);
964
available_ram[i] = st.availLocalRAM*MEGA;
965
available_ram_unknown[i] = false;
966
(*__calDeviceClose)(dev);
970
for (int i=0; i<count; i++) {
971
available_ram_unknown[i] = false;
972
available_ram[i] = attribs.localRAM*MEGA;