diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2016-04-20 22:19:47 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2016-04-22 11:27:05 +0000 |
commit | 334e2dc9c3da4519e31e0452a40d3a958c401876 (patch) | |
tree | bfe420e41e0e9c5e7767c4ce657bd5e29192d91f | |
parent | tdf#97915: add Intel driver 3.0.1.10891 to blacklist (diff) | |
download | core-334e2dc9c3da4519e31e0452a40d3a958c401876.tar.gz core-334e2dc9c3da4519e31e0452a40d3a958c401876.zip |
opencl: better logging of devices and device selection
changes:
- Clew misses a lot of things, added defines needed for gathering
platform and device info.
- Refactored profile saving and loading to use libxml2 instead
the weird type of saving the profile data.
- Added an additional "log" file which is similar to the OpenGL
but it writes the OpenCL relevant information like which devices
and platforms are available (+ all the extra useful version
information) and which device was selected (if any at all).
Change-Id: I0fe793c756f8f4f1761fe120fc361df36e581903
Reviewed-on: https://gerrit.libreoffice.org/24270
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
-rw-r--r-- | external/clew/source/include/clew/clew.h | 67 | ||||
-rw-r--r-- | opencl/Library_opencl.mk | 2 | ||||
-rw-r--r-- | opencl/inc/opencl_device.hxx | 2 | ||||
-rw-r--r-- | opencl/inc/opencl_device_selection.h | 817 | ||||
-rw-r--r-- | opencl/source/opencl_device.cxx | 279 | ||||
-rw-r--r-- | opencl/source/openclwrapper.cxx | 5 |
6 files changed, 606 insertions, 566 deletions
diff --git a/external/clew/source/include/clew/clew.h b/external/clew/source/include/clew/clew.h index f932b341cde2..b23dc6041543 100644 --- a/external/clew/source/include/clew/clew.h +++ b/external/clew/source/include/clew/clew.h @@ -412,19 +412,86 @@ typedef struct { #define CL_DEVICE_TYPE_CPU (1 << 1) #define CL_DEVICE_TYPE_GPU (1 << 2) #define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) +#define CL_DEVICE_TYPE_CUSTOM (1 << 4) #define CL_DEVICE_TYPE_ALL 0xFFFFFFFF // cl_device_info +#define CL_DEVICE_TYPE 0x1000 +#define CL_DEVICE_VENDOR_ID 0x1001 #define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 +#define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 +#define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 +#define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B #define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C +#define CL_DEVICE_ADDRESS_BITS 0x100D +#define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E +#define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F +#define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 +#define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 +#define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 +#define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 +#define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 +#define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 +#define CL_DEVICE_IMAGE_SUPPORT 0x1016 +#define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 +#define CL_DEVICE_MAX_SAMPLERS 0x1018 +#define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 +#define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A +#define CL_DEVICE_SINGLE_FP_CONFIG 0x101B +#define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C +#define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D +#define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E #define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F +#define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 +#define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 +#define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 +#define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 +#define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 +#define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 +#define CL_DEVICE_ENDIAN_LITTLE 0x1026 +#define CL_DEVICE_AVAILABLE 0x1027 +#define CL_DEVICE_COMPILER_AVAILABLE 0x1028 +#define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 +#define CL_DEVICE_QUEUE_PROPERTIES 0x102A #define CL_DEVICE_NAME 0x102B #define CL_DEVICE_VENDOR 0x102C #define CL_DRIVER_VERSION 0x102D +#define CL_DEVICE_PROFILE 0x102E #define CL_DEVICE_VERSION 0x102F #define CL_DEVICE_EXTENSIONS 0x1030 #define CL_DEVICE_PLATFORM 0x1031 +#define CL_DEVICE_DOUBLE_FP_CONFIG 0x1032 +/* 0x1033 reserved for CL_DEVICE_HALF_FP_CONFIG */ +#define CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF 0x1034 +#define CL_DEVICE_HOST_UNIFIED_MEMORY 0x1035 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR 0x1036 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT 0x1037 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_INT 0x1038 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG 0x1039 +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT 0x103A +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE 0x103B +#define CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF 0x103C +#define CL_DEVICE_OPENCL_C_VERSION 0x103D +#define CL_DEVICE_LINKER_AVAILABLE 0x103E +#define CL_DEVICE_BUILT_IN_KERNELS 0x103F +#define CL_DEVICE_IMAGE_MAX_BUFFER_SIZE 0x1040 +#define CL_DEVICE_IMAGE_MAX_ARRAY_SIZE 0x1041 +#define CL_DEVICE_PARENT_DEVICE 0x1042 +#define CL_DEVICE_PARTITION_MAX_SUB_DEVICES 0x1043 +#define CL_DEVICE_PARTITION_PROPERTIES 0x1044 +#define CL_DEVICE_PARTITION_AFFINITY_DOMAIN 0x1045 +#define CL_DEVICE_PARTITION_TYPE 0x1046 +#define CL_DEVICE_REFERENCE_COUNT 0x1047 +#define CL_DEVICE_PREFERRED_INTEROP_USER_SYNC 0x1048 +#define CL_DEVICE_PRINTF_BUFFER_SIZE 0x1049 +#define CL_DEVICE_IMAGE_PITCH_ALIGNMENT 0x104A +#define CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT 0x104B // cl_device_fp_config - bitfield #define CL_FP_DENORM (1 << 0) diff --git a/opencl/Library_opencl.mk b/opencl/Library_opencl.mk index eb832208b654..501be304cfaf 100644 --- a/opencl/Library_opencl.mk +++ b/opencl/Library_opencl.mk @@ -24,6 +24,7 @@ $(eval $(call gb_Library_use_externals,opencl,\ icu_headers \ icui18n \ icuuc \ + libxml2 \ )) $(eval $(call gb_Library_use_custom_headers,opencl,\ @@ -37,6 +38,7 @@ $(eval $(call gb_Library_use_libraries,opencl,\ comphelper \ cppu \ sal \ + tl \ )) $(eval $(call gb_Library_add_exception_objects,opencl,\ diff --git a/opencl/inc/opencl_device.hxx b/opencl/inc/opencl_device.hxx index 3e9bdef6d899..7b5b79aec3dc 100644 --- a/opencl/inc/opencl_device.hxx +++ b/opencl/inc/opencl_device.hxx @@ -14,7 +14,7 @@ namespace opencl { -ds_device getDeviceSelection(const char* pFileName, bool bForceSelection = false); +ds_device getDeviceSelection(OUString pFileName, bool bForceSelection = false); } diff --git a/opencl/inc/opencl_device_selection.h b/opencl/inc/opencl_device_selection.h index b6a30fd5b01c..cf57b3183f8a 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() == false) + 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 (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 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; } diff --git a/opencl/source/openclwrapper.cxx b/opencl/source/openclwrapper.cxx index 74a925b75584..b17dc3ef9b55 100644 --- a/opencl/source/openclwrapper.cxx +++ b/opencl/source/openclwrapper.cxx @@ -703,9 +703,8 @@ bool switchOpenCLDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEv rtl::Bootstrap::expandMacros(url); OUString path; osl::FileBase::getSystemPathFromFileURL(url,path); - OString dsFileName = rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8); - ds_device pSelectedDevice = getDeviceSelection(dsFileName.getStr(), bForceEvaluation); - pDeviceId = pSelectedDevice.oclDeviceID; + ds_device pSelectedDevice = getDeviceSelection(path, bForceEvaluation); + pDeviceId = pSelectedDevice.aDeviceID; } |