diff options
Diffstat (limited to 'opencl/source/opencl_device.cxx')
-rw-r--r-- | opencl/source/opencl_device.cxx | 279 |
1 files changed, 167 insertions, 112 deletions
diff --git a/opencl/source/opencl_device.cxx b/opencl/source/opencl_device.cxx index 32a94df5dcb3..af3bc1844e3a 100644 --- a/opencl/source/opencl_device.cxx +++ b/opencl/source/opencl_device.cxx @@ -46,15 +46,11 @@ namespace opencl { +namespace { + bool bIsDeviceSelected = false; ds_device selectedDevice; -struct LibreOfficeDeviceScore -{ - double fTime; // small time means faster device - bool bNoCLErrors; // were there any opencl errors -}; - struct LibreOfficeDeviceEvaluationIO { std::vector<double> input0; @@ -182,7 +178,7 @@ double random(double min, double max) } /* Populate input */ -void populateInput(LibreOfficeDeviceEvaluationIO* testData) +void populateInput(std::unique_ptr<LibreOfficeDeviceEvaluationIO>& testData) { double* input0 = &testData->input0[0]; double* input1 = &testData->input1[0]; @@ -196,49 +192,22 @@ void populateInput(LibreOfficeDeviceEvaluationIO* testData) 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 = static_cast<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 (nullptr != score) - { - delete static_cast<LibreOfficeDeviceScore*>(score); - } - return DS_SUCCESS; -} /* Evaluate devices */ -ds_status evaluateScoreForDevice(ds_device* device, void* evalData) +ds_status evaluateScoreForDevice(ds_device& rDevice, std::unique_ptr<LibreOfficeDeviceEvaluationIO>& testData) { - if (DS_DEVICE_OPENCL_DEVICE == device->type) + if (rDevice.eType == DeviceType::OpenCLDevice) { /* Evaluating an OpenCL device */ - SAL_INFO("opencl.device", "Device: \"" << device->oclDeviceName << "\" (OpenCL) evaluation..."); + SAL_INFO("opencl.device", "Device: \"" << rDevice.sDeviceName << "\" (OpenCL) evaluation..."); cl_int clStatus; /* Check for 64-bit float extensions */ size_t aDevExtInfoSize = 0; - clStatus = clGetDeviceInfo(device->oclDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize); + clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, 0, nullptr, &aDevExtInfoSize); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); std::unique_ptr<char[]> aExtInfo(new char[aDevExtInfoSize]); - clStatus = clGetDeviceInfo(device->oclDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr); + clStatus = clGetDeviceInfo(rDevice.aDeviceID, CL_DEVICE_EXTENSIONS, sizeof(char) * aDevExtInfoSize, aExtInfo.get(), nullptr); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clGetDeviceInfo"); bool bKhrFp64Flag = false; bool bAmdFp64Flag = false; @@ -268,9 +237,8 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) if (!bKhrFp64Flag && !bAmdFp64Flag) { /* No 64-bit float support */ - device->score = static_cast<void*>(new LibreOfficeDeviceScore); - static_cast<LibreOfficeDeviceScore*>(device->score)->fTime = DBL_MAX; - static_cast<LibreOfficeDeviceScore*>(device->score)->bNoCLErrors = true; + rDevice.fTime = DBL_MAX; + rDevice.bErrors = false; SAL_INFO("opencl.device", "... no fp64 support"); } else @@ -278,30 +246,29 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) /* 64-bit float support present */ /* Create context and command queue */ - cl_context clContext = clCreateContext(nullptr, 1, &device->oclDeviceID, nullptr, nullptr, &clStatus); + cl_context clContext = clCreateContext(nullptr, 1, &rDevice.aDeviceID, nullptr, nullptr, &clStatus); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateContext"); - cl_command_queue clQueue = clCreateCommandQueue(clContext, device->oclDeviceID, 0, &clStatus); + cl_command_queue clQueue = clCreateCommandQueue(clContext, rDevice.aDeviceID, 0, &clStatus); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateCommandQueue"); /* Build program */ cl_program clProgram = clCreateProgramWithSource(clContext, 1, &source, sourceSize, &clStatus); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateProgramWithSource"); - clStatus = clBuildProgram(clProgram, 1, &device->oclDeviceID, buildOption, nullptr, nullptr); + clStatus = clBuildProgram(clProgram, 1, &rDevice.aDeviceID, buildOption, nullptr, nullptr); 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, nullptr, &length); + clStatus = clGetProgramBuildInfo(clProgram, rDevice.aDeviceID, CL_PROGRAM_BUILD_LOG, 0, nullptr, &length); buildLog = static_cast<char*>(malloc(length)); - clGetProgramBuildInfo(clProgram, device->oclDeviceID, CL_PROGRAM_BUILD_LOG, length, buildLog, &length); + clGetProgramBuildInfo(clProgram, rDevice.aDeviceID, CL_PROGRAM_BUILD_LOG, length, buildLog, &length); SAL_INFO("opencl.device", "Build Errors:\n" << buildLog); free(buildLog); - device->score = static_cast<void*>(new LibreOfficeDeviceScore); - static_cast<LibreOfficeDeviceScore*>(device->score)->fTime = DBL_MAX; - static_cast<LibreOfficeDeviceScore*>(device->score)->bNoCLErrors = false; + rDevice.fTime = DBL_MAX; + rDevice.bErrors = true; } else { @@ -310,7 +277,6 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) timerStart(&kernelTime); /* Run kernel */ - LibreOfficeDeviceEvaluationIO* testData = static_cast<LibreOfficeDeviceEvaluationIO*>(evalData); cl_kernel clKernel = clCreateKernel(clProgram, "DynamicKernel", &clStatus); DS_CHECK_STATUS(clStatus, "evaluateScoreForDevice::clCreateKernel"); cl_mem clResult = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, sizeof(cl_double) * testData->outputSize, &testData->output[0], &clStatus); @@ -345,9 +311,8 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) clReleaseMemObject(clResult); clReleaseKernel(clKernel); - device->score = static_cast<void*>(new LibreOfficeDeviceScore); - static_cast<LibreOfficeDeviceScore*>(device->score)->fTime = timerCurrent(&kernelTime); - static_cast<LibreOfficeDeviceScore*>(device->score)->bNoCLErrors = true; + rDevice.fTime = timerCurrent(&kernelTime); + rDevice.bErrors = false; } clReleaseProgram(clProgram); @@ -362,7 +327,6 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) timer kernelTime; timerStart(&kernelTime); - LibreOfficeDeviceEvaluationIO* testData = static_cast<LibreOfficeDeviceEvaluationIO*>(evalData); for (unsigned long j = 0; j < testData->outputSize; j++) { double fAverage = 0.0f; @@ -384,28 +348,45 @@ ds_status evaluateScoreForDevice(ds_device* device, void* evalData) // slower than the above. float fInterpretTailFactor = 10.0; - device->score = static_cast<void*>(new LibreOfficeDeviceScore); - static_cast<LibreOfficeDeviceScore*>(device->score)->fTime = timerCurrent(&kernelTime); - static_cast<LibreOfficeDeviceScore*>(device->score)->bNoCLErrors = true; - - static_cast<LibreOfficeDeviceScore*>(device->score)->fTime *= fInterpretTailFactor; + rDevice.fTime = timerCurrent(&kernelTime); + rDevice.fTime *= fInterpretTailFactor; + rDevice.bErrors = false; } return DS_SUCCESS; } +ds_status profileDevices(std::unique_ptr<ds_profile>& pProfile, std::unique_ptr<LibreOfficeDeviceEvaluationIO>& pTestData) +{ + ds_status status = DS_SUCCESS; + + if (!pProfile) + return DS_INVALID_PROFILE; + + for (ds_device& rDevice : pProfile->devices) + { + ds_status evaluatorStatus = evaluateScoreForDevice(rDevice, pTestData); + if (evaluatorStatus != DS_SUCCESS) + { + status = evaluatorStatus; + return status; + } + } + return status; +} + /* Pick best device */ -ds_status pickBestDevice(ds_profile* profile, int* bestDeviceIdx) +ds_status pickBestDevice(std::unique_ptr<ds_profile>& profile, int& rBestDeviceIndex) { double bestScore = DBL_MAX; - *bestDeviceIdx = -1; - for (unsigned int d = 0; d < profile->numDevices; d++) + rBestDeviceIndex = -1; + + for (unsigned int d = 0; d < profile->devices.size(); d++) { - ds_device device = profile->devices[d]; - LibreOfficeDeviceScore *pScore = static_cast<LibreOfficeDeviceScore*>(device.score); + ds_device& device = profile->devices[d]; // Check blacklist and whitelist for actual devices - if (device.type == DS_DEVICE_OPENCL_DEVICE) + if (device.eType == DeviceType::OpenCLDevice) { // There is a silly impedance mismatch here. Why do we // need two different ways to describe an OpenCL platform @@ -415,32 +396,32 @@ ds_status pickBestDevice(ds_profile* profile, int* bestDeviceIdx) OpenCLDeviceInfo aDevice; // We know that only the below fields are used by checkForKnownBadCompilers() - aPlatform.maVendor = OUString(device.oclPlatformVendor, strlen(device.oclPlatformVendor), RTL_TEXTENCODING_UTF8); - aDevice.maName = OUString(device.oclDeviceName, strlen(device.oclDeviceName), RTL_TEXTENCODING_UTF8); - aDevice.maDriver = OUString(device.oclDriverVersion, strlen(device.oclDriverVersion), RTL_TEXTENCODING_UTF8); + aPlatform.maVendor = OStringToOUString(device.sPlatformVendor, RTL_TEXTENCODING_UTF8); + aDevice.maName = OStringToOUString(device.sDeviceName, RTL_TEXTENCODING_UTF8); + aDevice.maDriver = OStringToOUString(device.sDriverVersion, RTL_TEXTENCODING_UTF8); // If blacklisted or not whitelisted, ignore it if (OpenCLConfig::get().checkImplementation(aPlatform, aDevice)) { - SAL_INFO("opencl.device", "Device[" << d << "] " << device.oclDeviceName << " is blacklisted or not whitelisted"); - pScore->fTime = DBL_MAX; - pScore->bNoCLErrors = true; + SAL_INFO("opencl.device", "Device[" << d << "] " << device.sDeviceName << " is blacklisted or not whitelisted"); + device.fTime = DBL_MAX; + device.bErrors = false; } } double fScore = DBL_MAX; - if (pScore) + if (device.fTime >= 0.0 || device.fTime == DBL_MAX) { - fScore = pScore->fTime; + fScore = device.fTime; } else { SAL_INFO("opencl.device", "Unusual null score"); } - if (DS_DEVICE_OPENCL_DEVICE == device.type) + if (device.eType == DeviceType::OpenCLDevice) { - SAL_INFO("opencl.device", "Device[" << d << "] " << device.oclDeviceName << " (OpenCL) score is " << fScore); + SAL_INFO("opencl.device", "Device[" << d << "] " << device.sDeviceName << " (OpenCL) score is " << fScore); } else { @@ -449,59 +430,135 @@ ds_status pickBestDevice(ds_profile* profile, int* bestDeviceIdx) if (fScore < bestScore) { bestScore = fScore; - *bestDeviceIdx = d; + rBestDeviceIndex = d; } } - if (DS_DEVICE_OPENCL_DEVICE == profile->devices[*bestDeviceIdx].type) + if (profile->devices[rBestDeviceIndex].eType == DeviceType::OpenCLDevice) { - SAL_INFO("opencl.device", "Selected Device[" << *bestDeviceIdx << "]: " << profile->devices[*bestDeviceIdx].oclDeviceName << "(OpenCL)."); + SAL_INFO("opencl.device", "Selected Device[" << rBestDeviceIndex << "]: " << profile->devices[rBestDeviceIndex].sDeviceName << "(OpenCL)."); } else { - SAL_INFO("opencl.device", "Selected Device[" << *bestDeviceIdx << "]: CPU (Native)."); + SAL_INFO("opencl.device", "Selected Device[" << rBestDeviceIndex << "]: CPU (Native)."); } - return DS_SUCCESS; } /* Return device ID for matching device name */ -int matchDevice(ds_profile* profile, char* deviceName) +int matchDevice(std::unique_ptr<ds_profile>& profile, char* deviceName) { int deviceMatch = -1; - for (unsigned int d = 0; d < profile->numDevices - 1; d++) + for (unsigned int d = 0; d < profile->devices.size() - 1; d++) { - if ((std::string(profile->devices[d].oclDeviceName)).find(deviceName) != std::string::npos) deviceMatch = d; + if ((std::string(profile->devices[d].sDeviceName.getStr())).find(deviceName) != std::string::npos) + deviceMatch = d; } - if (std::string("NATIVE_CPU").find(deviceName) != std::string::npos) deviceMatch = profile->numDevices - 1; + if (std::string("NATIVE_CPU").find(deviceName) != std::string::npos) + deviceMatch = profile->devices.size() - 1; return deviceMatch; } -/*************************************************************************/ -/* EXTERNAL FUNCTIONS */ -/*************************************************************************/ -ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection) +class LogWriter +{ +private: + SvFileStream maStream; +public: + LogWriter(OUString aFileName) + : maStream(aFileName, StreamMode::WRITE) + {} + + void text(const OString& rText) + { + maStream.WriteOString(rText); + maStream.WriteChar('\n'); + } + + void log(const OString& rKey, const OString& rValue) + { + maStream.WriteOString(rKey); + maStream.WriteCharPtr(": "); + maStream.WriteOString(rValue); + maStream.WriteChar('\n'); + } + + void log(const OString& rKey, const OUString& rValue) + { + log(rKey, OUStringToOString(rValue, RTL_TEXTENCODING_UTF8)); + } + + void log(const OString& rKey, int rValue) + { + log(rKey, OString::number(rValue)); + } + + void log(const OString& rKey, bool rValue) + { + log(rKey, OString::boolean(rValue)); + } +}; + + +void writeDevicesLog(std::unique_ptr<ds_profile>& rProfile, OUString sProfilePath, int nSelectedIndex) +{ + OUString aCacheFile(sProfilePath + "opencl_devices.log"); + LogWriter aWriter(aCacheFile); + + int nIndex = 0; + + for (ds_device& rDevice : rProfile->devices) + { + if (rDevice.eType == DeviceType::OpenCLDevice) + { + aWriter.log("Device Index", nIndex); + aWriter.log(" Selected", nIndex == nSelectedIndex); + aWriter.log(" Device Name", rDevice.sDeviceName); + aWriter.log(" Device Vendor", rDevice.sDeviceVendor); + aWriter.log(" Device Version", rDevice.sDeviceVersion); + aWriter.log(" Driver Version", rDevice.sDriverVersion); + aWriter.log(" Device Type", rDevice.sDeviceType); + aWriter.log(" Device Extensions", rDevice.sDeviceExtensions); + aWriter.log(" Device OpenCL C Version", rDevice.sDeviceOpenCLVersion); + + aWriter.log(" Device Available", rDevice.bDeviceAvailable); + aWriter.log(" Device Compiler Available", rDevice.bDeviceCompilerAvailable); + aWriter.log(" Device Linker Available", rDevice.bDeviceLinkerAvailable); + + aWriter.log(" Platform Name", rDevice.sPlatformName); + aWriter.log(" Platform Vendor", rDevice.sPlatformVendor); + aWriter.log(" Platform Version", rDevice.sPlatformVersion); + aWriter.log(" Platform Profile", rDevice.sPlatformProfile); + aWriter.log(" Platform Extensions", rDevice.sPlatformExtensions); + aWriter.text(""); + } + nIndex++; + } +} + +} // end anonymous namespace + +ds_device getDeviceSelection(OUString sProfilePath, bool bForceSelection) { /* Run only if device is not yet selected */ if (!bIsDeviceSelected || bForceSelection) { /* Setup */ - ds_profile* profile = nullptr; - initDSProfile(&profile, "LibreOffice v0.1"); + std::unique_ptr<ds_profile> aProfile; + ds_status status; + status = initDSProfile(aProfile, "LibreOffice v1"); - if (!profile) + if (status != DS_SUCCESS) { // failed to initialize profile. - selectedDevice.type = DS_DEVICE_NATIVE_CPU; + selectedDevice.eType = DeviceType::NativeCPU; return selectedDevice; } /* Try reading scores from file */ - std::string tmpStr(sProfilePath); - const char* fileName = tmpStr.append("sc_opencl_device_profile.dat").c_str(); - ds_status status; + OUString sFilePath = sProfilePath + OUString("opencl_profile.xml"); + if (!bForceSelection) { - status = readProfileFromFile(profile, deserializeScore, fileName); + status = readProfile(sFilePath, aProfile); } else { @@ -512,7 +569,7 @@ ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection) { if (!bForceSelection) { - SAL_INFO("opencl.device", "Profile file not available (" << fileName << "); performing profiling."); + SAL_INFO("opencl.device", "Profile file not available (" << sFilePath << "); performing profiling."); } /* Populate input data for micro-benchmark */ @@ -524,23 +581,22 @@ ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection) testData->input2.resize(testData->inputSize); testData->input3.resize(testData->inputSize); testData->output.resize(testData->outputSize); - populateInput(testData.get()); + populateInput(testData); /* Perform evaluations */ - unsigned int numUpdates; - status = profileDevices(profile, DS_EVALUATE_ALL, evaluateScoreForDevice, static_cast<void*>(testData.get()), &numUpdates); + status = profileDevices(aProfile, testData); if (DS_SUCCESS == status) { /* Write scores to file */ - status = writeProfileToFile(profile, serializeScore, fileName); + status = writeProfile(sFilePath, aProfile); if (DS_SUCCESS == status) { - SAL_INFO("opencl.device", "Scores written to file (" << fileName << ")."); + SAL_INFO("opencl.device", "Scores written to file (" << sFilePath << ")."); } else { - SAL_INFO("opencl.device", "Error saving scores to file (" << fileName << "); scores not written to file."); + SAL_INFO("opencl.device", "Error saving scores to file (" << sFilePath << "); scores not written to file."); } } else @@ -550,25 +606,25 @@ ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection) } else { - SAL_INFO("opencl.device", "Profile read from file (" << fileName << ")."); + SAL_INFO("opencl.device", "Profile read from file (" << sFilePath << ")."); } /* Pick best device */ int bestDeviceIdx; - pickBestDevice(profile, &bestDeviceIdx); + pickBestDevice(aProfile, bestDeviceIdx); /* Override if necessary */ char* overrideDeviceStr = getenv("SC_OPENCL_DEVICE_OVERRIDE"); if (nullptr != overrideDeviceStr) { - int overrideDeviceIdx = matchDevice(profile, overrideDeviceStr); + int overrideDeviceIdx = matchDevice(aProfile, overrideDeviceStr); if (-1 != overrideDeviceIdx) { SAL_INFO("opencl.device", "Overriding Device Selection (SC_OPENCL_DEVICE_OVERRIDE=" << overrideDeviceStr << ")."); bestDeviceIdx = overrideDeviceIdx; - if (DS_DEVICE_OPENCL_DEVICE == profile->devices[bestDeviceIdx].type) + if (aProfile->devices[bestDeviceIdx].eType == DeviceType::OpenCLDevice) { - SAL_INFO("opencl.device", "Selected Device[" << bestDeviceIdx << "]: " << profile->devices[bestDeviceIdx].oclDeviceName << " (OpenCL)."); + SAL_INFO("opencl.device", "Selected Device[" << bestDeviceIdx << "]: " << aProfile->devices[bestDeviceIdx].sDeviceName << " (OpenCL)."); } else { @@ -582,11 +638,10 @@ ds_device getDeviceSelection(const char* sProfilePath, bool bForceSelection) } /* Final device selection */ - selectedDevice = profile->devices[bestDeviceIdx]; + selectedDevice = aProfile->devices[bestDeviceIdx]; bIsDeviceSelected = true; - /* Release profile */ - releaseDSProfile(profile, releaseScore); + writeDevicesLog(aProfile, sProfilePath, bestDeviceIdx); } return selectedDevice; } |