[Libreoffice-commits] core.git: external/clew opencl/inc opencl/Library_opencl.mk opencl/source

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Fri Apr 22 11:27:28 UTC 2016


 external/clew/source/include/clew/clew.h |   67 ++
 opencl/Library_opencl.mk                 |    2 
 opencl/inc/opencl_device.hxx             |    2 
 opencl/inc/opencl_device_selection.h     |  817 +++++++++++++------------------
 opencl/source/opencl_device.cxx          |  279 ++++++----
 opencl/source/openclwrapper.cxx          |    5 
 6 files changed, 606 insertions(+), 566 deletions(-)

New commits:
commit 334e2dc9c3da4519e31e0452a40d3a958c401876
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Wed Apr 20 22:19:47 2016 +0900

    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 at gmail.com>
    Tested-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/external/clew/source/include/clew/clew.h b/external/clew/source/include/clew/clew.h
index f932b34..b23dc60 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 eb83220..501be30 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 3e9bdef..7b5b79a 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 b6a30fd..cf57b31 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 32a94df..af3bc18 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 74a925b..b17dc3e 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;
 
     }
 


More information about the Libreoffice-commits mailing list