diff options
Diffstat (limited to 'opencl/inc/opencl_device_selection.h')
-rw-r--r-- | opencl/inc/opencl_device_selection.h | 817 |
1 files changed, 367 insertions, 450 deletions
diff --git a/opencl/inc/opencl_device_selection.h b/opencl/inc/opencl_device_selection.h index b6a30fd5b01c..6ec506dd0314 100644 --- a/opencl/inc/opencl_device_selection.h +++ b/opencl/inc/opencl_device_selection.h @@ -19,8 +19,12 @@ #include <string.h> #include <clew/clew.h> +#include <libxml/xmlwriter.h> +#include <libxml/xmlstring.h> +#include <tools/stream.hxx> +#include <rtl/math.hxx> -#define DS_DEVICE_NAME_LENGTH 256 +#include <vector> enum ds_status { @@ -38,84 +42,106 @@ enum ds_status }; // device type -enum ds_device_type +enum class DeviceType { - DS_DEVICE_NATIVE_CPU = 0 - ,DS_DEVICE_OPENCL_DEVICE + None, + NativeCPU, + OpenCLDevice }; - struct ds_device { - ds_device_type type; - cl_device_id oclDeviceID; - char* oclPlatformVendor; - char* oclDeviceName; - char* oclDriverVersion; - void* score; // a pointer to the score data, the content/format is application defined + DeviceType eType; + cl_device_id aDeviceID; + + OString sPlatformName; + OString sPlatformVendor; + OString sPlatformVersion; + OString sPlatformProfile; + OString sPlatformExtensions; + + OString sDeviceName; + OString sDeviceVendor; + OString sDeviceVersion; + OString sDriverVersion; + OString sDeviceType; + OString sDeviceExtensions; + OString sDeviceOpenCLVersion; + + bool bDeviceAvailable; + bool bDeviceCompilerAvailable; + bool bDeviceLinkerAvailable; + + double fTime; // small time means faster device + bool bErrors; // were there any opencl errors }; struct ds_profile { - unsigned int numDevices; - ds_device* devices; - const char* version; + std::vector<ds_device> devices; + OString version; + + ds_profile(OString& inVersion) + : version(inVersion) + {} }; -// deallocate memory used by score -typedef ds_status(* ds_score_release)(void* score); -inline ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) +inline OString getPlatformInfoString(cl_platform_id aPlatformId, cl_platform_info aPlatformInfo) { - ds_status status = DS_SUCCESS; - if (profile != NULL) - { - if (profile->devices != NULL && sr != NULL) - { - unsigned int i; - for (i = 0; i < profile->numDevices; i++) - { - free(profile->devices[i].oclPlatformVendor); - free(profile->devices[i].oclDeviceName); - free(profile->devices[i].oclDriverVersion); - status = sr(profile->devices[i].score); - if (status != DS_SUCCESS) break; - } - free(profile->devices); - } - free(profile); - } - return status; + std::vector<char> temporary(2048, 0); + clGetPlatformInfo(aPlatformId, aPlatformInfo, temporary.size(), temporary.data(), nullptr); + return OString(temporary.data()); } +inline OString getDeviceInfoString(cl_device_id aDeviceId, cl_device_info aDeviceInfo) +{ + std::vector<char> temporary(2048, 0); + clGetDeviceInfo(aDeviceId, aDeviceInfo, temporary.size(), temporary.data(), nullptr); + return OString(temporary.data()); +} -inline ds_status initDSProfile(ds_profile** p, const char* version) +inline OString getDeviceType(cl_device_id aDeviceId) +{ + OString sType = ""; + cl_device_type aDeviceType; + clGetDeviceInfo(aDeviceId, CL_DEVICE_TYPE, sizeof(aDeviceType), &aDeviceType, nullptr); + if (aDeviceType & CL_DEVICE_TYPE_CPU) + sType += "cpu "; + if (aDeviceType & CL_DEVICE_TYPE_GPU) + sType += "gpu "; + if (aDeviceType & CL_DEVICE_TYPE_ACCELERATOR) + sType += "accelerator "; + if (aDeviceType & CL_DEVICE_TYPE_CUSTOM) + sType += "custom "; + if (aDeviceType & CL_DEVICE_TYPE_DEFAULT) + sType += "default "; + return sType; +} + +inline bool getDeviceInfoBool(cl_device_id aDeviceId, cl_device_info aDeviceInfo) +{ + cl_bool bCLBool; + clGetDeviceInfo(aDeviceId, aDeviceInfo, sizeof(bCLBool), &bCLBool, nullptr); + return bCLBool == CL_TRUE; +} + +inline ds_status initDSProfile(std::unique_ptr<ds_profile>& rProfile, OString rVersion) { int numDevices; cl_uint numPlatforms; - cl_platform_id* platforms = NULL; - cl_device_id* devices = NULL; - ds_status status = DS_SUCCESS; - ds_profile* profile = NULL; + std::vector<cl_platform_id> platforms; + std::vector<cl_device_id> devices; + unsigned int next; unsigned int i; - if (p == NULL) return DS_INVALID_PROFILE; - - profile = static_cast<ds_profile*>(malloc(sizeof(ds_profile))); - if (profile == NULL) return DS_MEMORY_ERROR; - - memset(profile, 0, sizeof(ds_profile)); + rProfile = std::unique_ptr<ds_profile>(new ds_profile(rVersion)); clGetPlatformIDs(0, NULL, &numPlatforms); if (numPlatforms != 0) { - platforms = static_cast<cl_platform_id*>(malloc(numPlatforms * sizeof(cl_platform_id))); - if (platforms == NULL) - { - status = DS_MEMORY_ERROR; - goto cleanup; - } - clGetPlatformIDs(numPlatforms, platforms, NULL); + platforms.resize(numPlatforms); + clGetPlatformIDs(numPlatforms, platforms.data(), NULL); } numDevices = 0; @@ -134,35 +160,27 @@ inline ds_status initDSProfile(ds_profile** p, const char* version) } numDevices += num; } + if (numDevices != 0) { - devices = static_cast<cl_device_id*>(malloc(numDevices * sizeof(cl_device_id))); - if (devices == NULL) - { - status = DS_MEMORY_ERROR; - goto cleanup; - } + devices.resize(numDevices); } - profile->numDevices = numDevices + 1; // +1 to numDevices to include the native CPU - profile->devices = static_cast<ds_device*>(malloc(profile->numDevices * sizeof(ds_device))); - if (profile->devices == NULL) - { - profile->numDevices = 0; - status = DS_MEMORY_ERROR; - goto cleanup; - } - memset(profile->devices, 0, profile->numDevices * sizeof(ds_device)); + rProfile->devices.resize(numDevices + 1); // +1 to numDevices to include the native CPU next = 0; for (i = 0; i < (unsigned int)numPlatforms; i++) { cl_uint num = 0; unsigned j; - char vendor[256]; - if (clGetPlatformInfo(platforms[i], CL_PLATFORM_VENDOR, sizeof(vendor), vendor, NULL) != CL_SUCCESS) - vendor[0] = '\0'; - cl_int err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, devices, &num); + + OString sPlatformProfile = getPlatformInfoString(platforms[i], CL_PLATFORM_PROFILE); + OString sPlatformVersion = getPlatformInfoString(platforms[i], CL_PLATFORM_VERSION); + OString sPlatformName = getPlatformInfoString(platforms[i], CL_PLATFORM_NAME); + OString sPlatformVendor = getPlatformInfoString(platforms[i], CL_PLATFORM_VENDOR); + OString sPlatformExts = getPlatformInfoString(platforms[i], CL_PLATFORM_EXTENSIONS); + + cl_int err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, numDevices, devices.data(), &num); if (err != CL_SUCCESS) { /* we want to catch at least the case when the call returns @@ -174,470 +192,369 @@ inline ds_status initDSProfile(ds_profile** p, const char* version) } for (j = 0; j < num; j++, next++) { - char buffer[DS_DEVICE_NAME_LENGTH]; - size_t length; - - profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE; - profile->devices[next].oclDeviceID = devices[j]; + cl_device_id aDeviceID = devices[j]; + + ds_device& rDevice = rProfile->devices[next]; + rDevice.eType = DeviceType::OpenCLDevice; + rDevice.aDeviceID = aDeviceID; + + rDevice.sPlatformName = sPlatformName; + rDevice.sPlatformVendor = sPlatformVendor; + rDevice.sPlatformVersion = sPlatformVersion; + rDevice.sPlatformProfile = sPlatformProfile; + rDevice.sPlatformExtensions = sPlatformExts; + + rDevice.sDeviceName = getDeviceInfoString(aDeviceID, CL_DEVICE_NAME); + rDevice.sDeviceVendor = getDeviceInfoString(aDeviceID, CL_DEVICE_VENDOR); + rDevice.sDeviceVersion = getDeviceInfoString(aDeviceID, CL_DEVICE_VERSION); + rDevice.sDriverVersion = getDeviceInfoString(aDeviceID, CL_DRIVER_VERSION); + rDevice.sDeviceType = getDeviceType(aDeviceID); + rDevice.sDeviceExtensions = getDeviceInfoString(aDeviceID, CL_DEVICE_EXTENSIONS); + rDevice.sDeviceOpenCLVersion = getDeviceInfoString(aDeviceID, CL_DEVICE_OPENCL_C_VERSION); + + rDevice.bDeviceAvailable = getDeviceInfoBool(aDeviceID, CL_DEVICE_AVAILABLE); + rDevice.bDeviceCompilerAvailable = getDeviceInfoBool(aDeviceID, CL_DEVICE_COMPILER_AVAILABLE); + rDevice.bDeviceLinkerAvailable = getDeviceInfoBool(aDeviceID, CL_DEVICE_LINKER_AVAILABLE); + } + } + rProfile->devices[next].eType = DeviceType::NativeCPU; - profile->devices[next].oclPlatformVendor = strdup(vendor); + return DS_SUCCESS; +} - clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME - , DS_DEVICE_NAME_LENGTH, &buffer, NULL); - length = strlen(buffer); - profile->devices[next].oclDeviceName = static_cast<char*>(malloc(length + 1)); - memcpy(profile->devices[next].oclDeviceName, buffer, length + 1); +namespace +{ - clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION - , DS_DEVICE_NAME_LENGTH, &buffer, NULL); - length = strlen(buffer); - profile->devices[next].oclDriverVersion = static_cast<char*>(malloc(length + 1)); - memcpy(profile->devices[next].oclDriverVersion, buffer, length + 1); - } - } - profile->devices[next].type = DS_DEVICE_NATIVE_CPU; - profile->version = version; +/** + * XmlWriter writes a XML to a SvStream. It uses libxml2 for writing but hides + * all the internal libxml2 workings and uses types that are native for LO + * development. + * + * The codepage used for XML is always "utf-8" and the output is indented so it + * is easier to read. + * + * TODO: move to common code + */ +class XmlWriter +{ +private: + SvStream* mpStream; + xmlTextWriterPtr mpWriter; -cleanup: - if (platforms) free(platforms); - if (devices) free(devices); - if (status == DS_SUCCESS) + static int funcWriteCallback(void* pContext, const char* sBuffer, int nLen) { - *p = profile; + SvStream* pStream = static_cast<SvStream*>(pContext); + return static_cast<int>(pStream->Write(sBuffer, nLen)); } - else + + static int funcCloseCallback(void* pContext) { - if (profile) - { - if (profile->devices) free(profile->devices); - free(profile); - } + SvStream* pStream = static_cast<SvStream*>(pContext); + pStream->Flush(); + return 0; // 0 or -1 in case of error } - return status; -} - -// Pointer to a function that calculates the score of a device (ex: device->score) -// update the data size of score. The encoding and the format of the score data -// is implementation defined. The function should return DS_SUCCESS if there's no error to be reported. -typedef ds_status(* ds_perf_evaluator)(ds_device* device, void* data); -typedef enum { - DS_EVALUATE_ALL - , DS_EVALUATE_NEW_ONLY -} ds_evaluation_type; - -inline ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type, - ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) -{ - ds_status status = DS_SUCCESS; - unsigned int i; - unsigned int updates = 0; +public: - if (profile == NULL) + XmlWriter(SvStream* pStream) + : mpStream(pStream) + , mpWriter(nullptr) { - return DS_INVALID_PROFILE; } - if (evaluator == NULL) + + ~XmlWriter() { - return DS_INVALID_PERF_EVALUATOR; + if (mpWriter != nullptr) + endDocument(); } - for (i = 0; i < profile->numDevices; i++) + bool startDocument() { - ds_status evaluatorStatus; + xmlOutputBufferPtr xmlOutBuffer = xmlOutputBufferCreateIO(funcWriteCallback, funcCloseCallback, mpStream, nullptr); + mpWriter = xmlNewTextWriter(xmlOutBuffer); + if (mpWriter == nullptr) + return false; + xmlTextWriterSetIndent(mpWriter, 1); + xmlTextWriterStartDocument(mpWriter, nullptr, "UTF-8", nullptr); + return true; + } - switch (type) - { - case DS_EVALUATE_NEW_ONLY: - if (profile->devices[i].score != NULL) break; - // else fall through - case DS_EVALUATE_ALL: - evaluatorStatus = evaluator(profile->devices + i, evaluatorData); - if (evaluatorStatus != DS_SUCCESS) - { - status = evaluatorStatus; - return status; - } - updates++; - break; - default: - return DS_INVALID_PERF_EVALUATOR_TYPE; - break; - }; + void endDocument() + { + xmlTextWriterEndDocument(mpWriter); + xmlFreeTextWriter(mpWriter); + mpWriter = nullptr; } - if (numUpdates) *numUpdates = updates; - return status; -} + void startElement(const OString& sName) + { + xmlChar* xmlName = xmlCharStrdup(sName.getStr()); + xmlTextWriterStartElement(mpWriter, xmlName); + xmlFree(xmlName); + } -#define DS_TAG_VERSION "<version>" -#define DS_TAG_VERSION_END "</version>" -#define DS_TAG_DEVICE "<device>" -#define DS_TAG_DEVICE_END "</device>" -#define DS_TAG_SCORE "<score>" -#define DS_TAG_SCORE_END "</score>" -#define DS_TAG_DEVICE_TYPE "<type>" -#define DS_TAG_DEVICE_TYPE_END "</type>" -#define DS_TAG_DEVICE_NAME "<name>" -#define DS_TAG_DEVICE_NAME_END "</name>" -#define DS_TAG_DEVICE_DRIVER_VERSION "<driver>" -#define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>" + void endElement() + { + xmlTextWriterEndElement(mpWriter); + } -#define DS_DEVICE_NATIVE_CPU_STRING "native_cpu" + void content(const OString& sValue) + { + xmlChar* xmlValue = xmlCharStrdup(sValue.getStr()); + xmlTextWriterWriteString(mpWriter, xmlValue); + xmlFree(xmlValue); + } +}; -typedef ds_status(* ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize); -inline ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) +/** + * XmlWalker main purpose is to make it easier for walking the + * parsed XML DOM tree. + * + * It hides all the libxml2 and C -isms and makes the useage more + * confortable from LO developer point of view. + * + * TODO: move to common code + */ +class XmlWalker { - ds_status status = DS_SUCCESS; - FILE* profileFile = NULL; +private: + xmlDocPtr mpDocPtr; + xmlNodePtr mpRoot; + xmlNodePtr mpCurrent; + std::vector<xmlNodePtr> mpStack; - if (profile == NULL) return DS_INVALID_PROFILE; +public: + XmlWalker() + {} - profileFile = fopen(file, "wb"); - if (profileFile == NULL) + ~XmlWalker() { - status = DS_FILE_ERROR; + xmlFreeDoc(mpDocPtr); } - else + + bool open(SvStream* pStream) { - unsigned int i; + sal_Size nSize = pStream->remainingSize(); + std::vector<sal_uInt8> aBuffer(nSize + 1); + pStream->Read(aBuffer.data(), nSize); + aBuffer[nSize] = 0; + mpDocPtr = xmlParseDoc(reinterpret_cast<xmlChar*>(aBuffer.data())); + if (mpDocPtr == nullptr) + return false; + mpRoot = xmlDocGetRootElement(mpDocPtr); + mpCurrent = mpRoot; + mpStack.push_back(mpCurrent); + return true; + } - // write version string - fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile); - fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile); - fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile); - fwrite("\n", sizeof(char), 1, profileFile); + OString name() + { + return OString(reinterpret_cast<const char*>(mpCurrent->name)); + } - for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) + OString content() + { + OString aContent; + if (mpCurrent->xmlChildrenNode != nullptr) { - void* serializedScore; - unsigned int serializedScoreSize; - - fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile); - - fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile); - fwrite(&profile->devices[i].type, sizeof(ds_device_type), 1, profileFile); - fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile); - - switch (profile->devices[i].type) - { - case DS_DEVICE_NATIVE_CPU: - { - // There's no need to emit a device name for the native CPU device. - /* - fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile); - fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile); - fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile); - */ - } - break; - case DS_DEVICE_OPENCL_DEVICE: - { - fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile); - fwrite(profile->devices[i].oclDeviceName, sizeof(char), strlen(profile->devices[i].oclDeviceName), profileFile); - fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile); - - fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile); - fwrite(profile->devices[i].oclDriverVersion, sizeof(char), strlen(profile->devices[i].oclDriverVersion), profileFile); - fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile); - } - break; - default: - break; - }; - - fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile); - status = serializer(profile->devices + i, &serializedScore, &serializedScoreSize); - if (status == DS_SUCCESS && serializedScore != NULL && serializedScoreSize > 0) - { - fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile); - free(serializedScore); - } - fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile); - fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile); - fwrite("\n", sizeof(char), 1, profileFile); + xmlChar* pContent = xmlNodeListGetString(mpDocPtr, mpCurrent->xmlChildrenNode, 1); + aContent = OString(reinterpret_cast<const char*>(pContent)); + xmlFree(pContent); } - fclose(profileFile); + return aContent; } - return status; -} - - -inline ds_status readProFile(const char* fileName, char** content, size_t* contentSize) -{ - FILE* input = NULL; - size_t size = 0; - char* binary = NULL; - long pos = -1; - - *contentSize = 0; - *content = NULL; - input = fopen(fileName, "rb"); - if (input == NULL) + void children() { - return DS_FILE_ERROR; + mpStack.push_back(mpCurrent); + mpCurrent = mpCurrent->xmlChildrenNode; } - fseek(input, 0L, SEEK_END); - pos = ftell(input); - if (pos < 0) + void parent() { - fclose(input); - return DS_FILE_ERROR; + mpCurrent = mpStack.back(); + mpStack.pop_back(); } - size = pos; - rewind(input); - binary = static_cast<char*>(malloc(size)); - if (binary == NULL) + void next() { - fclose(input); - return DS_FILE_ERROR; + mpCurrent = mpCurrent->next; } - size_t bytesRead = fread(binary, sizeof(char), size, input); - (void) bytesRead; // avoid warning - fclose(input); - *contentSize = size; - *content = binary; - return DS_SUCCESS; -} - - -inline const char* findString(const char* contentStart, const char* contentEnd, const char* string) -{ - size_t stringLength; - const char* currentPosition; - const char* found; - found = NULL; - stringLength = strlen(string); - currentPosition = contentStart; - for (currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) + bool isValid() { - if (*currentPosition == string[0]) - { - if (currentPosition + stringLength < contentEnd) - { - if (strncmp(currentPosition, string, stringLength) == 0) - { - found = currentPosition; - break; - } - } - } + return mpCurrent != nullptr; } - return found; -} +}; +} // end anonymous namespace -typedef ds_status(* ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize); -inline ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) +inline ds_status writeProfile(const OUString& rStreamName, std::unique_ptr<ds_profile>& pProfile) { + if (pProfile == nullptr) + return DS_INVALID_PROFILE; + if (rStreamName.isEmpty()) + return DS_INVALID_PROFILE; - ds_status status = DS_SUCCESS; - char* contentStart = NULL; - const char* contentEnd = NULL; - size_t contentSize; + std::unique_ptr<SvStream> pStream; + pStream.reset(new SvFileStream(rStreamName, STREAM_STD_READWRITE | StreamMode::TRUNC)); - if (profile == NULL) return DS_INVALID_PROFILE; + XmlWriter aXmlWriter(pStream.get()); - status = readProFile(file, &contentStart, &contentSize); - if (status == DS_SUCCESS) - { - const char* currentPosition; - const char* dataStart; - const char* dataEnd; - size_t versionStringLength; + if (!aXmlWriter.startDocument()) + return DS_FILE_ERROR; - contentEnd = contentStart + contentSize; - currentPosition = contentStart; + aXmlWriter.startElement("profile"); + aXmlWriter.startElement("version"); + aXmlWriter.content(OString(pProfile->version)); + aXmlWriter.endElement(); - // parse the version string - dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION); - if (dataStart == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - dataStart += strlen(DS_TAG_VERSION); + for (ds_device& rDevice : pProfile->devices) + { + aXmlWriter.startElement("device"); - dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END); - if (dataEnd == NULL) + switch(rDevice.eType) { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; + case DeviceType::NativeCPU: + aXmlWriter.startElement("type"); + aXmlWriter.content("native"); + aXmlWriter.endElement(); + break; + case DeviceType::OpenCLDevice: + aXmlWriter.startElement("type"); + aXmlWriter.content("opencl"); + aXmlWriter.endElement(); + + aXmlWriter.startElement("name"); + aXmlWriter.content(OString(rDevice.sDeviceName)); + aXmlWriter.endElement(); + + aXmlWriter.startElement("driver"); + aXmlWriter.content(OString(rDevice.sDriverVersion)); + aXmlWriter.endElement(); + break; + default: + break; } - versionStringLength = strlen(profile->version); - if (versionStringLength != static_cast<size_t>(dataEnd - dataStart) - || strncmp(profile->version, dataStart, versionStringLength) != 0) - { - // version mismatch - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - currentPosition = dataEnd + strlen(DS_TAG_VERSION_END); + aXmlWriter.startElement("time"); + if (rtl::math::approxEqual(rDevice.fTime, DBL_MAX)) + aXmlWriter.content("max"); + else + aXmlWriter.content(OString::number(rDevice.fTime)); + aXmlWriter.endElement(); - // parse the device information - while (true) - { - unsigned int i; + aXmlWriter.startElement("errors"); + aXmlWriter.content(rDevice.bErrors ? "true" : "false"); + aXmlWriter.endElement(); - const char* deviceTypeStart; - const char* deviceTypeEnd; - ds_device_type deviceType; + aXmlWriter.endElement(); + } - const char* deviceNameStart; - const char* deviceNameEnd; + aXmlWriter.endElement(); + aXmlWriter.endDocument(); - const char* deviceScoreStart; - const char* deviceScoreEnd; + return DS_SUCCESS; +} - const char* deviceDriverStart; - const char* deviceDriverEnd; +inline ds_status readProfile(const OUString& rStreamName, std::unique_ptr<ds_profile>& pProfile) +{ + ds_status eStatus = DS_SUCCESS; - dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE); - if (dataStart == NULL) - { - // nothing useful remain, quit... - break; - } - dataStart += strlen(DS_TAG_DEVICE); - dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END); - if (dataEnd == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } + if (rStreamName.isEmpty()) + return DS_INVALID_PROFILE; + + std::unique_ptr<SvStream> pStream; + pStream.reset(new SvFileStream(rStreamName, StreamMode::READ)); + XmlWalker aWalker; - // parse the device type - deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE); - if (deviceTypeStart == NULL) + if (!aWalker.open(pStream.get())) + return DS_FILE_ERROR; + + if (aWalker.name() == "profile") + { + aWalker.children(); + while (aWalker.isValid()) + { + if (aWalker.name() == "version") { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; + if (aWalker.content() != pProfile->version) + return DS_PROFILE_FILE_ERROR; } - deviceTypeStart += strlen(DS_TAG_DEVICE_TYPE); - deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END); - if (deviceTypeEnd == NULL) + else if (aWalker.name() == "device") { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type)); + aWalker.children(); + DeviceType eDeviceType = DeviceType::None; + OString sName; + OString sVersion; + double fTime = -1.0; + bool bErrors = true; - // parse the device name - if (deviceType == DS_DEVICE_OPENCL_DEVICE) - { - - deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME); - if (deviceNameStart == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - deviceNameStart += strlen(DS_TAG_DEVICE_NAME); - deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END); - if (deviceNameEnd == NULL) + while (aWalker.isValid()) { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - + if (aWalker.name() == "type") + { + OString sContent = aWalker.content(); + if (sContent == "native") + eDeviceType = DeviceType::NativeCPU; + else if (sContent == "opencl") + eDeviceType = DeviceType::OpenCLDevice; + else + return DS_PROFILE_FILE_ERROR; + } + else if (aWalker.name() == "name") + { + sName = aWalker.content(); + } + else if (aWalker.name() == "driver") + { + sVersion = aWalker.content(); + } + else if (aWalker.name() == "time") + { + if (aWalker.content() == "max") + fTime = DBL_MAX; + else + fTime = aWalker.content().toDouble(); + } + else if (aWalker.name() == "errors") + { + bErrors = (aWalker.content() == "true"); + } - deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION); - if (deviceDriverStart == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - deviceDriverStart += strlen(DS_TAG_DEVICE_DRIVER_VERSION); - deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END); - if (deviceDriverEnd == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; + aWalker.next(); } + if (fTime < 0.0) + return DS_PROFILE_FILE_ERROR; - // check if this device is on the system - for (i = 0; i < profile->numDevices; i++) + for (ds_device& rDevice : pProfile->devices) { - if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) + // type matches? either both are DS_DEVICE_OPENCL_DEVICE or DS_DEVICE_NATIVE_CPU + if (rDevice.eType == eDeviceType) { - size_t actualDeviceNameLength; - size_t driverVersionLength; - - actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName); - driverVersionLength = strlen(profile->devices[i].oclDriverVersion); - if (actualDeviceNameLength == static_cast<size_t>(deviceNameEnd - deviceNameStart) - && driverVersionLength == static_cast<size_t>(deviceDriverEnd - deviceDriverStart) - && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength) == 0 - && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength) == 0) + // is DS_DEVICE_NATIVE_CPU or name + version matches? + if (eDeviceType == DeviceType::NativeCPU || + (sName == OString(rDevice.sDeviceName) && + sVersion == OString(rDevice.sDriverVersion))) { - - deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE); - if (deviceScoreStart == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - deviceScoreStart += strlen(DS_TAG_SCORE); - deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END); - status = deserializer(profile->devices + i, reinterpret_cast<const unsigned char*>(deviceScoreStart), deviceScoreEnd - deviceScoreStart); - if (status != DS_SUCCESS) - { - goto cleanup; - } + rDevice.fTime = fTime; + rDevice.bErrors = bErrors; } } } + aWalker.parent(); } - else if (deviceType == DS_DEVICE_NATIVE_CPU) - { - for (i = 0; i < profile->numDevices; i++) - { - if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) - { - deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE); - if (deviceScoreStart == NULL) - { - status = DS_PROFILE_FILE_ERROR; - goto cleanup; - } - deviceScoreStart += strlen(DS_TAG_SCORE); - deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END); - status = deserializer(profile->devices + i, reinterpret_cast<const unsigned char*>(deviceScoreStart), deviceScoreEnd - deviceScoreStart); - if (status != DS_SUCCESS) - { - goto cleanup; - } - } - } - } - - // skip over the current one to find the next device - currentPosition = dataEnd + strlen(DS_TAG_DEVICE_END); + aWalker.next(); } + aWalker.parent(); } -cleanup: - if (contentStart != NULL) free(contentStart); - if (status != DS_SUCCESS) - return status; - - // Check that all the devices present had valid cached scores. If - // not, return DS_INVALID_PROFILE and let the caller re-evaluate - // scores for present devices, and write a new profile file. - for (unsigned int i = 0; i < profile->numDevices; i++) - if (profile->devices[i].score == NULL) - return DS_INVALID_PROFILE; - return DS_SUCCESS; + return eStatus; } #endif |