~ubuntu-branches/ubuntu/natty/boinc/natty

« back to all changes in this revision

Viewing changes to client/coproc_detect.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Hahler
  • Date: 2010-07-13 03:59:26 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20100713035926-8jun0z3d3yfl27k3
Tags: 6.10.58-0ubuntu1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// This file is part of BOINC.
 
2
// http://boinc.berkeley.edu
 
3
// Copyright (C) 2009 University of California
 
4
//
 
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.
 
9
//
 
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.
 
14
//
 
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/>.
 
17
 
 
18
 
 
19
// client-specific GPU code.  Mostly GPU detection
 
20
 
 
21
#include "cpp.h"
 
22
 
 
23
#ifdef _WIN32
 
24
#include "boinc_win.h"
 
25
#ifndef SIM
 
26
#include <nvapi.h>
 
27
#endif
 
28
#else
 
29
#include "config.h"
 
30
#endif
 
31
 
 
32
#ifndef _WIN32
 
33
#ifdef __APPLE__
 
34
// Suppress obsolete warning when building for OS 10.3.9
 
35
#define DLOPEN_NO_WARN
 
36
#endif
 
37
#include <dlfcn.h>
 
38
#include <setjmp.h>
 
39
#include <signal.h>
 
40
#endif
 
41
 
 
42
#include "coproc.h"
 
43
#include "str_util.h"
 
44
#include "util.h"
 
45
 
 
46
#include "client_state.h"
 
47
#include "client_msgs.h"
 
48
 
 
49
using std::string;
 
50
using std::vector;
 
51
 
 
52
//#define MEASURE_AVAILABLE_RAM
 
53
 
 
54
static bool in_vector(int n, vector<int>& v) {
 
55
    for (unsigned int i=0; i<v.size(); i++) {
 
56
        if (v[i] == n) return true;
 
57
    }
 
58
    return false;
 
59
}
 
60
 
 
61
#ifndef _WIN32
 
62
jmp_buf resume;
 
63
 
 
64
void segv_handler(int) {
 
65
    longjmp(resume, 1);
 
66
}
 
67
#endif
 
68
 
 
69
void COPROC::print_available_ram() {
 
70
#ifdef MEASURE_AVAILABLE_RAM
 
71
    if (gstate.now - last_print_time < 60) return;
 
72
    last_print_time = gstate.now;
 
73
 
 
74
    for (int i=0; i<count; i++) {
 
75
        if (available_ram_unknown[i]) {
 
76
            if (log_flags.coproc_debug) {
 
77
                msg_printf(0, MSG_INFO,
 
78
                    "[coproc_debug] %s device %d: available RAM unknown",
 
79
                    type, device_nums[i]
 
80
                );
 
81
            }
 
82
        } else {
 
83
            if (log_flags.coproc_debug) {
 
84
                msg_printf(0, MSG_INFO,
 
85
                    "[coproc_debug] %s device %d: available RAM %d MB",
 
86
                    type, device_nums[i],
 
87
                    (int)(available_ram[i]/MEGA)
 
88
                );
 
89
            }
 
90
        }
 
91
    }
 
92
#endif
 
93
}
 
94
 
 
95
void COPROCS::get(
 
96
    bool use_all, vector<string>&descs, vector<string>&warnings,
 
97
    vector<int>& ignore_cuda_dev,
 
98
    vector<int>& ignore_ati_dev
 
99
) {
 
100
 
 
101
#ifdef _WIN32
 
102
    try {
 
103
        COPROC_CUDA::get(*this, use_all, descs, warnings, ignore_cuda_dev);
 
104
    }
 
105
    catch (...) {
 
106
        warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection");
 
107
    }
 
108
    try {
 
109
        COPROC_ATI::get(*this, descs, warnings, ignore_ati_dev);
 
110
    } 
 
111
    catch (...) {
 
112
        warnings.push_back("Caught SIGSEGV in ATI GPU detection");
 
113
    }
 
114
#else
 
115
    void (*old_sig)(int) = signal(SIGSEGV, segv_handler);
 
116
    if (setjmp(resume)) {
 
117
        warnings.push_back("Caught SIGSEGV in NVIDIA GPU detection");
 
118
    } else {
 
119
        COPROC_CUDA::get(*this, use_all, descs, warnings, ignore_cuda_dev);
 
120
    }
 
121
#ifndef __APPLE__       // ATI does not yet support CAL on Macs
 
122
    if (setjmp(resume)) {
 
123
        warnings.push_back("Caught SIGSEGV in ATI GPU detection");
 
124
    } else {
 
125
        COPROC_ATI::get(*this, descs, warnings, ignore_ati_dev);
 
126
    }
 
127
#endif
 
128
    signal(SIGSEGV, old_sig);
 
129
#endif
 
130
}
 
131
 
 
132
// return 1/-1/0 if device 1 is more/less/same capable than device 2.
 
133
// If "loose", ignore FLOPS and tolerate small memory diff
 
134
//
 
135
int cuda_compare(COPROC_CUDA& c1, COPROC_CUDA& c2, bool loose) {
 
136
    if (c1.prop.major > c2.prop.major) return 1;
 
137
    if (c1.prop.major < c2.prop.major) return -1;
 
138
    if (c1.prop.minor > c2.prop.minor) return 1;
 
139
    if (c1.prop.minor < c2.prop.minor) return -1;
 
140
    if (c1.cuda_version > c2.cuda_version) return 1;
 
141
    if (c1.cuda_version < c2.cuda_version) return -1;
 
142
    if (loose) {
 
143
        if (c1.prop.totalGlobalMem > 1.4*c2.prop.totalGlobalMem) return 1;
 
144
        if (c1.prop.totalGlobalMem < .7* c2.prop.totalGlobalMem) return -1;
 
145
        return 0;
 
146
    }
 
147
    if (c1.prop.totalGlobalMem > c2.prop.totalGlobalMem) return 1;
 
148
    if (c1.prop.totalGlobalMem < c2.prop.totalGlobalMem) return -1;
 
149
    double s1 = c1.peak_flops();
 
150
    double s2 = c2.peak_flops();
 
151
    if (s1 > s2) return 1;
 
152
    if (s1 < s2) return -1;
 
153
    return 0;
 
154
}
 
155
 
 
156
#ifdef _WIN32
 
157
typedef int (__stdcall *CUDA_GDC)(int *count);
 
158
typedef int (__stdcall *CUDA_GDV)(int* version);
 
159
typedef int (__stdcall *CUDA_GDI)(int);
 
160
typedef int (__stdcall *CUDA_GDG)(int*, int);
 
161
typedef int (__stdcall *CUDA_GDA)(int*, int, int);
 
162
typedef int (__stdcall *CUDA_GDN)(char*, int, int);
 
163
typedef int (__stdcall *CUDA_GDM)(unsigned int*, int);
 
164
typedef int (__stdcall *CUDA_GDCC)(int*, int*, int);
 
165
typedef int (__stdcall *CUDA_CC)(unsigned int*, unsigned int, unsigned int);
 
166
typedef int (__stdcall *CUDA_CD)(unsigned int);
 
167
typedef int (__stdcall *CUDA_MA)(unsigned int*, unsigned int);
 
168
typedef int (__stdcall *CUDA_MF)(unsigned int);
 
169
typedef int (__stdcall *CUDA_MGI)(unsigned int*, unsigned int*);
 
170
 
 
171
CUDA_GDC __cuDeviceGetCount = NULL;
 
172
CUDA_GDV __cuDriverGetVersion = NULL;
 
173
CUDA_GDI __cuInit = NULL;
 
174
CUDA_GDG __cuDeviceGet = NULL;
 
175
CUDA_GDA __cuDeviceGetAttribute = NULL;
 
176
CUDA_GDN __cuDeviceGetName = NULL;
 
177
CUDA_GDM __cuDeviceTotalMem = NULL;
 
178
CUDA_GDCC __cuDeviceComputeCapability = NULL;
 
179
CUDA_CC __cuCtxCreate = NULL;
 
180
CUDA_CD __cuCtxDestroy = NULL;
 
181
CUDA_MA __cuMemAlloc = NULL;
 
182
CUDA_MF __cuMemFree = NULL;
 
183
CUDA_MGI __cuMemGetInfo = NULL;
 
184
#else
 
185
void* cudalib;
 
186
int (*__cuInit)(int);
 
187
int (*__cuDeviceGetCount)(int*);
 
188
int (*__cuDriverGetVersion)(int*);
 
189
int (*__cuDeviceGet)(int*, int);
 
190
int (*__cuDeviceGetAttribute)(int*, int, int);
 
191
int (*__cuDeviceGetName)(char*, int, int);
 
192
int (*__cuDeviceTotalMem)(unsigned int*, int);
 
193
int (*__cuDeviceComputeCapability)(int*, int*, int);
 
194
int (*__cuCtxCreate)(unsigned int*, unsigned int, unsigned int);
 
195
int (*__cuCtxDestroy)(unsigned int);
 
196
int (*__cuMemAlloc)(unsigned int*, unsigned int);
 
197
int (*__cuMemFree)(unsigned int);
 
198
int (*__cuMemGetInfo)(unsigned int*, unsigned int*);
 
199
#endif
 
200
 
 
201
// NVIDIA interfaces are documented here:
 
202
// http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/online/index.html
 
203
 
 
204
void COPROC_CUDA::get(
 
205
    COPROCS& coprocs,
 
206
    bool use_all,    // if false, use only those equivalent to most capable
 
207
    vector<string>& descs,
 
208
    vector<string>& warnings,
 
209
    vector<int>& ignore_devs
 
210
) {
 
211
    int count, retval;
 
212
    char buf[256];
 
213
 
 
214
#ifdef _WIN32
 
215
    HMODULE cudalib = LoadLibrary("nvcuda.dll");
 
216
    if (!cudalib) {
 
217
        warnings.push_back("No NVIDIA library found");
 
218
        return;
 
219
    }
 
220
    __cuDeviceGetCount = (CUDA_GDC)GetProcAddress( cudalib, "cuDeviceGetCount" );
 
221
    __cuDriverGetVersion = (CUDA_GDV)GetProcAddress( cudalib, "cuDriverGetVersion" );
 
222
    __cuInit = (CUDA_GDI)GetProcAddress( cudalib, "cuInit" );
 
223
    __cuDeviceGet = (CUDA_GDG)GetProcAddress( cudalib, "cuDeviceGet" );
 
224
    __cuDeviceGetAttribute = (CUDA_GDA)GetProcAddress( cudalib, "cuDeviceGetAttribute" );
 
225
    __cuDeviceGetName = (CUDA_GDN)GetProcAddress( cudalib, "cuDeviceGetName" );
 
226
    __cuDeviceTotalMem = (CUDA_GDM)GetProcAddress( cudalib, "cuDeviceTotalMem" );
 
227
    __cuDeviceComputeCapability = (CUDA_GDCC)GetProcAddress( cudalib, "cuDeviceComputeCapability" );
 
228
    __cuCtxCreate = (CUDA_CC)GetProcAddress( cudalib, "cuCtxCreate" );
 
229
    __cuCtxDestroy = (CUDA_CD)GetProcAddress( cudalib, "cuCtxDestroy" );
 
230
    __cuMemAlloc = (CUDA_MA)GetProcAddress( cudalib, "cuMemAlloc" );
 
231
    __cuMemFree = (CUDA_MF)GetProcAddress( cudalib, "cuMemFree" );
 
232
    __cuMemGetInfo = (CUDA_MGI)GetProcAddress( cudalib, "cuMemGetInfo" );
 
233
 
 
234
#ifndef SIM
 
235
    NvAPI_Status nvapiStatus;
 
236
    NvDisplayHandle hDisplay;
 
237
    NV_DISPLAY_DRIVER_VERSION Version;
 
238
    memset(&Version, 0, sizeof(Version));
 
239
    Version.version = NV_DISPLAY_DRIVER_VERSION_VER;
 
240
 
 
241
    NvAPI_Initialize();
 
242
    for (int i=0; ; i++) {
 
243
        nvapiStatus = NvAPI_EnumNvidiaDisplayHandle(i, &hDisplay);
 
244
        if (nvapiStatus != NVAPI_OK) break;
 
245
        nvapiStatus = NvAPI_GetDisplayDriverVersion(hDisplay, &Version);
 
246
        if (nvapiStatus == NVAPI_OK) break;
 
247
    }
 
248
#endif
 
249
#else
 
250
 
 
251
#ifdef __APPLE__
 
252
    cudalib = dlopen("/usr/local/cuda/lib/libcuda.dylib", RTLD_NOW);
 
253
#else
 
254
    cudalib = dlopen("libcuda.so", RTLD_NOW);
 
255
#endif
 
256
    if (!cudalib) {
 
257
        warnings.push_back("No NVIDIA library found");
 
258
        return;
 
259
    }
 
260
    __cuDeviceGetCount = (int(*)(int*)) dlsym(cudalib, "cuDeviceGetCount");
 
261
    __cuDriverGetVersion = (int(*)(int*)) dlsym( cudalib, "cuDriverGetVersion" );
 
262
    __cuInit = (int(*)(int)) dlsym( cudalib, "cuInit" );
 
263
    __cuDeviceGet = (int(*)(int*, int)) dlsym( cudalib, "cuDeviceGet" );
 
264
    __cuDeviceGetAttribute = (int(*)(int*, int, int)) dlsym( cudalib, "cuDeviceGetAttribute" );
 
265
    __cuDeviceGetName = (int(*)(char*, int, int)) dlsym( cudalib, "cuDeviceGetName" );
 
266
    __cuDeviceTotalMem = (int(*)(unsigned int*, int)) dlsym( cudalib, "cuDeviceTotalMem" );
 
267
    __cuDeviceComputeCapability = (int(*)(int*, int*, int)) dlsym( cudalib, "cuDeviceComputeCapability" );
 
268
    __cuCtxCreate = (int(*)(unsigned int*, unsigned int, unsigned int)) dlsym( cudalib, "cuCtxCreate" );
 
269
    __cuCtxDestroy = (int(*)(unsigned int)) dlsym( cudalib, "cuCtxDestroy" );
 
270
    __cuMemAlloc = (int(*)(unsigned int*, unsigned int)) dlsym( cudalib, "cuMemAlloc" );
 
271
    __cuMemFree = (int(*)(unsigned int)) dlsym( cudalib, "cuMemFree" );
 
272
    __cuMemGetInfo = (int(*)(unsigned int*, unsigned int*)) dlsym( cudalib, "cuMemGetInfo" );
 
273
#endif
 
274
 
 
275
    if (!__cuDriverGetVersion) {
 
276
        warnings.push_back("cuDriverGetVersion() missing from NVIDIA library");
 
277
        return;
 
278
    }
 
279
    if (!__cuInit) {
 
280
        warnings.push_back("cuInit() missing from NVIDIA library");
 
281
        return;
 
282
    }
 
283
    if (!__cuDeviceGetCount) {
 
284
        warnings.push_back("cuDeviceGetCount() missing from NVIDIA library");
 
285
        return;
 
286
    }
 
287
    if (!__cuDeviceGet) {
 
288
        warnings.push_back("cuDeviceGet() missing from NVIDIA library");
 
289
        return;
 
290
    }
 
291
    if (!__cuDeviceGetAttribute) {
 
292
        warnings.push_back("cuDeviceGetAttribute() missing from NVIDIA library");
 
293
        return;
 
294
    }
 
295
    if (!__cuDeviceTotalMem) {
 
296
        warnings.push_back("cuDeviceTotalMem() missing from NVIDIA library");
 
297
        return;
 
298
    }
 
299
    if (!__cuDeviceComputeCapability) {
 
300
        warnings.push_back("cuDeviceComputeCapability() missing from NVIDIA library");
 
301
        return;
 
302
    }
 
303
    if (!__cuCtxCreate) {
 
304
        warnings.push_back("cuCtxCreate() missing from NVIDIA library");
 
305
        return;
 
306
    }
 
307
    if (!__cuCtxDestroy) {
 
308
        warnings.push_back("cuCtxDestroy() missing from NVIDIA library");
 
309
        return;
 
310
    }
 
311
    if (!__cuMemAlloc) {
 
312
        warnings.push_back("cuMemAlloc() missing from NVIDIA library");
 
313
        return;
 
314
    }
 
315
    if (!__cuMemFree) {
 
316
        warnings.push_back("cuMemFree() missing from NVIDIA library");
 
317
        return;
 
318
    }
 
319
    if (!__cuMemGetInfo) {
 
320
        warnings.push_back("cuMemGetInfo() missing from NVIDIA library");
 
321
        return;
 
322
    }
 
323
 
 
324
    retval = (*__cuInit)(0);
 
325
    if (retval) {
 
326
        sprintf(buf, "NVIDIA drivers present but no GPUs found");
 
327
        warnings.push_back(buf);
 
328
        return;
 
329
    }
 
330
 
 
331
    int cuda_version;
 
332
    retval = (*__cuDriverGetVersion)(&cuda_version);
 
333
    if (retval) {
 
334
        sprintf(buf, "cuDriverGetVersion() returned %d", retval);
 
335
        warnings.push_back(buf);
 
336
        return;
 
337
    }
 
338
 
 
339
    vector<COPROC_CUDA> gpus;
 
340
    retval = (*__cuDeviceGetCount)(&count);
 
341
    if (retval) {
 
342
        sprintf(buf, "cuDeviceGetCount() returned %d", retval);
 
343
        warnings.push_back(buf);
 
344
        return;
 
345
    }
 
346
    sprintf(buf, "NVIDIA library reports %d GPU%s", count, (count==1)?"":"s");
 
347
    warnings.push_back(buf);
 
348
 
 
349
    int j;
 
350
    unsigned int i;
 
351
    COPROC_CUDA cc;
 
352
    string s;
 
353
    for (j=0; j<count; j++) {
 
354
        memset(&cc.prop, 0, sizeof(cc.prop));
 
355
        int device;
 
356
        retval = (*__cuDeviceGet)(&device, j);
 
357
        if (retval) {
 
358
            sprintf(buf, "cuDeviceGet(%d) returned %d", j, retval);
 
359
            warnings.push_back(buf);
 
360
            return;
 
361
        }
 
362
        (*__cuDeviceGetName)(cc.prop.name, 256, device);
 
363
        if (retval) {
 
364
            sprintf(buf, "cuDeviceGetName(%d) returned %d", j, retval);
 
365
            warnings.push_back(buf);
 
366
            return;
 
367
        }
 
368
        (*__cuDeviceComputeCapability)(&cc.prop.major, &cc.prop.minor, device);
 
369
        (*__cuDeviceTotalMem)(&cc.prop.totalGlobalMem, device);
 
370
        (*__cuDeviceGetAttribute)(&cc.prop.sharedMemPerBlock, CU_DEVICE_ATTRIBUTE_SHARED_MEMORY_PER_BLOCK, device);
 
371
        (*__cuDeviceGetAttribute)(&cc.prop.regsPerBlock, CU_DEVICE_ATTRIBUTE_REGISTERS_PER_BLOCK, device);
 
372
        (*__cuDeviceGetAttribute)(&cc.prop.warpSize, CU_DEVICE_ATTRIBUTE_WARP_SIZE, device);
 
373
        (*__cuDeviceGetAttribute)(&cc.prop.memPitch, CU_DEVICE_ATTRIBUTE_MAX_PITCH, device);
 
374
        retval = (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsPerBlock, CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK, device);
 
375
        retval = (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[0], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_X, device);
 
376
        (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[1], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Y, device);
 
377
        (*__cuDeviceGetAttribute)(&cc.prop.maxThreadsDim[2], CU_DEVICE_ATTRIBUTE_MAX_BLOCK_DIM_Z, device);
 
378
        (*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[0], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_X, device);
 
379
        (*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[1], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Y, device);
 
380
        (*__cuDeviceGetAttribute)(&cc.prop.maxGridSize[2], CU_DEVICE_ATTRIBUTE_MAX_GRID_DIM_Z, device);
 
381
        (*__cuDeviceGetAttribute)(&cc.prop.clockRate, CU_DEVICE_ATTRIBUTE_CLOCK_RATE, device);
 
382
        (*__cuDeviceGetAttribute)(&cc.prop.totalConstMem, CU_DEVICE_ATTRIBUTE_TOTAL_CONSTANT_MEMORY, device);
 
383
        (*__cuDeviceGetAttribute)(&cc.prop.textureAlignment, CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT, device);
 
384
        (*__cuDeviceGetAttribute)(&cc.prop.deviceOverlap, CU_DEVICE_ATTRIBUTE_GPU_OVERLAP, device);
 
385
        retval = (*__cuDeviceGetAttribute)(&cc.prop.multiProcessorCount, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, device);
 
386
        //retval = (*__cuDeviceGetProperties)(&cc.prop, device);
 
387
        if (cc.prop.major <= 0) continue;  // major == 0 means emulation
 
388
        if (cc.prop.major > 100) continue;  // e.g. 9999 is an error
 
389
#if defined(_WIN32) && !defined(SIM)
 
390
        cc.display_driver_version = Version.drvVersion;
 
391
#else
 
392
        cc.display_driver_version = 0;
 
393
#endif
 
394
        cc.cuda_version = cuda_version;
 
395
        cc.device_num = j;
 
396
        gpus.push_back(cc);
 
397
    }
 
398
 
 
399
    if (!gpus.size()) {
 
400
        warnings.push_back("No CUDA-capable NVIDIA GPUs found");
 
401
        return;
 
402
    }
 
403
 
 
404
    // identify the most capable non-ignored instance
 
405
    //
 
406
    COPROC_CUDA best;
 
407
    bool first = true;
 
408
    for (i=0; i<gpus.size(); i++) {
 
409
        if (in_vector(gpus[i].device_num, ignore_devs)) continue;
 
410
        if (first) {
 
411
            best = gpus[i];
 
412
            first = false;
 
413
        } else if (cuda_compare(gpus[i], best, false) > 0) {
 
414
            best = gpus[i];
 
415
        }
 
416
    }
 
417
 
 
418
    // see which other instances are equivalent,
 
419
    // and set the "count" and "device_nums" fields
 
420
    //
 
421
    best.count = 0;
 
422
    for (i=0; i<gpus.size(); i++) {
 
423
        char buf2[256];
 
424
        gpus[i].description(buf);
 
425
        if (in_vector(gpus[i].device_num, ignore_devs)) {
 
426
            sprintf(buf2, "NVIDIA GPU %d (ignored by config): %s", gpus[i].device_num, buf);
 
427
        } else if (use_all || !cuda_compare(gpus[i], best, true)) {
 
428
            best.device_nums[best.count] = gpus[i].device_num;
 
429
            best.count++;
 
430
            sprintf(buf2, "NVIDIA GPU %d: %s", gpus[i].device_num, buf);
 
431
        } else {
 
432
            sprintf(buf2, "NVIDIA GPU %d (not used): %s", gpus[i].device_num, buf);
 
433
        }
 
434
        descs.push_back(string(buf2));
 
435
    }
 
436
 
 
437
    if (best.count) {
 
438
        COPROC_CUDA* ccp = new COPROC_CUDA;
 
439
        *ccp = best;
 
440
        coprocs.coprocs.push_back(ccp);
 
441
    }
 
442
}
 
443
 
 
444
// fake a NVIDIA GPU (for debugging)
 
445
//
 
446
COPROC_CUDA* fake_cuda(COPROCS& coprocs, double ram, int count) {
 
447
   COPROC_CUDA* cc = new COPROC_CUDA;
 
448
   strcpy(cc->type, "CUDA");
 
449
   cc->count = count;
 
450
   for (int i=0; i<count; i++) {
 
451
       cc->device_nums[i] = i;
 
452
   }
 
453
   cc->display_driver_version = 18000;
 
454
   cc->cuda_version = 2020;
 
455
   strcpy(cc->prop.name, "Fake NVIDIA GPU");
 
456
   cc->prop.totalGlobalMem = (unsigned int)ram;
 
457
   cc->prop.sharedMemPerBlock = 100;
 
458
   cc->prop.regsPerBlock = 8;
 
459
   cc->prop.warpSize = 10;
 
460
   cc->prop.memPitch = 10;
 
461
   cc->prop.maxThreadsPerBlock = 20;
 
462
   cc->prop.maxThreadsDim[0] = 2;
 
463
   cc->prop.maxThreadsDim[1] = 2;
 
464
   cc->prop.maxThreadsDim[2] = 2;
 
465
   cc->prop.maxGridSize[0] = 10;
 
466
   cc->prop.maxGridSize[1] = 10;
 
467
   cc->prop.maxGridSize[2] = 10;
 
468
   cc->prop.totalConstMem = 10;
 
469
   cc->prop.major = 1;
 
470
   cc->prop.minor = 2;
 
471
   cc->prop.clockRate = 1250000;
 
472
   cc->prop.textureAlignment = 1000;
 
473
   cc->prop.multiProcessorCount = 14;
 
474
   coprocs.coprocs.push_back(cc);
 
475
   return cc;
 
476
}
 
477
 
 
478
// See how much RAM is available on each GPU.
 
479
// If this fails, set "available_ram_unknown"
 
480
//
 
481
void COPROC_CUDA::get_available_ram() {
 
482
#ifdef MEASURE_AVAILABLE_RAM
 
483
    int device, i, retval;
 
484
    unsigned int memfree, memtotal;
 
485
    unsigned int ctx;
 
486
    
 
487
    // avoid crash if faked GPU
 
488
    //
 
489
    if (!__cuDeviceGet) {
 
490
        for (i=0; i<count; i++) {
 
491
            available_ram[i] = available_ram_fake[i];
 
492
            available_ram_unknown[i] = false;
 
493
        }
 
494
        return;
 
495
    }
 
496
    for (i=0; i<count; i++) {
 
497
        int devnum = device_nums[i];
 
498
        available_ram[i] = 0;
 
499
        available_ram_unknown[i] = true;
 
500
        retval = (*__cuDeviceGet)(&device, devnum);
 
501
        if (retval) {
 
502
            if (log_flags.coproc_debug) {
 
503
                msg_printf(0, MSG_INFO,
 
504
                    "[coproc] cuDeviceGet(%d) returned %d", devnum, retval
 
505
                );
 
506
            }
 
507
            continue;
 
508
        }
 
509
        retval = (*__cuCtxCreate)(&ctx, 0, device);
 
510
        if (retval) {
 
511
            if (log_flags.coproc_debug) {
 
512
                msg_printf(0, MSG_INFO,
 
513
                    "[coproc] cuCtxCreate(%d) returned %d", devnum, retval
 
514
                );
 
515
            }
 
516
            continue;
 
517
        }
 
518
        retval = (*__cuMemGetInfo)(&memfree, &memtotal);
 
519
        if (retval) {
 
520
            if (log_flags.coproc_debug) {
 
521
                msg_printf(0, MSG_INFO,
 
522
                    "[coproc] cuMemGetInfo(%d) returned %d", devnum, retval
 
523
                );
 
524
            }
 
525
            (*__cuCtxDestroy)(ctx);
 
526
            continue;
 
527
        }
 
528
        (*__cuCtxDestroy)(ctx);
 
529
        available_ram[i] = (double) memfree;
 
530
        available_ram_unknown[i] = false;
 
531
    }
 
532
#else
 
533
    for (int i=0; i<count; i++) {
 
534
        available_ram_unknown[i] = false;
 
535
        available_ram[i] = prop.totalGlobalMem;
 
536
    }
 
537
#endif
 
538
}
 
539
 
 
540
// check whether each GPU is running a graphics app (assume yes)
 
541
// return true if there's been a change since last time
 
542
//
 
543
bool COPROC_CUDA::check_running_graphics_app() {
 
544
    int retval, j;
 
545
    bool change = false;
 
546
    for (j=0; j<count; j++) {
 
547
        bool new_val = true;
 
548
        int device, kernel_timeout;
 
549
        retval = (*__cuDeviceGet)(&device, j);
 
550
        if (!retval) {
 
551
            retval = (*__cuDeviceGetAttribute)(&kernel_timeout, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, device);
 
552
            if (!retval && !kernel_timeout) {
 
553
                new_val = false;
 
554
            }
 
555
        }
 
556
        if (new_val != running_graphics_app[j]) {
 
557
            change = true;
 
558
        }
 
559
        running_graphics_app[j] = new_val;
 
560
    }
 
561
    return change;
 
562
}
 
563
 
 
564
////////////////// ATI STARTS HERE /////////////////
 
565
//
 
566
// Docs:
 
567
// http://developer.amd.com/gpu_assets/Stream_Computing_User_Guide.pdf
 
568
// ?? why don't they have HTML docs??
 
569
 
 
570
#ifdef _WIN32
 
571
typedef int (__stdcall *ATI_ATTRIBS) (CALdeviceattribs *attribs, CALuint ordinal);
 
572
typedef int (__stdcall *ATI_CLOSE)(void);
 
573
typedef int (__stdcall *ATI_GDC)(CALuint *numDevices);
 
574
typedef int (__stdcall *ATI_GDI)(void);
 
575
typedef int (__stdcall *ATI_INFO) (CALdeviceinfo *info, CALuint ordinal);
 
576
typedef int (__stdcall *ATI_VER) (CALuint *cal_major, CALuint *cal_minor, CALuint *cal_imp);
 
577
typedef int (__stdcall *ATI_STATUS) (CALdevicestatus*, CALdevice);
 
578
typedef int (__stdcall *ATI_DEVICEOPEN) (CALdevice*, CALuint);
 
579
typedef int (__stdcall *ATI_DEVICECLOSE) (CALdevice);
 
580
 
 
581
ATI_ATTRIBS __calDeviceGetAttribs = NULL;
 
582
ATI_CLOSE   __calShutdown = NULL;
 
583
ATI_GDC     __calDeviceGetCount = NULL;
 
584
ATI_GDI     __calInit = NULL;
 
585
ATI_INFO    __calDeviceGetInfo = NULL;
 
586
ATI_VER     __calGetVersion = NULL;
 
587
ATI_STATUS  __calDeviceGetStatus = NULL;
 
588
ATI_DEVICEOPEN  __calDeviceOpen = NULL;
 
589
ATI_DEVICECLOSE  __calDeviceClose = NULL;
 
590
 
 
591
#else
 
592
 
 
593
int (*__calInit)();
 
594
int (*__calGetVersion)(CALuint*, CALuint*, CALuint*);
 
595
int (*__calDeviceGetCount)(CALuint*);
 
596
int (*__calDeviceGetAttribs)(CALdeviceattribs*, CALuint);
 
597
int (*__calShutdown)();
 
598
int (*__calDeviceGetInfo)(CALdeviceinfo*, CALuint);
 
599
int (*__calDeviceGetStatus)(CALdevicestatus*, CALdevice);
 
600
int (*__calDeviceOpen)(CALdevice*, CALuint);
 
601
int (*__calDeviceClose)(CALdevice);
 
602
 
 
603
#endif
 
604
 
 
605
void COPROC_ATI::get(COPROCS& coprocs,
 
606
    vector<string>& descs, vector<string>& warnings, vector<int>& ignore_devs
 
607
) {
 
608
    CALuint numDevices, cal_major, cal_minor, cal_imp;
 
609
    CALdevice device;
 
610
    CALdeviceinfo info;
 
611
    CALdeviceattribs attribs;
 
612
    char buf[256];
 
613
    bool amdrt_detected = false;
 
614
    bool atirt_detected = false;
 
615
    int retval;
 
616
 
 
617
    attribs.struct_size = sizeof(CALdeviceattribs);
 
618
    device = 0;
 
619
    numDevices =0;
 
620
 
 
621
#ifdef _WIN32
 
622
 
 
623
#if defined _M_X64
 
624
    const char* atilib_name = "aticalrt64.dll";
 
625
    const char* amdlib_name = "amdcalrt64.dll";
 
626
#else
 
627
    const char* atilib_name = "aticalrt.dll";
 
628
    const char* amdlib_name = "amdcalrt.dll";
 
629
#endif
 
630
 
 
631
    HINSTANCE callib = LoadLibrary(atilib_name);
 
632
    if (callib) {
 
633
        atirt_detected = true;
 
634
    } else {
 
635
        callib = LoadLibrary(amdlib_name);
 
636
        if (callib) {
 
637
            amdrt_detected = true;
 
638
        }
 
639
    }
 
640
 
 
641
    if (!callib) {
 
642
        warnings.push_back("No ATI library found.");
 
643
        return;
 
644
    }
 
645
 
 
646
    __calInit = (ATI_GDI)GetProcAddress(callib, "calInit" );
 
647
    __calGetVersion = (ATI_VER)GetProcAddress(callib, "calGetVersion" );
 
648
    __calDeviceGetCount = (ATI_GDC)GetProcAddress(callib, "calDeviceGetCount" );
 
649
    __calDeviceGetAttribs =(ATI_ATTRIBS)GetProcAddress(callib, "calDeviceGetAttribs" );
 
650
    __calShutdown = (ATI_CLOSE)GetProcAddress(callib, "calShutdown" );
 
651
    __calDeviceGetInfo = (ATI_INFO)GetProcAddress(callib, "calDeviceGetInfo" );
 
652
    __calDeviceGetStatus = (ATI_STATUS)GetProcAddress(callib, "calDeviceGetStatus" );
 
653
    __calDeviceOpen = (ATI_DEVICEOPEN)GetProcAddress(callib, "calDeviceOpen" );
 
654
    __calDeviceClose = (ATI_DEVICECLOSE)GetProcAddress(callib, "calDeviceClose" );
 
655
 
 
656
#else
 
657
 
 
658
    void* callib;
 
659
 
 
660
    callib = dlopen("libaticalrt.so", RTLD_NOW);
 
661
    if (!callib) {
 
662
        warnings.push_back("No ATI library found");
 
663
        return;
 
664
    }
 
665
 
 
666
    atirt_detected = true;
 
667
 
 
668
    __calInit = (int(*)()) dlsym(callib, "calInit");
 
669
    __calGetVersion = (int(*)(CALuint*, CALuint*, CALuint*)) dlsym(callib, "calGetVersion");
 
670
    __calDeviceGetCount = (int(*)(CALuint*)) dlsym(callib, "calDeviceGetCount");
 
671
    __calDeviceGetAttribs = (int(*)(CALdeviceattribs*, CALuint)) dlsym(callib, "calDeviceGetAttribs");
 
672
    __calShutdown = (int(*)()) dlsym(callib, "calShutdown");
 
673
    __calDeviceGetInfo = (int(*)(CALdeviceinfo*, CALuint)) dlsym(callib, "calDeviceGetInfo");
 
674
    __calDeviceGetStatus = (int(*)(CALdevicestatus*, CALdevice)) dlsym(callib, "calDeviceGetStatus");
 
675
    __calDeviceOpen = (int(*)(CALdevice*, CALuint)) dlsym(callib, "calDeviceOpen");
 
676
    __calDeviceClose = (int(*)(CALdevice)) dlsym(callib, "calDeviceClose");
 
677
 
 
678
#endif
 
679
 
 
680
    if (!__calInit) {
 
681
        warnings.push_back("calInit() missing from CAL library");
 
682
        return;
 
683
    }
 
684
    if (!__calGetVersion) {
 
685
        warnings.push_back("calGetVersion() missing from CAL library");
 
686
        return;
 
687
    }
 
688
    if (!__calDeviceGetCount) {
 
689
        warnings.push_back("calDeviceGetCount() missing from CAL library");
 
690
        return;
 
691
    }
 
692
    if (!__calDeviceGetAttribs) {
 
693
        warnings.push_back("calDeviceGetAttribs() missing from CAL library");
 
694
        return;
 
695
    }
 
696
    if (!__calDeviceGetInfo) {
 
697
        warnings.push_back("calDeviceGetInfo() missing from CAL library");
 
698
        return;
 
699
    }
 
700
    if (!__calDeviceGetStatus) {
 
701
        warnings.push_back("calDeviceGetStatus() missing from CAL library");
 
702
        return;
 
703
    }
 
704
    if (!__calDeviceOpen) {
 
705
        warnings.push_back("calDeviceOpen() missing from CAL library");
 
706
        return;
 
707
    }
 
708
    if (!__calDeviceClose) {
 
709
        warnings.push_back("calDeviceClose() missing from CAL library");
 
710
        return;
 
711
    }
 
712
 
 
713
    retval = (*__calInit)();
 
714
    if (retval != CAL_RESULT_OK) {
 
715
        sprintf(buf, "calInit() returned %d", retval);
 
716
        warnings.push_back(buf);
 
717
        return;
 
718
    }
 
719
    retval = (*__calDeviceGetCount)(&numDevices);
 
720
    if (retval != CAL_RESULT_OK) {
 
721
        sprintf(buf, "calDeviceGetCount() returned %d", retval);
 
722
        warnings.push_back(buf);
 
723
        return;
 
724
    }
 
725
    retval = (*__calGetVersion)(&cal_major, &cal_minor, &cal_imp);
 
726
    if (retval != CAL_RESULT_OK) {
 
727
        sprintf(buf, "calGetVersion() returned %d", retval);
 
728
        warnings.push_back(buf);
 
729
        return;
 
730
    }
 
731
 
 
732
    if (!numDevices) {
 
733
        warnings.push_back("No usable CAL devices found");
 
734
        return;
 
735
    }
 
736
 
 
737
    COPROC_ATI cc, cc2;
 
738
    string s, gpu_name;
 
739
    vector<COPROC_ATI> gpus;
 
740
    for (CALuint i=0; i<numDevices; i++) {
 
741
        retval = (*__calDeviceGetInfo)(&info, i);
 
742
        if (retval != CAL_RESULT_OK) {
 
743
            sprintf(buf, "calDeviceGetInfo() returned %d", retval);
 
744
            warnings.push_back(buf);
 
745
            return;
 
746
        }
 
747
        retval = (*__calDeviceGetAttribs)(&attribs, i);
 
748
        if (retval != CAL_RESULT_OK) {
 
749
            sprintf(buf, "calDeviceGetAttribs() returned %d", retval);
 
750
            warnings.push_back(buf);
 
751
            return;
 
752
        }
 
753
        switch ((int)attribs.target) {
 
754
        case CAL_TARGET_600:
 
755
            gpu_name="ATI Radeon HD 2900 (RV600)";
 
756
            break;
 
757
        case CAL_TARGET_610:
 
758
            gpu_name="ATI Radeon HD 2300/2400/3200 (RV610)";
 
759
            attribs.numberOfSIMD=1;        // set correct values (reported wrong by driver)
 
760
            attribs.wavefrontSize=32;
 
761
            break;
 
762
        case CAL_TARGET_630:
 
763
            gpu_name="ATI Radeon HD 2600 (RV630)";
 
764
            // set correct values (reported wrong by driver)
 
765
            attribs.numberOfSIMD=3;
 
766
            attribs.wavefrontSize=32;
 
767
            break;
 
768
        case CAL_TARGET_670:
 
769
            gpu_name="ATI Radeon HD 3800 (RV670)";
 
770
            break;
 
771
        case CAL_TARGET_710:
 
772
            gpu_name="ATI Radeon HD 4350/4550 (R710)";
 
773
            break;
 
774
        case CAL_TARGET_730:
 
775
            gpu_name="ATI Radeon HD 4600 series (R730)";
 
776
            break;
 
777
        case CAL_TARGET_7XX:
 
778
            gpu_name="ATI Radeon (RV700 class)";
 
779
            break;
 
780
        case CAL_TARGET_770:
 
781
            gpu_name="ATI Radeon HD 4700/4800 (RV740/RV770)";
 
782
            break;
 
783
        case 8:
 
784
            gpu_name="ATI Radeon HD5800 series (Cypress)";
 
785
            break;
 
786
        case 9:
 
787
            gpu_name="ATI Radeon HD5700 series (Juniper)";
 
788
            break;
 
789
        case 10:
 
790
            gpu_name="ATI Radeon HD5x00 series (Redwood)";
 
791
            break;
 
792
        case 11:
 
793
            gpu_name="ATI Radeon HD5x00 series (Cedar)";
 
794
            break;
 
795
        default:
 
796
            gpu_name="ATI unknown";
 
797
            break;
 
798
        }
 
799
        cc.attribs = attribs;
 
800
        cc.info = info;
 
801
        strcpy(cc.name, gpu_name.c_str());
 
802
        sprintf(cc.version, "%d.%d.%d", cal_major, cal_minor, cal_imp);
 
803
        cc.amdrt_detected = amdrt_detected;
 
804
        cc.atirt_detected = atirt_detected;
 
805
        cc.device_num = i;
 
806
        gpus.push_back(cc);
 
807
    }
 
808
 
 
809
    // TODO: count only GPUs with as much memory as fastest one,
 
810
    // same as for NVIDIA
 
811
 
 
812
    COPROC_ATI best;
 
813
    bool first = true;
 
814
    for (unsigned int i=0; i<gpus.size(); i++) {
 
815
        char buf[256], buf2[256];
 
816
        gpus[i].description(buf);
 
817
        if (in_vector(gpus[i].device_num, ignore_devs)) {
 
818
            sprintf(buf2, "ATI GPU %d (ignored by config): %s", gpus[i].device_num, buf);
 
819
        } else {
 
820
            if (first) {
 
821
                best = gpus[i];
 
822
                first = false;
 
823
            } else if (gpus[i].peak_flops() > best.peak_flops()) {
 
824
                best = gpus[i];
 
825
            }
 
826
            sprintf(buf2, "ATI GPU %d: %s", gpus[i].device_num, buf);
 
827
        }
 
828
        descs.push_back(buf2);
 
829
    }
 
830
    best.count = 0;
 
831
    for (unsigned int i=0; i<gpus.size(); i++) {
 
832
        if (in_vector(gpus[i].device_num, ignore_devs)) continue;
 
833
        best.device_nums[best.count] = i;
 
834
        best.count++;
 
835
    }
 
836
 
 
837
    COPROC_ATI* ccp = new COPROC_ATI;
 
838
    *ccp = best;
 
839
    strcpy(ccp->type, "ATI");
 
840
    coprocs.coprocs.push_back(ccp);
 
841
 
 
842
    // shut down, otherwise Lenovo won't be able to switch to low-power GPU
 
843
    //
 
844
    retval = (*__calShutdown)();
 
845
}
 
846
 
 
847
COPROC_ATI* fake_ati(COPROCS& coprocs, double ram, int count) {
 
848
    COPROC_ATI* cc = new COPROC_ATI;
 
849
    strcpy(cc->type, "ATI");
 
850
    strcpy(cc->version, "1.4.3");
 
851
    strcpy(cc->name, "foobar");
 
852
    cc->count = count;
 
853
    memset(&cc->attribs, 0, sizeof(cc->attribs));
 
854
    memset(&cc->info, 0, sizeof(cc->info));
 
855
    cc->attribs.localRAM = (int)(ram/MEGA);
 
856
    cc->attribs.numberOfSIMD = 32;
 
857
    cc->attribs.wavefrontSize = 32;
 
858
    cc->attribs.engineClock = 50;
 
859
    for (int i=0; i<count; i++) {
 
860
        cc->device_nums[i] = i;
 
861
    }
 
862
    coprocs.coprocs.push_back(cc);
 
863
    return cc;
 
864
}
 
865
 
 
866
void COPROC_ATI::get_available_ram() {
 
867
#ifdef MEASURE_AVAILABLE_RAM
 
868
    CALdevicestatus st;
 
869
    CALdevice dev;
 
870
    int i, retval;
 
871
 
 
872
    st.struct_size = sizeof(CALdevicestatus);
 
873
 
 
874
    // avoid crash if faked GPU
 
875
    if (!__calInit) {
 
876
        for (i=0; i<count; i++) {
 
877
            available_ram[i] = available_ram_fake[i];
 
878
            available_ram_unknown[i] = false;
 
879
        }
 
880
        return;
 
881
    }
 
882
    for (i=0; i<count; i++) {
 
883
        available_ram[i] = 0;
 
884
        available_ram_unknown[i] = true;
 
885
    }
 
886
    retval = (*__calInit)();
 
887
    if (retval) {
 
888
        if (log_flags.coproc_debug) {
 
889
            msg_printf(0, MSG_INFO,
 
890
                "[coproc] calInit() returned %d", retval
 
891
            );
 
892
        }
 
893
        return;
 
894
    }
 
895
 
 
896
    for (i=0; i<count; i++) {
 
897
        int devnum = device_nums[i];
 
898
        retval = (*__calDeviceOpen)(&dev, devnum);
 
899
        if (retval) {
 
900
            if (log_flags.coproc_debug) {
 
901
                msg_printf(0, MSG_INFO,
 
902
                    "[coproc] calDeviceOpen(%d) returned %d", devnum, retval
 
903
                );
 
904
            }
 
905
            continue;
 
906
        }
 
907
        retval = (*__calDeviceGetStatus)(&st, dev);
 
908
        if (retval) {
 
909
            if (log_flags.coproc_debug) {
 
910
                msg_printf(0, MSG_INFO,
 
911
                    "[coproc] calDeviceGetStatus(%d) returned %d",
 
912
                    devnum, retval
 
913
                );
 
914
            }
 
915
            (*__calDeviceClose)(dev);
 
916
            continue;
 
917
        }
 
918
        available_ram[i] = st.availLocalRAM*MEGA;
 
919
        available_ram_unknown[i] = false;
 
920
        (*__calDeviceClose)(dev);
 
921
    }
 
922
    (*__calShutdown)();
 
923
#else
 
924
    for (int i=0; i<count; i++) {
 
925
        available_ram_unknown[i] = false;
 
926
        available_ram[i] = attribs.localRAM*MEGA;
 
927
    }
 
928
#endif
 
929
}