2013-11-19 16:36:00 -05:00
|
|
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* This file is part of the LibreOffice project.
|
|
|
|
*
|
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2013-11-20 18:40:49 +02:00
|
|
|
#include <windows.h>
|
2013-11-20 20:45:05 +02:00
|
|
|
#elif defined __MACH__
|
|
|
|
#include <mach/mach_time.h>
|
2013-11-19 16:36:00 -05:00
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
#include <time.h>
|
|
|
|
#include <math.h>
|
2013-11-19 16:46:29 -05:00
|
|
|
#include <float.h>
|
2013-11-19 16:36:00 -05:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
2013-11-19 19:11:50 -05:00
|
|
|
#include <vector>
|
2013-11-19 19:15:40 -05:00
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
|
|
|
2013-11-19 16:36:00 -05:00
|
|
|
#include "opencl_device.hxx"
|
|
|
|
|
|
|
|
|
2013-11-27 20:47:25 -05:00
|
|
|
#define INPUTSIZE 15360
|
|
|
|
#define OUTPUTSIZE 15360
|
2013-11-19 16:36:00 -05:00
|
|
|
|
|
|
|
#define STRINGIFY(...) #__VA_ARGS__"\n"
|
|
|
|
#define LOG_PRINTF(x) (std::cout << x << std::endl)
|
|
|
|
//#define LOG_PRINTF(x)
|
|
|
|
|
|
|
|
#define DS_CHECK_STATUS(status, name) \
|
|
|
|
if (CL_SUCCESS != status) \
|
|
|
|
{ \
|
|
|
|
LOG_PRINTF("[OCL] Error code is " << status << " at " << name); \
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace sc { namespace OpenCLDevice {
|
|
|
|
|
|
|
|
bool bIsInited = false;
|
|
|
|
bool bIsDeviceSelected = false;
|
|
|
|
ds_device selectedDevice;
|
|
|
|
|
2013-11-19 19:36:24 -05:00
|
|
|
struct LibreOfficeDeviceScore
|
2013-11-19 16:36:00 -05:00
|
|
|
{
|
|
|
|
double fTime; // small time means faster device
|
|
|
|
bool bNoCLErrors; // were there any opencl errors
|
2013-11-19 19:36:24 -05:00
|
|
|
};
|
2013-11-19 16:36:00 -05:00
|
|
|
|
2013-11-19 19:11:50 -05:00
|
|
|
struct LibreOfficeDeviceEvaluationIO
|
2013-11-19 16:36:00 -05:00
|
|
|
{
|
2013-11-19 19:11:50 -05:00
|
|
|
std::vector<double> input0;
|
|
|
|
std::vector<double> input1;
|
|
|
|
std::vector<double> input2;
|
|
|
|
std::vector<double> input3;
|
|
|
|
std::vector<double> output;
|
2013-11-19 16:36:00 -05:00
|
|
|
unsigned long inputSize;
|
|
|
|
unsigned long outputSize;
|
2013-11-19 19:11:50 -05:00
|
|
|
};
|
2013-11-19 16:36:00 -05:00
|
|
|
|
2013-11-19 19:36:24 -05:00
|
|
|
struct timer
|
2013-11-19 16:36:00 -05:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2013-11-20 20:45:05 +02:00
|
|
|
LARGE_INTEGER start;
|
2013-11-19 16:36:00 -05:00
|
|
|
#else
|
2013-11-20 20:45:05 +02:00
|
|
|
long long start;
|
2013-11-19 16:36:00 -05:00
|
|
|
#endif
|
2013-11-19 19:36:24 -05:00
|
|
|
};
|
2013-11-19 16:36:00 -05:00
|
|
|
|
|
|
|
const char* source = STRINGIFY(
|
|
|
|
\n#if defined(KHR_DP_EXTENSION)
|
|
|
|
\n#pragma OPENCL EXTENSION cl_khr_fp64 : enable
|
|
|
|
\n#elif defined(AMD_DP_EXTENSION)
|
|
|
|
\n#pragma OPENCL EXTENSION cl_amd_fp64 : enable
|
|
|
|
\n#endif
|
|
|
|
\n
|
|
|
|
int isNan(fp_t a) { return a != a; }
|
|
|
|
fp_t fsum(fp_t a, fp_t b) { return a + b; }
|
|
|
|
|
|
|
|
fp_t fAverage(__global fp_t* input)
|
|
|
|
{
|
|
|
|
fp_t sum = 0;
|
|
|
|
int count = 0;
|
|
|
|
for (int i = 0; i < INPUTSIZE; i++)
|
|
|
|
{
|
|
|
|
if (!isNan(input[i]))
|
|
|
|
{
|
|
|
|
sum = fsum(input[i], sum);
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sum / (fp_t)count;
|
|
|
|
}
|
|
|
|
fp_t fMin(__global fp_t* input)
|
|
|
|
{
|
|
|
|
fp_t min = MAXFLOAT;
|
|
|
|
for (int i = 0; i < INPUTSIZE; i++)
|
|
|
|
{
|
|
|
|
if (!isNan(input[i]))
|
|
|
|
{
|
|
|
|
min = fmin(input[i], min);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return min;
|
|
|
|
}
|
|
|
|
fp_t fSoP(__global fp_t* input0, __global fp_t* input1)
|
|
|
|
{
|
|
|
|
fp_t sop = 0.0;
|
|
|
|
for (int i = 0; i < INPUTSIZE; i++)
|
|
|
|
{
|
|
|
|
sop += (isNan(input0[i]) ? 0 : input0[i]) * (isNan(input1[i]) ? 0 : input1[i]);
|
|
|
|
}
|
|
|
|
return sop;
|
|
|
|
}
|
|
|
|
__kernel void DynamicKernel(
|
|
|
|
__global fp_t* result, __global fp_t* input0, __global fp_t* input1, __global fp_t* input2, __global fp_t* input3)
|
|
|
|
{
|
|
|
|
int gid0 = get_global_id(0);
|
|
|
|
fp_t tmp0 = fAverage(input0);
|
|
|
|
fp_t tmp1 = fMin(input1) * fSoP(input2, input3);
|
|
|
|
result[gid0] = fsum(tmp0, tmp1);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
size_t sourceSize[] = { strlen(source) };
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* INTERNAL FUNCTIONS */
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Timer functions - start timer */
|
|
|
|
void timerStart(timer* mytimer)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
QueryPerformanceCounter(&mytimer->start);
|
2013-11-20 20:45:05 +02:00
|
|
|
#elif defined __MACH__
|
|
|
|
mytimer->start = mach_absolute_time();
|
2013-11-19 16:36:00 -05:00
|
|
|
#else
|
|
|
|
struct timespec s;
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &s);
|
|
|
|
mytimer->start = (long long)s.tv_sec * (long long)1.0E6 + (long long)s.tv_nsec / (long long)1.0E3;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-11-20 20:59:20 +02:00
|
|
|
/* Timer functions - get current value */
|
|
|
|
double timerCurrent(timer* mytimer)
|
2013-11-19 16:36:00 -05:00
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2013-11-20 20:45:05 +02:00
|
|
|
LARGE_INTEGER stop, frequency;
|
|
|
|
QueryPerformanceCounter(&stop);
|
|
|
|
QueryPerformanceFrequency(&frequency);
|
|
|
|
double time = ((double)(stop.QuadPart - mytimer->start.QuadPart) / frequency.QuadPart);
|
|
|
|
#elif defined __MACH__
|
|
|
|
static mach_timebase_info_data_t info = { 0, 0 };
|
|
|
|
if (info.numer == 0)
|
|
|
|
mach_timebase_info(&info);
|
|
|
|
long long stop = mach_absolute_time();
|
2013-11-20 22:22:43 +02:00
|
|
|
double time = ((stop - mytimer->start) * (double) info.numer / info.denom) / 1.0E9;
|
2013-11-19 16:36:00 -05:00
|
|
|
#else
|
|
|
|
struct timespec s;
|
2013-11-20 20:45:05 +02:00
|
|
|
long long stop;
|
2013-11-19 16:36:00 -05:00
|
|
|
clock_gettime(CLOCK_MONOTONIC, &s);
|
2013-11-20 20:45:05 +02:00
|
|
|
stop = (long long)s.tv_sec * (long long)1.0E6 + (long long)s.tv_nsec / (long long)1.0E3;
|
|
|
|
double time = ((double)(stop - mytimer->start) / 1.0E6);
|
2013-11-19 16:36:00 -05:00
|
|
|
#endif
|
|
|
|
return time;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Random number generator */
|
|
|
|
double random(double min, double max)
|
|
|
|
{
|
|
|
|
return floor(((double)rand() / ((unsigned int)RAND_MAX + 1)) * (max - min + 1) + min);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Populate input */
|
|
|
|
void populateInput(LibreOfficeDeviceEvaluationIO* testData)
|
|
|
|
{
|
|
|
|
srand((unsigned int)time(NULL));
|
2013-11-19 19:11:50 -05:00
|
|
|
double* input0 = &testData->input0[0];
|
|
|
|
double* input1 = &testData->input1[0];
|
|
|
|
double* input2 = &testData->input2[0];
|
|
|
|
double* input3 = &testData->input3[0];
|
2013-11-19 16:36:00 -05:00
|
|
|
for (unsigned long i = 0; i < testData->inputSize; i++)
|
|
|
|
{
|
|
|
|
input0[i] = random(0, i);
|
|
|
|
input1[i] = random(0, i);
|
|
|
|
input2[i] = random(0, i);
|
|
|
|
input3[i] = random(0, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Encode score object as byte string */
|
|
|
|
ds_status serializeScore(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize)
|
|
|
|
{
|
|
|
|
*serializedScoreSize = sizeof(LibreOfficeDeviceScore);
|
|
|
|
*serializedScore = (void*)new unsigned char[*serializedScoreSize];
|
|
|
|
memcpy(*serializedScore, device->score, *serializedScoreSize);
|
|
|
|
return DS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parses byte string and stores in score object */
|
|
|
|
ds_status deserializeScore(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize)
|
|
|
|
{
|
|
|
|
// check that serializedScoreSize == sizeof(LibreOfficeDeviceScore);
|
|
|
|
device->score = new LibreOfficeDeviceScore;
|
|
|
|
memcpy(device->score, serializedScore, serializedScoreSize);
|
|
|
|
return DS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Releases memory held by score */
|
|
|
|
ds_status releaseScore(void* score)
|
|
|
|
{
|
|
|
|
if (NULL != score)
|
|
|
|
{
|
|
|
|
delete (LibreOfficeDeviceScore*)score;
|
|
|
|
}
|
|
|
|
return DS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Evaluate devices */
|
|
|
|
ds_status evaluateScoreForDevice(ds_device* device, void* evalData)
|
|
|
|
{
|
|
|
|
if (DS_DEVICE_OPENCL_DEVICE == device->type)
|
|
|
|
{
|
|
|
|
/* Evaluating an OpenCL device */
|
|
|
|
LOG_PRINTF("[DS] Device: \"" << device->oclDeviceName << "\" (OpenCL) evaluation...");
|
|
|
|
cl_int clStatus;
|
|
|
|
cl_context clContext;
|
|
|
|
cl_command_queue clQueue;
|
|
|
|
cl_program clProgram;
|
|
|
|
cl_kernel clKernel;
|
|
|
|
|
|
|
|
/* Check for 64-bit float extensions */
|
|
|
|
size_t aDevExtInfoSize = 0;
|
|
|
|
clStatus = clGetDeviceInfo(device->oclDeviceID, CL_DEVICE_EXTENSIONS, 0, NULL, &aDevExtInfoSize);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
|
|
|
|
|
|
|
|
char* aExtInfo = new char[aDevExtInfoSize];
|
|
|
|
clStatus = clGetDeviceInfo(device->oclDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo, NULL);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo");
|
|
|
|
|
|
|
|
bool bKhrFp64Flag = false;
|
|
|
|
bool bAmdFp64Flag = false;
|
2013-11-19 16:59:35 -05:00
|
|
|
const char* buildOption = NULL;
|
2013-11-19 16:36:00 -05:00
|
|
|
std::string tmpStr("-Dfp_t=double -Dfp_t4=double4 -Dfp_t16=double16 -DINPUTSIZE=");
|
2013-11-20 21:42:20 +02:00
|
|
|
std::ostringstream tmpOStrStr;
|
|
|
|
tmpOStrStr << std::dec << INPUTSIZE;
|
|
|
|
tmpStr.append(tmpOStrStr.str());
|
2013-11-19 16:36:00 -05:00
|
|
|
|
|
|
|
if ((std::string(aExtInfo)).find("cl_khr_fp64") != std::string::npos)
|
|
|
|
{
|
|
|
|
bKhrFp64Flag = true;
|
|
|
|
//buildOption = "-D KHR_DP_EXTENSION -Dfp_t=double -Dfp_t4=double4 -Dfp_t16=double16";
|
|
|
|
tmpStr.append(" -DKHR_DP_EXTENSION");
|
|
|
|
buildOption = tmpStr.c_str();
|
|
|
|
}
|
|
|
|
else if ((std::string(aExtInfo)).find("cl_amd_fp64") != std::string::npos)
|
|
|
|
{
|
|
|
|
bAmdFp64Flag = true;
|
|
|
|
//buildOption = "-D AMD_DP_EXTENSION -Dfp_t=double -Dfp_t4=double4 -Dfp_t16=double16";
|
|
|
|
tmpStr.append(" -DAMD_DP_EXTENSION");
|
|
|
|
buildOption = tmpStr.c_str();
|
|
|
|
}
|
|
|
|
delete[] aExtInfo;
|
|
|
|
|
|
|
|
if (!bKhrFp64Flag && !bAmdFp64Flag)
|
|
|
|
{
|
|
|
|
/* No 64-bit float support */
|
|
|
|
device->score = (void*)new LibreOfficeDeviceScore;
|
|
|
|
((LibreOfficeDeviceScore*)device->score)->fTime = DBL_MAX;
|
|
|
|
((LibreOfficeDeviceScore*)device->score)->bNoCLErrors = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* 64-bit float support present */
|
|
|
|
|
|
|
|
/* Create context and command queue */
|
|
|
|
clContext = clCreateContext(NULL, 1, &device->oclDeviceID, NULL, NULL, &clStatus);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateContext");
|
|
|
|
clQueue = clCreateCommandQueue(clContext, device->oclDeviceID, 0, &clStatus);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateCommandQueue");
|
|
|
|
|
|
|
|
/* Build program */
|
|
|
|
clProgram = clCreateProgramWithSource(clContext, 1, &source, sourceSize, &clStatus);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateProgramWithSource");
|
|
|
|
clStatus = clBuildProgram(clProgram, 1, &device->oclDeviceID, buildOption, NULL, NULL);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clBuildProgram");
|
|
|
|
if (CL_SUCCESS != clStatus)
|
|
|
|
{
|
|
|
|
/* Build program failed */
|
|
|
|
size_t length;
|
|
|
|
char* buildLog;
|
|
|
|
clStatus = clGetProgramBuildInfo(clProgram, device->oclDeviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &length);
|
|
|
|
buildLog = (char*)malloc(length);
|
|
|
|
clStatus = clGetProgramBuildInfo(clProgram, device->oclDeviceID, CL_PROGRAM_BUILD_LOG, length, buildLog, &length);
|
|
|
|
LOG_PRINTF("[OCL] Build Errors" << std::endl << buildLog);
|
|
|
|
free(buildLog);
|
|
|
|
|
|
|
|
device->score = (void*)new LibreOfficeDeviceScore;
|
|
|
|
((LibreOfficeDeviceScore*)device->score)->fTime = DBL_MAX;
|
|
|
|
((LibreOfficeDeviceScore*)device->score)->bNoCLErrors = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Build program succeeded */
|
|
|
|
timer kernelTime;
|
|
|
|
timerStart(&kernelTime);
|
|
|
|
|
|
|
|
/* Run kernel */
|
|
|
|
LibreOfficeDeviceEvaluationIO* testData = (LibreOfficeDeviceEvaluationIO*)evalData;
|
|
|
|
clKernel = clCreateKernel(clProgram, "DynamicKernel", &clStatus);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateKernel");
|
2013-11-19 19:11:50 -05:00
|
|
|
cl_mem clResult = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->outputSize, &testData->output[0], &clStatus);
|
2013-11-19 16:36:00 -05:00
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateBuffer::clResult");
|
2013-11-19 19:11:50 -05:00
|
|
|
cl_mem clInput0 = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->inputSize, &testData->input0[0], &clStatus);
|
2013-11-19 16:36:00 -05:00
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateBuffer::clInput0");
|
2013-11-19 19:11:50 -05:00
|
|
|
cl_mem clInput1 = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->inputSize, &testData->input1[0], &clStatus);
|
2013-11-19 16:36:00 -05:00
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateBuffer::clInput1");
|
2013-11-19 19:11:50 -05:00
|
|
|
cl_mem clInput2 = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->inputSize, &testData->input2[0], &clStatus);
|
2013-11-19 16:36:00 -05:00
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateBuffer::clInput2");
|
2013-11-19 19:11:50 -05:00
|
|
|
cl_mem clInput3 = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->inputSize, &testData->input3[0], &clStatus);
|
2013-11-19 16:36:00 -05:00
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateBuffer::clInput3");
|
|
|
|
clStatus = clSetKernelArg(clKernel, 0, sizeof(cl_mem), (void*)&clResult);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clSetKernelArg::clResult");
|
|
|
|
clStatus = clSetKernelArg(clKernel, 1, sizeof(cl_mem), (void*)&clInput0);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clSetKernelArg::clInput0");
|
|
|
|
clStatus = clSetKernelArg(clKernel, 2, sizeof(cl_mem), (void*)&clInput1);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clSetKernelArg::clInput1");
|
|
|
|
clStatus = clSetKernelArg(clKernel, 3, sizeof(cl_mem), (void*)&clInput2);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clSetKernelArg::clInput2");
|
|
|
|
clStatus = clSetKernelArg(clKernel, 4, sizeof(cl_mem), (void*)&clInput3);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clSetKernelArg::clInput3");
|
|
|
|
size_t globalWS[1] = { testData->outputSize };
|
|
|
|
size_t localSize[1] = { 64 };
|
|
|
|
clStatus = clEnqueueNDRangeKernel(clQueue, clKernel, 1, 0, globalWS, localSize, 0, NULL, NULL);
|
|
|
|
DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clEnqueueNDRangeKernel");
|
|
|
|
clFinish(clQueue);
|
|
|
|
clReleaseMemObject(clInput3);
|
|
|
|
clReleaseMemObject(clInput2);
|
|
|
|
clReleaseMemObject(clInput1);
|
|
|
|
clReleaseMemObject(clInput0);
|
|
|
|
clReleaseMemObject(clResult);
|
|
|
|
clReleaseKernel(clKernel);
|
|
|
|
|
|
|
|
device->score = (void*)new LibreOfficeDeviceScore;
|
2013-11-20 20:59:20 +02:00
|
|
|
((LibreOfficeDeviceScore*)device->score)->fTime = timerCurrent(&kernelTime);
|
2013-11-19 16:36:00 -05:00
|
|
|
((LibreOfficeDeviceScore*)device->score)->bNoCLErrors = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
clReleaseProgram(clProgram);
|
|
|
|
clReleaseCommandQueue(clQueue);
|
|
|
|
clReleaseContext(clContext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Evaluating an Native CPU device */
|
|
|
|
LOG_PRINTF("[DS] Device: \"CPU\" (Native) evaluation...");
|
|
|
|
timer kernelTime;
|
|
|
|
timerStart(&kernelTime);
|
|
|
|
|
|
|
|
LibreOfficeDeviceEvaluationIO* testData = (LibreOfficeDeviceEvaluationIO*)evalData;
|
|
|
|
for (unsigned long j = 0; j < testData->outputSize; j++)
|
|
|
|
{
|
|
|
|
double fAverage = 0.0f;
|
|
|
|
double fMin = DBL_MAX;
|
|
|
|
double fSoP = 0.0f;
|
|
|
|
for (unsigned long i = 0; i < testData->inputSize; i++)
|
|
|
|
{
|
|
|
|
fAverage += testData->input0[i];
|
|
|
|
fMin = ((fMin < testData->input1[i]) ? fMin : testData->input1[i]);
|
|
|
|
fSoP += testData->input2[i] * testData->input3[i];
|
|
|
|
}
|
|
|
|
fAverage /= testData->inputSize;
|
|
|
|
testData->output[j] = fAverage + (fMin * fSoP);
|
|
|
|
}
|
|
|
|
|
|
|
|
device->score = (void*)new LibreOfficeDeviceScore;
|
2013-11-20 20:59:20 +02:00
|
|
|
((LibreOfficeDeviceScore*)device->score)->fTime = timerCurrent(&kernelTime);
|
2013-11-19 16:36:00 -05:00
|
|
|
((LibreOfficeDeviceScore*)device->score)->bNoCLErrors = true;
|
|
|
|
}
|
|
|
|
return DS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pick best device */
|
|
|
|
ds_status pickBestDevice(ds_profile* profile, int* bestDeviceIdx)
|
|
|
|
{
|
|
|
|
double bestScore = DBL_MAX;
|
|
|
|
*bestDeviceIdx = -1;
|
|
|
|
|
|
|
|
for (unsigned int d = 0; d < profile->numDevices; d++)
|
|
|
|
{
|
|
|
|
ds_device device = profile->devices[d];
|
|
|
|
LibreOfficeDeviceScore score = *(LibreOfficeDeviceScore*)device.score;
|
|
|
|
if (DS_DEVICE_OPENCL_DEVICE == device.type)
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Device[" << d << "] " << device.oclDeviceName << " (OpenCL) score is " << score.fTime);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Device[" << d << "] CPU (Native) score is " << score.fTime);
|
|
|
|
}
|
|
|
|
if (score.fTime < bestScore)
|
|
|
|
{
|
|
|
|
bestScore = score.fTime;
|
|
|
|
*bestDeviceIdx = d;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (DS_DEVICE_OPENCL_DEVICE == profile->devices[*bestDeviceIdx].type)
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Selected Device[" << *bestDeviceIdx << "]: " << profile->devices[*bestDeviceIdx].oclDeviceName << "(OpenCL).");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Selected Device[" << *bestDeviceIdx << "]: CPU (Native).");
|
|
|
|
}
|
|
|
|
|
|
|
|
return DS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return device ID for matching device name */
|
|
|
|
int matchDevice(ds_profile* profile, char* deviceName)
|
|
|
|
{
|
|
|
|
int deviceMatch = -1;
|
|
|
|
for (unsigned int d = 0; d < profile->numDevices - 1; d++)
|
|
|
|
{
|
|
|
|
if ((std::string(profile->devices[d].oclDeviceName)).find(deviceName) != std::string::npos) deviceMatch = d;
|
|
|
|
}
|
|
|
|
if (std::string("NATIVE_CPU").find(deviceName) != std::string::npos) deviceMatch = profile->numDevices - 1;
|
|
|
|
return deviceMatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************/
|
|
|
|
/* EXTERNAL FUNCTIONS */
|
|
|
|
/*************************************************************************/
|
|
|
|
ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection)
|
|
|
|
{
|
|
|
|
/* Run only if device is not yet selected */
|
|
|
|
if (!bIsDeviceSelected || bForceSelection)
|
|
|
|
{
|
|
|
|
/* Setup */
|
|
|
|
ds_status status;
|
2013-11-19 19:24:23 -05:00
|
|
|
ds_profile* profile = NULL;
|
2013-11-19 16:36:00 -05:00
|
|
|
status = initDSProfile(&profile, "LibreOffice v0.1");
|
|
|
|
|
2013-11-19 19:24:23 -05:00
|
|
|
if (!profile)
|
|
|
|
{
|
|
|
|
// failed to initialize profile.
|
2013-11-21 15:14:14 -05:00
|
|
|
selectedDevice.type = DS_DEVICE_NATIVE_CPU;
|
2013-11-19 19:24:23 -05:00
|
|
|
return selectedDevice;
|
|
|
|
}
|
|
|
|
|
2013-11-19 16:36:00 -05:00
|
|
|
/* Try reading scores from file */
|
|
|
|
std::string tmpStr(sProfilePath);
|
|
|
|
const char* fileName = tmpStr.append("sc_opencl_device_profile.dat").c_str();
|
|
|
|
if (!bForceSelection)
|
|
|
|
{
|
|
|
|
status = readProfileFromFile(profile, deserializeScore, fileName);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = DS_INVALID_PROFILE;
|
|
|
|
LOG_PRINTF("[DS] Performing forced profiling.");
|
|
|
|
}
|
|
|
|
if (DS_SUCCESS != status)
|
|
|
|
{
|
|
|
|
if (!bForceSelection) LOG_PRINTF("[DS] Profile file not available (" << fileName << "); performing profiling.");
|
|
|
|
|
|
|
|
/* Populate input data for micro-benchmark */
|
2013-11-19 19:15:40 -05:00
|
|
|
boost::scoped_ptr<LibreOfficeDeviceEvaluationIO> testData(new LibreOfficeDeviceEvaluationIO);
|
2013-11-19 16:36:00 -05:00
|
|
|
testData->inputSize = INPUTSIZE;
|
|
|
|
testData->outputSize = OUTPUTSIZE;
|
2013-11-19 19:11:50 -05:00
|
|
|
testData->input0.resize(testData->inputSize);
|
|
|
|
testData->input1.resize(testData->inputSize);
|
|
|
|
testData->input2.resize(testData->inputSize);
|
|
|
|
testData->input3.resize(testData->inputSize);
|
|
|
|
testData->output.resize(testData->outputSize);
|
2013-11-19 19:15:40 -05:00
|
|
|
populateInput(testData.get());
|
2013-11-19 16:36:00 -05:00
|
|
|
|
|
|
|
/* Perform evaluations */
|
|
|
|
unsigned int numUpdates;
|
2013-11-19 19:15:40 -05:00
|
|
|
status = profileDevices(profile, DS_EVALUATE_ALL, evaluateScoreForDevice, (void*)testData.get(), &numUpdates);
|
|
|
|
|
2013-11-19 16:36:00 -05:00
|
|
|
if (DS_SUCCESS == status)
|
|
|
|
{
|
|
|
|
/* Write scores to file */
|
|
|
|
status = writeProfileToFile(profile, serializeScore, fileName);
|
|
|
|
if (DS_SUCCESS == status)
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Scores written to file (" << fileName << ").");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Error saving scores to file (" << fileName << "); scores not written to file.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Unable to evaluate performance; scores not written to file.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Profile read from file (" << fileName << ").");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pick best device */
|
|
|
|
int bestDeviceIdx;
|
|
|
|
pickBestDevice(profile, &bestDeviceIdx);
|
|
|
|
|
|
|
|
/* Overide if necessary */
|
|
|
|
char* overrideDeviceStr = getenv("SC_OPENCL_DEVICE_OVERRIDE");
|
|
|
|
if (NULL != overrideDeviceStr)
|
|
|
|
{
|
2013-11-19 16:59:35 -05:00
|
|
|
int overrideDeviceIdx = matchDevice(profile, overrideDeviceStr);
|
2013-11-19 16:36:00 -05:00
|
|
|
if (-1 != overrideDeviceIdx)
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Overriding Device Selection (SC_OPENCL_DEVICE_OVERRIDE=" << overrideDeviceStr << ").");
|
|
|
|
bestDeviceIdx = overrideDeviceIdx;
|
|
|
|
if (DS_DEVICE_OPENCL_DEVICE == profile->devices[bestDeviceIdx].type)
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Selected Device[" << bestDeviceIdx << "]: " << profile->devices[bestDeviceIdx].oclDeviceName << " (OpenCL).");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Selected Device[" << bestDeviceIdx << "]: CPU (Native).");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LOG_PRINTF("[DS] Ignoring invalid SC_OPENCL_DEVICE_OVERRIDE=" << overrideDeviceStr << ").");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Final device selection */
|
|
|
|
selectedDevice = profile->devices[bestDeviceIdx];
|
|
|
|
bIsDeviceSelected = true;
|
|
|
|
|
|
|
|
/* Release profile */
|
|
|
|
status = releaseDSProfile(profile, releaseScore);
|
|
|
|
}
|
|
|
|
return selectedDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool selectedDeviceIsOpenCL(ds_device device)
|
|
|
|
{
|
|
|
|
return (DS_DEVICE_OPENCL_DEVICE == device.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool selectedDeviceIsNativeCPU(ds_device device)
|
|
|
|
{
|
|
|
|
return (DS_DEVICE_NATIVE_CPU == device.type);
|
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|