summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToma┼ż Vajngerl <tomaz.vajngerl@collabora.co.uk>2016-04-20 22:19:47 +0900
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-04-25 08:53:18 +0000
commit8d3dd678bf9fd50a736cc0ff956f1efd7e660502 (patch)
tree2c03ac868b34340a0869d958cccca8d5cf2420a7
parent91e73f12fec47c8896122cfe72eb374bd283a132 (diff)
tdf#99453 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). (cherry picked from commit 334e2dc9c3da4519e31e0452a40d3a958c401876) Change-Id: I0fe793c756f8f4f1761fe120fc361df36e581903 Reviewed-on: https://gerrit.libreoffice.org/24303 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r--include/clew/clew.h67
-rw-r--r--opencl/Library_opencl.mk2
-rw-r--r--opencl/inc/opencl_device.hxx2
-rw-r--r--opencl/inc/opencl_device_selection.h817
-rw-r--r--opencl/source/opencl_device.cxx277
-rw-r--r--opencl/source/openclwrapper.cxx5
6 files changed, 604 insertions, 566 deletions
diff --git a/include/clew/clew.h b/include/clew/clew.h
index e5cfaf0836be..a1ae2aa133a8 100644
--- a/include/clew/clew.h
+++ b/include/clew/clew.h
@@ -412,19 +412,86 @@ typedef struct _cl_image_format {
#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 edc6adda2e04..4529da7129d3 100644
--- a/opencl/Library_opencl.mk
+++ b/opencl/Library_opencl.mk
@@ -23,6 +23,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..0963304e8f99 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 const & pFileName, bool bForceSelection = false);
}
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
diff --git a/opencl/source/opencl_device.cxx b/opencl/source/opencl_device.cxx
index 9a10d3651d1d..d70ea8180199 100644
--- a/opencl/source/opencl_device.cxx
+++ b/opencl/source/opencl_device.cxx
@@ -45,15 +45,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;
@@ -181,7 +177,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];
@@ -195,49 +191,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;
@@ -267,9 +236,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
@@ -277,30 +245,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
{
@@ -309,7 +276,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);
@@ -344,9 +310,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);
@@ -361,7 +326,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;
@@ -383,28 +347,46 @@ 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 (std::vector<ds_device>::size_type 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
@@ -414,32 +396,33 @@ 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
+ || rtl::math::approxEqual(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
{
@@ -448,59 +431,131 @@ 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, 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 const & 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 + "opencl_profile.xml";
+
if (!bForceSelection)
{
- status = readProfileFromFile(profile, deserializeScore, fileName);
+ status = readProfile(sFilePath, aProfile);
}
else
{
@@ -511,7 +566,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 */
@@ -523,23 +578,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
@@ -549,25 +603,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
{
@@ -581,11 +635,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 7bbcb2c3bce3..e488f79fb8bc 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;
}