// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 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 .
#ifndef _USING_FCGI_
#include "boinc_fcgi.h"
#else
#include
#endif
#include
#include
#ifdef _WIN32
#ifndef SIM
#include
#endif
#else
#ifdef __APPLE__
// Suppress obsolete warning when building for OS 10.3.9
#define DLOPEN_NO_WARN
#endif
#include
#endif
#include "error_numbers.h"
#include "filesys.h"
#include "parse.h"
#include "str_util.h"
#include "coproc.h"
using std::string;
using std::vector;
#ifndef _USING_FCGI_
using std::perror;
#endif
#ifndef _USING_FCGI_
void COPROC::write_xml(MIOFILE& f) {
f.printf(
"\n"
" %s\n"
" %d\n"
"\n",
type, count
);
}
#endif
int COPROC_REQ::parse(MIOFILE& fin) {
char buf[1024];
strcpy(type, "");
count = 0;
while (fin.fgets(buf, sizeof(buf))) {
if (match_tag(buf, "")) {
if (!strlen(type)) return ERR_XML_PARSE;
return 0;
}
if (parse_str(buf, "", type, sizeof(type))) continue;
if (parse_double(buf, "", count)) continue;
}
return ERR_XML_PARSE;
}
int COPROC::parse(MIOFILE& fin) {
char buf[1024];
strcpy(type, "");
count = 0;
used = 0;
req_secs = 0;
estimated_delay = 0;
req_instances = 0;
while (fin.fgets(buf, sizeof(buf))) {
if (match_tag(buf, "")) {
if (!strlen(type)) return ERR_XML_PARSE;
return 0;
}
if (parse_str(buf, "", type, sizeof(type))) continue;
if (parse_int(buf, "", count)) continue;
if (parse_double(buf, "", req_secs)) continue;
if (parse_double(buf, "", req_instances)) continue;
if (parse_double(buf, "", estimated_delay)) continue;
}
return ERR_XML_PARSE;
}
void COPROCS::summary_string(char* buf, int len) {
char bigbuf[8192], buf2[1024];
strcpy(bigbuf, "");
for (unsigned int i=0; itype, "CUDA")) {
COPROC_CUDA* cp2 = (COPROC_CUDA*) cp;
int mem = (int)(cp2->prop.dtotalGlobalMem/MEGA);
sprintf(buf2, "[CUDA|%s|%d|%dMB|%d]",
cp2->prop.name, cp2->count, mem, cp2->display_driver_version
);
strcat(bigbuf, buf2);
} else if (!strcmp(cp->type, "CAL")){
COPROC_ATI* cp2 =(COPROC_ATI*) cp;
sprintf(buf2,"[CAL|%s|%d|%dMB|%s]",
cp2->name, cp2->count, cp2->attribs.localRAM, cp2->version
);
strcat(bigbuf,buf2);
}
}
bigbuf[len-1] = 0;
strcpy(buf, bigbuf);
}
void COPROCS::get(bool use_all, vector&descs, vector&warnings) {
COPROC_CUDA::get(*this, use_all, descs, warnings);
#ifndef __APPLE__ // ATI does not yet support CAL on Macs
COPROC_ATI::get(*this, descs, warnings);
#endif
}
// used only to parse scheduler request messages
//
int COPROCS::parse(FILE* fin) {
char buf[1024];
while (fgets(buf, sizeof(buf), fin)) {
if (match_tag(buf, "")) {
return 0;
}
if (strstr(buf, "")) {
COPROC_CUDA* cc = new COPROC_CUDA;
int retval = cc->parse(fin);
if (!retval) {
coprocs.push_back(cc);
}
}
if (strstr(buf, "")) {
COPROC_ATI* cc = new COPROC_ATI;
int retval = cc->parse(fin);
if (!retval) {
coprocs.push_back(cc);
}
}
}
return ERR_XML_PARSE;
}
COPROC* COPROCS::lookup(const char* type) {
for (unsigned int i=0; itype)) return cp;
}
return NULL;
}
#ifdef _WIN32
#endif
// return 1/-1/0 if device 1 is more/less/same capable than device 2.
// If "loose", ignore FLOPS and tolerate small memory diff
//
int cuda_compare(COPROC_CUDA& c1, COPROC_CUDA& c2, bool loose) {
if (c1.prop.major > c2.prop.major) return 1;
if (c1.prop.major < c2.prop.major) return -1;
if (c1.prop.minor > c2.prop.minor) return 1;
if (c1.prop.minor < c2.prop.minor) return -1;
if (c1.cuda_version > c2.cuda_version) return 1;
if (c1.cuda_version < c2.cuda_version) return -1;
if (loose) {
if (c1.prop.totalGlobalMem > 1.4*c2.prop.totalGlobalMem) return 1;
if (c1.prop.totalGlobalMem < .7* c2.prop.totalGlobalMem) return -1;
return 0;
}
if (c1.prop.totalGlobalMem > c2.prop.totalGlobalMem) return 1;
if (c1.prop.totalGlobalMem < c2.prop.totalGlobalMem) return -1;
double s1 = c1.flops_estimate();
double s2 = c2.flops_estimate();
if (s1 > s2) return 1;
if (s1 < s2) return -1;
return 0;
}
#ifdef _WIN32
typedef int (__stdcall *CUDA_GDC)(int *count);
typedef int (__stdcall *CUDA_GDP)(struct cudaDeviceProp *prop, int device);
typedef int (__stdcall *CUDA_GDV)(int* version);
typedef int (__stdcall *CUDA_GDI)(int);
typedef int (__stdcall *CUDA_GDG)(int*, int);
typedef int (__stdcall *CUDA_GDA)(int*, int, int);
typedef int (__stdcall *CUDA_GDN)(char*, int, int);
typedef int (__stdcall *CUDA_GDM)(unsigned int*, int);
typedef int (__stdcall *CUDA_GDCC)(int*, int*, int);
CUDA_GDC __cuDeviceGetCount = NULL;
//CUDA_GDP __cuDeviceGetProperties = NULL;
CUDA_GDV __cuDriverGetVersion = NULL;
CUDA_GDI __cuInit = NULL;
CUDA_GDG __cuDeviceGet = NULL;
CUDA_GDA __cuDeviceGetAttribute = NULL;
CUDA_GDN __cuDeviceGetName = NULL;
CUDA_GDM __cuDeviceTotalMem = NULL;
CUDA_GDCC __cuDeviceComputeCapability = NULL;
#else
void* cudalib;
int (*__cuInit)(int);
int (*__cuDeviceGetCount)(int*);
//int (*__cuDeviceGetProperties)(cudaDeviceProp*, int);
int (*__cuDriverGetVersion)(int*);
int (*__cuDeviceGet)(int*, int);
int (*__cuDeviceGetAttribute)(int*, int, int);
int (*__cuDeviceGetName)(char*, int, int);
int (*__cuDeviceTotalMem)(unsigned int*, int);
int (*__cuDeviceComputeCapability)(int*, int*, int);
#endif
// NVIDIA interfaces are documented here:
// http://developer.download.nvidia.com/compute/cuda/2_3/toolkit/docs/online/index.html
void COPROC_CUDA::get(
COPROCS& coprocs,
bool use_all, // if false, use only those equivalent to most capable
vector& descs,
vector& warnings
) {
int count, retval;
char buf[256];
#ifdef _WIN32
HMODULE cudalib = LoadLibrary("nvcuda.dll");
if (!cudalib) {
warnings.push_back("No NVIDIA library found");
return;
}
__cuDeviceGetCount = (CUDA_GDC)GetProcAddress(cudalib, "cuDeviceGetCount");
//__cuDeviceGetProperties = (CUDA_GDP)GetProcAddress(cudalib, "cuDeviceGetProperties");
__cuDriverGetVersion = (CUDA_GDV)GetProcAddress(cudalib, "cuDriverGetVersion" );
__cuInit = (CUDA_GDI)GetProcAddress(cudalib, "cuInit" );
__cuDeviceGet = (CUDA_GDG)GetProcAddress(cudalib, "cuDeviceGet" );
__cuDeviceGetAttribute = (CUDA_GDA)GetProcAddress(cudalib, "cuDeviceGetAttribute" );
__cuDeviceGetName = (CUDA_GDN)GetProcAddress(cudalib, "cuDeviceGetName" );
__cuDeviceTotalMem = (CUDA_GDM)GetProcAddress(cudalib, "cuDeviceTotalMem" );
__cuDeviceComputeCapability = (CUDA_GDCC)GetProcAddress(cudalib, "cuDeviceComputeCapability" );
#ifndef SIM
NvAPI_Status nvapiStatus;
NvDisplayHandle hDisplay;
NV_DISPLAY_DRIVER_VERSION Version;
memset(&Version, 0, sizeof(Version));
Version.version = NV_DISPLAY_DRIVER_VERSION_VER;
NvAPI_Initialize();
for (int i=0; ; i++) {
nvapiStatus = NvAPI_EnumNvidiaDisplayHandle(i, &hDisplay);
if (nvapiStatus != NVAPI_OK) break;
nvapiStatus = NvAPI_GetDisplayDriverVersion(hDisplay, &Version);
if (nvapiStatus == NVAPI_OK) break;
}
#endif
#else
#ifdef __APPLE__
cudalib = dlopen("/usr/local/cuda/lib/libcuda.dylib", RTLD_NOW);
#else
cudalib = dlopen("libcuda.so", RTLD_NOW);
#endif
if (!cudalib) {
warnings.push_back("No NVIDIA library found");
return;
}
__cuDeviceGetCount = (int(*)(int*)) dlsym(cudalib, "cuDeviceGetCount");
//__cuDeviceGetProperties = (int(*)(cudaDeviceProp*, int)) dlsym( cudalib, "cuDeviceGetProperties" );
__cuDriverGetVersion = (int(*)(int*)) dlsym( cudalib, "cuDriverGetVersion" );
__cuInit = (int(*)(int)) dlsym( cudalib, "cuInit" );
__cuDeviceGet = (int(*)(int*, int)) dlsym( cudalib, "cuDeviceGet" );
__cuDeviceGetAttribute = (int(*)(int*, int, int)) dlsym( cudalib, "cuDeviceGetAttribute" );
__cuDeviceGetName = (int(*)(char*, int, int)) dlsym( cudalib, "cuDeviceGetName" );
__cuDeviceTotalMem = (int(*)(unsigned int*, int)) dlsym( cudalib, "cuDeviceTotalMem" );
__cuDeviceComputeCapability = (int(*)(int*, int*, int)) dlsym( cudalib, "cuDeviceComputeCapability" );
#endif
if (!__cuDriverGetVersion) {
warnings.push_back("cuDriverGetVersion() missing from NVIDIA library");
return;
}
if (!__cuInit) {
warnings.push_back("cuInit() missing from NVIDIA library");
return;
}
if (!__cuDeviceGetCount) {
warnings.push_back("cuDeviceGetCount() missing from NVIDIA library");
return;
}
if (!__cuDeviceGet) {
warnings.push_back("cuDeviceGet() missing from NVIDIA library");
return;
}
if (!__cuDeviceGetAttribute) {
warnings.push_back("cuDeviceGetAttribute() missing from NVIDIA library");
return;
}
if (!__cuDeviceTotalMem) {
warnings.push_back("cuDeviceTotalMem() missing from NVIDIA library");
return;
}
if (!__cuDeviceComputeCapability) {
warnings.push_back("cuDeviceComputeCapability() missing from NVIDIA library");
return;
}
retval = (*__cuInit)(0);
if (retval) {
sprintf(buf, "cuInit() returned %d", retval);
warnings.push_back(buf);
return;
}
int cuda_version;
retval = (*__cuDriverGetVersion)(&cuda_version);
if (retval) {
sprintf(buf, "cuDriverGetVersion() returned %d", retval);
warnings.push_back(buf);
return;
}
vector gpus;
retval = (*__cuDeviceGetCount)(&count);
if (retval) {
sprintf(buf, "cuDeviceGetCount() returned %d", retval);
warnings.push_back(buf);
return;
}
int j;
unsigned int i;
COPROC_CUDA cc;
string s;
for (j=0; j 100) continue; // e.g. 9999 is an error
#if defined(_WIN32) && !defined(SIM)
cc.display_driver_version = Version.drvVersion;
#else
cc.display_driver_version = 0;
#endif
cc.cuda_version = cuda_version;
cc.device_num = j;
gpus.push_back(cc);
}
if (!gpus.size()) {
warnings.push_back("No CUDA-capable NVIDIA GPUs found");
return;
}
// identify the most capable instance
//
COPROC_CUDA best;
for (i=0; i 0) {
best = gpus[i];
}
}
// see which other instances are equivalent,
// and set the "count" and "device_nums" fields
//
best.count = 0;
for (i=0; itype, "CUDA");
cc->count = count;
for (int i=0; idevice_nums[i] = i;
}
cc->display_driver_version = 18000;
cc->cuda_version = 2020;
strcpy(cc->prop.name, "Fake NVIDIA GPU");
cc->prop.totalGlobalMem = 256*1024*1024;
cc->prop.sharedMemPerBlock = 100;
cc->prop.regsPerBlock = 8;
cc->prop.warpSize = 10;
cc->prop.memPitch = 10;
cc->prop.maxThreadsPerBlock = 20;
cc->prop.maxThreadsDim[0] = 2;
cc->prop.maxThreadsDim[1] = 2;
cc->prop.maxThreadsDim[2] = 2;
cc->prop.maxGridSize[0] = 10;
cc->prop.maxGridSize[1] = 10;
cc->prop.maxGridSize[2] = 10;
cc->prop.totalConstMem = 10;
cc->prop.major = 1;
cc->prop.minor = 2;
cc->prop.clockRate = 1250000;
cc->prop.textureAlignment = 1000;
cc->prop.multiProcessorCount = 14;
coprocs.coprocs.push_back(cc);
}
#ifndef _USING_FCGI_
void COPROC_CUDA::write_xml(MIOFILE& f) {
f.printf(
"\n"
" %d\n"
" %s\n"
" %f\n"
" %f\n"
" %f\n"
" %d\n"
" %d\n"
" %u\n"
" %u\n"
" %d\n"
" %d\n"
" %u\n"
" %d\n"
" %d %d %d\n"
" %d %d %d\n"
" %u\n"
" %d\n"
" %d\n"
" %d\n"
" %u\n"
" %d\n"
" %d\n"
"\n",
count,
prop.name,
req_secs,
req_instances,
estimated_delay,
display_driver_version,
cuda_version,
(unsigned int)prop.totalGlobalMem,
(unsigned int)prop.sharedMemPerBlock,
prop.regsPerBlock,
prop.warpSize,
(unsigned int)prop.memPitch,
prop.maxThreadsPerBlock,
prop.maxThreadsDim[0], prop.maxThreadsDim[1], prop.maxThreadsDim[2],
prop.maxGridSize[0], prop.maxGridSize[1], prop.maxGridSize[2],
(unsigned int)prop.totalConstMem,
prop.major,
prop.minor,
prop.clockRate,
(unsigned int)prop.textureAlignment,
prop.deviceOverlap,
prop.multiProcessorCount
);
}
#endif
void COPROC_CUDA::clear() {
count = 0;
used = 0;
req_secs = 0;
req_instances = 0;
estimated_delay = -1; // mark as absent
cuda_version = 0;
display_driver_version = 0;
strcpy(prop.name, "");
prop.totalGlobalMem = 0;
prop.sharedMemPerBlock = 0;
prop.regsPerBlock = 0;
prop.warpSize = 0;
prop.memPitch = 0;
prop.maxThreadsPerBlock = 0;
prop.maxThreadsDim[0] = 0;
prop.maxThreadsDim[1] = 0;
prop.maxThreadsDim[2] = 0;
prop.maxGridSize[0] = 0;
prop.maxGridSize[1] = 0;
prop.maxGridSize[2] = 0;
prop.clockRate = 0;
prop.totalConstMem = 0;
prop.major = 0;
prop.minor = 0;
prop.textureAlignment = 0;
prop.deviceOverlap = 0;
prop.multiProcessorCount = 0;
}
int COPROC_CUDA::parse(FILE* fin) {
char buf[1024], buf2[256];
clear();
while (fgets(buf, sizeof(buf), fin)) {
if (strstr(buf, "")) {
return 0;
}
if (parse_int(buf, "", count)) continue;
if (parse_double(buf, "", req_secs)) continue;
if (parse_double(buf, "", req_instances)) continue;
if (parse_double(buf, "", estimated_delay)) continue;
if (parse_str(buf, "", prop.name, sizeof(prop.name))) continue;
if (parse_int(buf, "", display_driver_version)) continue;
if (parse_int(buf, "", cuda_version)) continue;
if (parse_double(buf, "", prop.dtotalGlobalMem)) continue;
if (parse_int(buf, "", (int&)prop.sharedMemPerBlock)) continue;
if (parse_int(buf, "", prop.regsPerBlock)) continue;
if (parse_int(buf, "", prop.warpSize)) continue;
if (parse_int(buf, "", (int&)prop.memPitch)) continue;
if (parse_int(buf, "", prop.maxThreadsPerBlock)) continue;
if (parse_str(buf, "", buf2, sizeof(buf2))) {
// can't use sscanf here (FCGI)
//
prop.maxThreadsDim[0] = atoi(buf2);
char* p = strchr(buf2, ' ');
if (p) {
p++;
prop.maxThreadsDim[1] = atoi(p);
p = strchr(p, ' ');
if (p) {
p++;
prop.maxThreadsDim[2] = atoi(p);
}
}
continue;
}
if (parse_str(buf, "", buf2, sizeof(buf2))) {
prop.maxGridSize[0] = atoi(buf2);
char* p = strchr(buf2, ' ');
if (p) {
p++;
prop.maxGridSize[1] = atoi(p);
p = strchr(p, ' ');
if (p) {
p++;
prop.maxGridSize[2] = atoi(p);
}
}
continue;
}
if (parse_int(buf, "", prop.clockRate)) continue;
if (parse_int(buf, "", (int&)prop.totalConstMem)) continue;
if (parse_int(buf, "", prop.major)) continue;
if (parse_int(buf, "", prop.minor)) continue;
if (parse_int(buf, "", (int&)prop.textureAlignment)) continue;
if (parse_int(buf, "", prop.deviceOverlap)) continue;
if (parse_int(buf, "", prop.multiProcessorCount)) continue;
}
return ERR_XML_PARSE;
}
// check whether each GPU is running a graphics app (assume yes)
// return true if there's been a change since last time
//
bool COPROC_CUDA::check_running_graphics_app() {
int retval, j;
bool change = false;
for (j=0; j& descs, vector& warnings
) {
CALuint numDevices, cal_major, cal_minor, cal_imp;
CALdevice device;
CALdeviceinfo info;
CALdeviceattribs attribs;
char buf[256];
int retval;
attribs.struct_size = sizeof(CALdeviceattribs);
device = 0;
numDevices =0;
#ifdef _WIN32
#if defined _M_X64
HINSTANCE callib = LoadLibrary("aticalrt64.dll");
#else
HINSTANCE callib = LoadLibrary("aticalrt.dll");
#endif
if (!callib) {
warnings.push_back("No ATI library found.");
return;
}
__calInit = (ATI_GDI)GetProcAddress(callib, "calInit" );
__calDeviceGetCount = (ATI_GDC)GetProcAddress(callib, "calDeviceGetCount" );
__calGetVersion = (ATI_VER)GetProcAddress(callib, "calGetVersion" );
__calDeviceGetInfo = (ATI_INFO)GetProcAddress(callib, "calDeviceGetInfo" );
__calDeviceGetAttribs =(ATI_ATTRIBS)GetProcAddress(callib, "calDeviceGetAttribs" );
__calShutdown = (ATI_CLOSE)GetProcAddress(callib, "calShutdown" );
#else
void* callib;
callib = dlopen("libaticalrt.so", RTLD_NOW);
if (!callib) {
warnings.push_back("No ATI library found");
return;
}
__calInit = (int(*)()) dlsym(callib, "calInit");
__calGetVersion = (int(*)(CALuint*, CALuint*, CALuint*)) dlsym(callib, "calGetVersion");
__calDeviceGetCount = (int(*)(CALuint*)) dlsym(callib, "calDeviceGetCount");
__calDeviceGetAttribs = (int(*)(CALdeviceattribs*, CALuint)) dlsym(callib, "calDeviceGetAttribs");
__calDeviceGetInfo = (int(*)(CALdeviceinfo*, CALuint)) dlsym(callib, "calDeviceGetInfo");
__calShutdown = (int(*)()) dlsym(callib, "calShutdown");
#endif
if (!__calInit) {
warnings.push_back("calInit() missing from CAL library");
return;
}
if (!__calDeviceGetCount) {
warnings.push_back("calDeviceGetCount() missing from CAL library");
return;
}
if (!__calGetVersion) {
warnings.push_back("calGetVersion() missing from CAL library");
return;
}
if (!__calDeviceGetInfo) {
warnings.push_back("calDeviceGetInfo() missing from CAL library");
return;
}
if (!__calDeviceGetAttribs) {
warnings.push_back("calDeviceGetAttribs() missing from CAL library");
return;
}
retval = (*__calInit)();
if (retval != CAL_RESULT_OK) {
sprintf(buf, "calInit() returned %d", retval);
warnings.push_back(buf);
return;
}
retval = (*__calDeviceGetCount)(&numDevices);
if (retval != CAL_RESULT_OK) {
sprintf(buf, "calDeviceGetCount() returned %d", retval);
warnings.push_back(buf);
return;
}
retval = (*__calGetVersion)(&cal_major, &cal_minor, &cal_imp);
if (retval != CAL_RESULT_OK) {
sprintf(buf, "calGetVersion() returned %d", retval);
warnings.push_back(buf);
return;
}
if (!numDevices) {
warnings.push_back("No usable CAL devices found");
return;
}
COPROC_ATI cc, cc2;
string s, gpu_name;
vector gpus;
for (CALuint i=0; i best.flops_estimate()) {
best = gpus[i];
}
gpus[i].description(buf);
sprintf(buf2, "ATI GPU %d: %s", gpus[i].device_num, buf);
descs.push_back(buf2);
}
for (unsigned int i=0; itype, "ATI");
ccp->count = numDevices;
coprocs.coprocs.push_back(ccp);
__calShutdown();
}
#ifndef _USING_FCGI_
void COPROC_ATI::write_xml(MIOFILE& f) {
f.printf(
"\n"
" %d\n"
" %s\n"
" %f\n"
" %f\n"
" %f\n"
" %d\n"
" %d\n"
" %d\n"
" %u\n"
" %d\n"
" %d\n"
" %d\n"
" %d\n"
" %d\n"
" %d\n"
" %s\n"
"\n",
count,
name,
req_secs,
req_instances,
estimated_delay,
attribs.localRAM,
attribs.uncachedRemoteRAM,
attribs.cachedRemoteRAM,
attribs.engineClock,
attribs.memoryClock,
attribs.wavefrontSize,
attribs.numberOfSIMD,
attribs.doublePrecision,
attribs.pitch_alignment,
attribs.surface_alignment,
version
);
};
#endif
void COPROC_ATI::clear() {
count = 0;
used = 0;
req_secs = 0;
req_instances = 0;
estimated_delay = -1;
strcpy(name, "");
strcpy(version, "");
attribs.localRAM = 0;
attribs.uncachedRemoteRAM = 0;
attribs.cachedRemoteRAM = 0;
attribs.engineClock = 0;
attribs.memoryClock = 0;
attribs.wavefrontSize = 0;
attribs.numberOfSIMD = 0;
attribs.doublePrecision = CAL_FALSE;
attribs.pitch_alignment = 0;
attribs.surface_alignment = 0;
}
int COPROC_ATI::parse(FILE* fin) {
char buf[1024];
int n;
clear();
while (fgets(buf, sizeof(buf), fin)) {
if (strstr(buf, "")) return 0;
if (parse_int(buf, "", count)) continue;
if (parse_str(buf, "", name, sizeof(name))) continue;
if (parse_double(buf, "", req_secs)) continue;
if (parse_double(buf, "", req_instances)) continue;
if (parse_double(buf, "", estimated_delay)) continue;
if (parse_int(buf, "", n)) {
attribs.localRAM = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.uncachedRemoteRAM = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.cachedRemoteRAM = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.engineClock = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.memoryClock = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.wavefrontSize = n;
continue;
}
if (parse_int(buf, "" , n)) {
attribs.numberOfSIMD = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.doublePrecision = n?CAL_TRUE:CAL_FALSE;
continue;
}
if (parse_int(buf, "", n)) {
attribs.pitch_alignment = n;
continue;
}
if (parse_int(buf, "", n)) {
attribs.surface_alignment = n;
continue;
}
if (parse_str(buf, "", version, sizeof(version))) continue;
}
return ERR_XML_PARSE;
}
void COPROC_ATI::description(char* buf) {
sprintf(buf, "%s (CAL version %s, %.0fMB, %.0fGFLOPS)",
name, version, attribs.localRAM/1024.*1024., flops_estimate()/1.e9
);
}
void fake_ati(COPROCS& coprocs, int count) {
COPROC_ATI* cc = new COPROC_ATI;
strcpy(cc->type, "ATI");
strcpy(cc->version, "1.2.3");
cc->count = count;
cc->attribs.numberOfSIMD = 32;
cc->attribs.wavefrontSize = 32;
cc->attribs.engineClock = 50;
for (int i=0; idevice_nums[i] = i;
}
coprocs.coprocs.push_back(cc);
}