/*
 * oclh_h_ws_log_clapi_reps.c
 *      Author: havock
 */
#include <string.h>
#include <oclh_h_settings.h>
#include <oclh_h_base_defs.h>
#include <oclh_h_base_clapi_strings.h>
#include <oclh_h_base_dev_clapi_wrappers.h>
#include <oclh_h_ws_base_log.h>
#include <oclh_h_ws_log_clapi_reps.h>
#include <oclh_hd_std_types.clh>
#include <oclh_h_internals.h>

int32_t _ghf_logWS_PlatfInfo(const _GHT_WRKSET    wSet,
                             const cl_platform_id Platform,
                             const char*    const pcPrefix) {
/* TODO: make ifdefs */
    cl_int clErr=0;
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG],
         pchPlatfPrefix[_GHM_MAXLEN_OF_LOGMSG],
         *pcText=NULL;
    size_t szRes=0ul;
    cl_uint cluCnt=0ul;
    if(pcPrefix && pcPrefix[0])
        snprintf(pchPlatfPrefix, _GHM_MAXLEN_OF_LOGMSG,
                 "%s platform_0x%04lx |",pcPrefix,__GHM_U64STRIPTO2B(Platform));
    else snprintf(pchPlatfPrefix, _GHM_MAXLEN_OF_LOGMSG,
                  "platform_0x%04lx |", __GHM_U64STRIPTO2B(Platform));
    for(cluCnt=CL_PLATFORM_PROFILE; cluCnt<=CL_PLATFORM_EXTENSIONS; cluCnt++) {
        clErr=clGetPlatformInfo(Platform, cluCnt, 0ul, NULL, &szRes);
        if(clErr) snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                           "%s %s: oclerr %s (%d)", pchPlatfPrefix,
                           _ghf_PlatfPropString(cluCnt),
                           _ghf_CLAPIErrString(clErr), clErr);
        else {
            pcText=malloc(szRes);
            if(pcText) {
                clErr=clGetPlatformInfo(Platform,cluCnt,szRes,pcText,&szRes);
                if(clErr)
                    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                             "%s %s: oclerr %s (%d)", pchPlatfPrefix,
                             _ghf_PlatfPropString(cluCnt),
                             _ghf_CLAPIErrString(clErr), clErr);
                else {
                    pcText[szRes-1]='\0';
                    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                             "%s %s: %s", pchPlatfPrefix,
                             _ghf_PlatfPropString(cluCnt), pcText);
                }
                if(pcText) { free(pcText); pcText=NULL; }
            } else snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                            "%s %s: Undefined! Host memory allocation failed",
                            pchPlatfPrefix, _ghf_PlatfPropString(cluCnt));
        }
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#ifdef CL_PLATFORM_HOST_TIMER_RESOLUTION
    {
        cl_ulong clulHTR=0ul;
        clErr=clGetPlatformInfo(Platform, CL_PLATFORM_HOST_TIMER_RESOLUTION,
                                sizeof(cl_ulong), &clulHTR, &szRes);
        if(clErr)
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s The resolution of the host timer "
                     "as used by clGetDeviceAndHostTimer: oclerr %s (%d)",
                     pchPlatfPrefix, _ghf_CLAPIErrString(clErr), clErr);
        else {
            pcText[szRes-1]='\0';
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s  The resolution of the host timer "
                     "as used by clGetDeviceAndHostTimer: %lu nanosec",
                     pchPlatfPrefix, (uint64_t)clulHTR);
        }
    }
#endif /* CL_PLATFORM_HOST_TIMER_RESOLUTION */
    return(_GHM_OK);
}

int32_t _ghf_logWS_DevInfo(      _GHT_WRKSET  wSet,
                           const cl_device_id clDev,
                           const _GHE_LOGLVL  LogLevel) {
/**/
#define __LOG(___LOGLVL_ARG,___TYPE_ARG,___KEY_ARG)          \
{ if(LogLevel>=___LOGLVL_ARG)                                \
   _ghf_logWS_DevInf_ ## ___TYPE_ARG (wSet, clDev,           \
    ___KEY_ARG, pcDev,                                       \
    _ghf_DevPropSuffixString(___KEY_ARG,_GHE_RT_PREFIX),     \
    _ghf_DevPropSuffixString(___KEY_ARG,_GHE_RT_POSTFIX)); }
/**/
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG], pcDev[64];
    snprintf(pcDev, 64ul, "dev_0x%04lx |", __GHM_U64STRIPTO2B(clDev));
#ifdef CL_DEVICE_TYPE
    if(LogLevel>=_GHE_LOG_KEY_PARS) { /* type */
        size_t szRes=0ul;
        cl_device_type clDevType=0ul;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=clGetDeviceInfo(clDev, CL_DEVICE_TYPE,
                                    sizeof(cl_device_type), &clDevType, &szRes);
        if(wSet.APIErr)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(clDevType%2)
                strncat(pcStr, "default ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((clDevType>>1)%2)
                strncat(pcStr, "CPU ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((clDevType>>2)%2)
                strncat(pcStr, "GPU ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((clDevType>>3)%2)
                strncat(pcStr, "Accelerator ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG, "%s Type: %s", pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_TYPE */
#ifdef CL_DEVICE_VENDOR_ID
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_VENDOR_ID)
#endif /* CL_DEVICE_VENDOR_ID */
#ifdef CL_DEVICE_MAX_COMPUTE_UNITS
__LOG(_GHE_LOG_KEY_PARS, cluint, CL_DEVICE_MAX_COMPUTE_UNITS)
#endif /* CL_DEVICE_MAX_COMPUTE_UNITS */
#ifdef CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS)
#endif /* CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS */
#ifdef CL_DEVICE_MAX_WORK_ITEM_SIZES
    if(LogLevel>=_GHE_LOG_ALL) { /* max work-item sizes */
        size_t szRes=0ul;
        cl_uint cluInf=_ghf_getDevInf_cluint(clDev,
                                             CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,
                                             &wSet.APIErr);
        size_t* pszDevInf=NULL;
        cl_uint cluCnt=0u;
        char pcVals[_GHM_MAXLEN_OF_LOGMSG]="\0";
        if(cluInf==(cl_uint) _GHM_UNDEFUINTVAL)
            snprintf(pcVals, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            pszDevInf=malloc(cluInf*sizeof(size_t));
            if(pszDevInf) {
                wSet.APIErr=
                    clGetDeviceInfo(clDev, CL_DEVICE_MAX_WORK_ITEM_SIZES,
                                    cluInf*sizeof(size_t),pszDevInf,&szRes);
                if(wSet.APIErr)
                    snprintf(pcVals, _GHM_MAXLEN_OF_LOGMSG,
                             "Undefined! clGetDeviceInfo returned %s(%d)",
                             _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
                else {
                    for(cluCnt=0u; cluCnt<cluInf; cluCnt++) {
                        char pcVal[16]="\0";
                        snprintf(pcVal, 16, "%lu", pszDevInf[cluCnt]);
                        strncat(pcVals, pcVal,
                                _GHM_MAXLEN_OF_LOGMSG-strlen(pcVals));
                        if(cluCnt<cluInf-1) strncat(pcVals, ",", 1);
                    }
                }
                if(pszDevInf) { free(pszDevInf); pszDevInf=NULL; }
            } else
                snprintf(pcVals, _GHM_MAXLEN_OF_LOGMSG,
                         "Undefined! Host memory allocation failed");
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Max work-item sizes: %s ", pcDev, pcVals);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_MAX_WORK_ITEM_SIZES */
#ifdef CL_DEVICE_MAX_WORK_GROUP_SIZE
__LOG(_GHE_LOG_KEY_PARS, size, CL_DEVICE_MAX_WORK_GROUP_SIZE)
#endif /* CL_DEVICE_MAX_WORK_GROUP_SIZE */
    if(LogLevel>=_GHE_LOG_ALL) { /* preferred vector sizes */
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Preferred vector sizes:", pcDev);
        _ghf_logWS_Msg(wSet, pcLogMsg);
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE */
#ifdef CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF)
#endif /* CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF */
    }
    if(LogLevel>=_GHE_LOG_ALL) { /* native vector sizes */
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Native vector sizes:", pcDev);
        _ghf_logWS_Msg(wSet, pcLogMsg);
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_INT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_INT */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE */
#ifdef CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF)
#endif /* CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF */
    }
#ifdef CL_DEVICE_MAX_CLOCK_FREQUENCY
__LOG(_GHE_LOG_KEY_PARS, cluint, CL_DEVICE_MAX_CLOCK_FREQUENCY)
#endif /* CL_DEVICE_MAX_CLOCK_FREQUENCY */
#ifdef CL_DEVICE_ADDRESS_BITS
__LOG(_GHE_LOG_KEY_PARS, cluint, CL_DEVICE_ADDRESS_BITS)
#endif /* CL_DEVICE_ADDRESS_BITS */
#ifdef CL_DEVICE_MAX_MEM_ALLOC_SIZE
__LOG(_GHE_LOG_ALL, clulong, CL_DEVICE_MAX_MEM_ALLOC_SIZE)
#endif /* CL_DEVICE_MAX_MEM_ALLOC_SIZE */
#ifdef CL_DEVICE_IMAGE_SUPPORT
    if(LogLevel>=_GHE_LOG_ALL) { /* image support */
        cl_bool clbV=_ghf_getDevInf_bool(clDev,
                                         CL_DEVICE_IMAGE_SUPPORT, &wSet.APIErr);
        if(clbV==(cl_bool) _GHM_UNDEFUINTVAL) {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Image support: Undefined! "
                     "clGetDeviceInfo returned %s(%d)", pcDev,
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            _ghf_logWS_Msg(wSet, pcLogMsg);
        } else {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Image support: %s ", pcDev, (clbV)?"Yes":"No");
            _ghf_logWS_Msg(wSet, pcLogMsg);
            if(clbV) {
#ifdef CL_DEVICE_MAX_READ_IMAGE_ARGS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_READ_IMAGE_ARGS)
#endif /* CL_DEVICE_MAX_READ_IMAGE_ARGS */
#ifdef CL_DEVICE_MAX_WRITE_IMAGE_ARGS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_WRITE_IMAGE_ARGS)
#endif /* CL_DEVICE_MAX_WRITE_IMAGE_ARGS */
#ifdef CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS)
#endif /* CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS */
#if defined(CL_DEVICE_IMAGE2D_MAX_WIDTH) && \
    defined(CL_DEVICE_IMAGE2D_MAX_HEIGHT)
                { /* 2D image max width and height */
                    cl_int clLocErr[2]={ 0, 0 };
                    size_t szWidth=
                            _ghf_getDevInf_size(clDev,
                                                CL_DEVICE_IMAGE2D_MAX_WIDTH,
                                                &clLocErr[0]),
                           szHeight=
                            _ghf_getDevInf_size(clDev,
                                                CL_DEVICE_IMAGE2D_MAX_HEIGHT,
                                                &clLocErr[1]);
                    if(szWidth !=(size_t)_GHM_UNDEFUINTVAL &&
                       szHeight!=(size_t)_GHM_UNDEFUINTVAL)
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Image support | "
                                 "Max 2D-image size (maxWidth x maxHeight): "
                                 "%lux%lu pixels", pcDev, szWidth, szHeight);
                    else
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Image support | "
                                 "Max 2D-image size (maxWidth x maxHeight): "
                                 "Undefined! oclerrs %s(%d) %s(%d)", pcDev,
                                 _ghf_CLAPIErrString(clLocErr[0]), clLocErr[0],
                                 _ghf_CLAPIErrString(clLocErr[1]), clLocErr[1]);
                    _ghf_logWS_Msg(wSet, pcLogMsg);
                }
#endif /* defined(CL_DEVICE_IMAGE2D_MAX_WIDTH) &&
          defined(CL_DEVICE_IMAGE2D_MAX_HEIGHT) */
#if defined(CL_DEVICE_IMAGE3D_MAX_WIDTH) && \
    defined(CL_DEVICE_IMAGE3D_MAX_HEIGHT) && \
    defined(CL_DEVICE_IMAGE3D_MAX_DEPTH)
                { /* 3D image max width and height */
                    cl_int clLocErr[3]={ 0, 0, 0 };
                    size_t szWidth=
                            _ghf_getDevInf_size(clDev,
                                                CL_DEVICE_IMAGE3D_MAX_WIDTH,
                                                &clLocErr[0]),
                           szHeight=
                            _ghf_getDevInf_size(clDev,
                                                CL_DEVICE_IMAGE3D_MAX_HEIGHT,
                                                &clLocErr[1]),
                           szDepth=
                            _ghf_getDevInf_size(clDev,
                                                CL_DEVICE_IMAGE3D_MAX_DEPTH,
                                                &clLocErr[2]);
                    if(szWidth !=(size_t)_GHM_UNDEFUINTVAL &&
                       szHeight!=(size_t)_GHM_UNDEFUINTVAL &&
                       szDepth !=(size_t)_GHM_UNDEFUINTVAL)
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Image support | Max 3D-image size "
                                 "(maxWidth x maxHeight x maxDepth): "
                                 "%lux%lux%lu pixels",
                                 pcDev, szWidth, szHeight, szDepth);
                    else
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Image support | Max 3D-image size "
                                 "(maxWidth x maxHeight x maxDepth): "
                                 "Undefined! oclerrs %s(%d) %s(%d) %s(%d)",
                                 pcDev,
                                 _ghf_CLAPIErrString(clLocErr[0]),clLocErr[0],
                                 _ghf_CLAPIErrString(clLocErr[1]),clLocErr[1],
                                 _ghf_CLAPIErrString(clLocErr[2]),clLocErr[2]);
                    _ghf_logWS_Msg(wSet, pcLogMsg);
                }
#endif /* defined(CL_DEVICE_IMAGE3D_MAX_WIDTH) &&
          defined(CL_DEVICE_IMAGE3D_MAX_HEIGHT) &&
          defined(CL_DEVICE_IMAGE3D_MAX_DEPTH) */
#ifdef CL_DEVICE_IMAGE_MAX_BUFFER_SIZE
__LOG(_GHE_LOG_ALL, size, CL_DEVICE_IMAGE_MAX_BUFFER_SIZE)
#endif /* CL_DEVICE_IMAGE_MAX_BUFFER_SIZE */
#ifdef CL_DEVICE_IMAGE_MAX_ARRAY_SIZE
__LOG(_GHE_LOG_ALL, size, CL_DEVICE_IMAGE_MAX_ARRAY_SIZE)
#endif /* CL_DEVICE_IMAGE_MAX_ARRAY_SIZE */
#ifdef CL_DEVICE_MAX_SAMPLERS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_SAMPLERS)
#endif /* CL_DEVICE_MAX_SAMPLERS */
#ifdef CL_DEVICE_IMAGE_PITCH_ALIGNMENT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_IMAGE_PITCH_ALIGNMENT)
#endif /* CL_DEVICE_IMAGE_PITCH_ALIGNMENT */
#ifdef CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT)
#endif /* CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT */
            }
        }
    }
#endif /* CL_DEVICE_IMAGE_SUPPORT */
#ifdef CL_DEVICE_MAX_PIPE_ARGS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_PIPE_ARGS)
#endif /* CL_DEVICE_MAX_PIPE_ARGS */
#ifdef CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS)
#endif /* CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS */
#ifdef CL_DEVICE_PIPE_MAX_PACKET_SIZE
__LOG(_GHE_LOG_ALL, cluint_as_bytes, CL_DEVICE_PIPE_MAX_PACKET_SIZE)
#endif /* CL_DEVICE_PIPE_MAX_PACKET_SIZE */
#ifdef CL_DEVICE_MAX_PARAMETER_SIZE
__LOG(_GHE_LOG_ALL, size, CL_DEVICE_MAX_PARAMETER_SIZE)
#endif /* CL_DEVICE_MAX_PARAMETER_SIZE */
#ifdef CL_DEVICE_MEM_BASE_ADDR_ALIGN
__LOG(_GHE_LOG_KEY_PARS, cluint, CL_DEVICE_MEM_BASE_ADDR_ALIGN)
#endif /* CL_DEVICE_MEM_BASE_ADDR_ALIGN */
#ifdef CL_DEVICE_SINGLE_FP_CONFIG
    if(LogLevel>=_GHE_LOG_ALL) {
        /* supported single precision floating-point capabilities */
        size_t szRes=0;
        cl_device_fp_config cldfpcInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_SINGLE_FP_CONFIG,
                            sizeof(cl_device_fp_config), &cldfpcInf, &szRes);
        if(cldfpcInf==(cl_device_fp_config)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldfpcInf%2)
                strncat(pcStr, "denorms; ",_GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>1)%2)
                strncat(pcStr, "INF and quiet NaNs; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>2)%2)
                strncat(pcStr, "round to nearest; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>3)%2)
                strncat(pcStr, "round to zero; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>4)%2)
                strncat(pcStr, "round to +/-infinity; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>5)%2)
                strncat(pcStr, "IEEE754-2008 fused multiply-add; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            if((cldfpcInf>>6)%2)
                strncat(pcStr, "basic floating-point operations; ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Supported "
                 "single precision floating-point capabilities: %s",
                 pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_SINGLE_FP_CONFIG */
#ifdef CL_DEVICE_DOUBLE_FP_CONFIG
    if(LogLevel>=_GHE_LOG_ALL) {
        /* supported double precision floating-point capabilities */
        size_t szRes=0ul;
        cl_device_fp_config cldfpcInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_DOUBLE_FP_CONFIG,
                            sizeof(cl_device_fp_config), &cldfpcInf, &szRes);
        if(cldfpcInf==(cl_device_fp_config)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldfpcInf==0) strncat(pcStr, "unsupported",
                                     _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(cldfpcInf%2) strncat(pcStr, "denorms; ",
                                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>1)%2)
                    strncat(pcStr, "INF and quiet NaNs; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>2)%2)
                    strncat(pcStr, "round to nearest; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>3)%2)
                    strncat(pcStr, "round to zero; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>4)%2)
                    strncat(pcStr, "round to +/-infinity; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>5)%2)
                    strncat(pcStr, "IEEE754-2008 fused multiply-add; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldfpcInf>>6)%2)
                    strncat(pcStr, "basic floating-point operations; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Double precision floating-point support: %s",pcDev,pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_DOUBLE_FP_CONFIG */
#ifdef CL_DEVICE_GLOBAL_MEM_CACHE_TYPE
    if(LogLevel>=_GHE_LOG_ALL) { /* global memory cache support */
        size_t szRes=0ul;
        cl_device_mem_cache_type cldmctInf;
        char pcStr[32]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,
                            sizeof(cl_device_mem_cache_type),&cldmctInf,&szRes);
        if(cldmctInf==(cl_device_mem_cache_type)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldmctInf==0) strncpy(pcStr, "No",         sizeof(pcStr));
            if(cldmctInf==1) strncpy(pcStr, "read only",  sizeof(pcStr));
            if(cldmctInf==2) strncpy(pcStr, "read-write", sizeof(pcStr));
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Global memory cache support: %s", pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_GLOBAL_MEM_CACHE_TYPE */
#ifdef CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE)
#endif /* CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE */
#ifdef CL_DEVICE_GLOBAL_MEM_CACHE_SIZE
__LOG(_GHE_LOG_ALL, clulong, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE)
#endif /* CL_DEVICE_GLOBAL_MEM_CACHE_SIZE */
#ifdef CL_DEVICE_GLOBAL_MEM_SIZE
__LOG(_GHE_LOG_KEY_PARS, clulong, CL_DEVICE_GLOBAL_MEM_SIZE)
#endif /* CL_DEVICE_GLOBAL_MEM_SIZE */
#ifdef CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE
__LOG(_GHE_LOG_ALL, clulong, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE)
#endif /* CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE */
#ifdef CL_DEVICE_MAX_CONSTANT_ARGS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_CONSTANT_ARGS)
#endif /* CL_DEVICE_MAX_CONSTANT_ARGS */
#ifdef CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE
__LOG(_GHE_LOG_ALL, size_as_bytes, CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE)
#endif /* CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE */
#ifdef CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE
__LOG(_GHE_LOG_ALL,size_as_bytes,CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE)
#endif /* CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE */
#ifdef CL_DEVICE_LOCAL_MEM_TYPE
    if(LogLevel>=_GHE_LOG_ALL) { /* Type of local memory supported */
        size_t szRes=0ul;
        cl_device_local_mem_type cldlmtInf;
        char pcStringType[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_LOCAL_MEM_TYPE,
                            sizeof(cl_device_local_mem_type),&cldlmtInf,&szRes);
        if(cldlmtInf==(cl_device_local_mem_type)_GHM_UNDEFUINTVAL)
            snprintf(pcStringType, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldlmtInf==1) strncpy(pcStringType, "local",
                                     sizeof(pcStringType));
            if(cldlmtInf==2) strncpy(pcStringType, "global",
                                     sizeof(pcStringType));
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Type of local memory supported: %s", pcDev, pcStringType);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_LOCAL_MEM_TYPE */
#ifdef CL_DEVICE_LOCAL_MEM_SIZE
__LOG(_GHE_LOG_ALL, clulong, CL_DEVICE_LOCAL_MEM_SIZE)
#endif /* CL_DEVICE_LOCAL_MEM_SIZE */
#ifdef CL_DEVICE_ERROR_CORRECTION_SUPPORT
    if(LogLevel>=_GHE_LOG_ALL)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_ERROR_CORRECTION_SUPPORT, pcDev,
                               "Error correction support:", "Yes", "No");
#endif /* CL_DEVICE_ERROR_CORRECTION_SUPPORT */
#ifdef CL_DEVICE_PROFILING_TIMER_RESOLUTION
__LOG(_GHE_LOG_KEY_PARS, size, CL_DEVICE_PROFILING_TIMER_RESOLUTION)
#endif /* CL_DEVICE_PROFILING_TIMER_RESOLUTION */
#ifdef CL_DEVICE_ENDIAN_LITTLE
    if(LogLevel>=_GHE_LOG_KEY_PARS)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_ENDIAN_LITTLE, pcDev,
                               "Endianness:", "little-endian", "big-endian");
#endif /* CL_DEVICE_ENDIAN_LITTLE */
#ifdef CL_DEVICE_AVAILABLE
    if(LogLevel>=_GHE_LOG_KEY_PARS)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_AVAILABLE, pcDev,
                               "Is device available:", "Yes", "No");
#endif /* CL_DEVICE_AVAILABLE */
#ifdef CL_DEVICE_COMPILER_AVAILABLE
    if(LogLevel>=_GHE_LOG_KEY_PARS)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_COMPILER_AVAILABLE, pcDev,
                               "Is device compiler available:", "Yes", "No");
#endif /* CL_DEVICE_COMPILER_AVAILABLE */
#ifdef CL_DEVICE_LINKER_AVAILABLE
    if(LogLevel>=_GHE_LOG_KEY_PARS)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_LINKER_AVAILABLE, pcDev,
                               "Is device linker available:", "Yes", "No");
#endif /* CL_DEVICE_LINKER_AVAILABLE */
  /*
   * TODO: CL_DEVICE_IL_VERSION
   */
#ifdef CL_DEVICE_EXECUTION_CAPABILITIES
    if(LogLevel>=_GHE_LOG_ALL) { /* supported execution capabilities */
        size_t szRes=0ul;
        cl_device_exec_capabilities cldecInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_EXECUTION_CAPABILITIES,
                            sizeof(cl_device_exec_capabilities),
                            &cldecInf, &szRes);
        if(cldecInf==(cl_device_exec_capabilities)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldecInf==0)
                strncat(pcStr,"unsupported",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(cldecInf%2)
                    strncat(pcStr, "OpenCL kernels; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldecInf>>1)%2)
                    strncat(pcStr, "native kernels; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Execution capabilities of the device: %s", pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_EXECUTION_CAPABILITIES */
#ifdef CL_DEVICE_QUEUE_PROPERTIES
    if(LogLevel>=_GHE_LOG_ALL) {
        /* command-queue properties supported by the device */
        size_t szRes=0ul;
        cl_command_queue_properties clcqpInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_QUEUE_PROPERTIES,
                            sizeof(cl_command_queue_properties),
                            &clcqpInf, &szRes);
        if(clcqpInf==(cl_command_queue_properties)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(clcqpInf==0)
                strncat(pcStr, "unsupported",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(clcqpInf%2)
                    strncat(pcStr, "out of order execution mode; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>1)%2)
                    strncat(pcStr, "profiling; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>2)%2)
                    strncat(pcStr, "device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>3)%2)
                    strncat(pcStr, "default device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Command-queue properties supported by the device: %s",
                 pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_QUEUE_PROPERTIES */
#ifdef CL_DEVICE_QUEUE_ON_HOST_PROPERTIES
    if(LogLevel>=_GHE_LOG_ALL) {
        /* host command-queue properties supported by the device */
        size_t szRes=0ul;
        cl_command_queue_properties clcqpInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_QUEUE_ON_HOST_PROPERTIES,
                            sizeof(cl_command_queue_properties),
                            &clcqpInf, &szRes);
        if(clcqpInf==(cl_command_queue_properties)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(clcqpInf==0)
                strncat(pcStr, "unsupported",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(clcqpInf%2)
                    strncat(pcStr, "out of order execution mode; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>1)%2)
                    strncat(pcStr, "profiling; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>2)%2)
                    strncat(pcStr, "device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>3)%2)
                    strncat(pcStr, "default device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Host command-queue properties supported by the device: %s",
                 pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_QUEUE_ON_HOST_PROPERTIES */
#ifdef CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES
    if(LogLevel>=_GHE_LOG_ALL) {
        /* device command-queue properties supported by the device */
        size_t szRes=0ul;
        cl_command_queue_properties clcqpInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES,
                            sizeof(cl_command_queue_properties),
                            &clcqpInf, &szRes);
        if(clcqpInf==(cl_command_queue_properties)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(clcqpInf==0)
                strncat(pcStr, "unsupported",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(clcqpInf%2)
                    strncat(pcStr, "out of order execution mode; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>1)%2)
                    strncat(pcStr, "profiling; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>2)%2)
                    strncat(pcStr, "device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((clcqpInf>>3)%2)
                    strncat(pcStr, "default device queue; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Device command-queue properties supported by "
                 "the device: %s", pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES */
#ifdef CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE)
#endif /* CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE */
#ifdef CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE)
#endif /* CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE */
#ifdef CL_DEVICE_MAX_ON_DEVICE_QUEUES
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_ON_DEVICE_QUEUES)
#endif /* CL_DEVICE_MAX_ON_DEVICE_QUEUES */
#ifdef CL_DEVICE_MAX_ON_DEVICE_EVENTS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_ON_DEVICE_EVENTS)
#endif /* CL_DEVICE_MAX_ON_DEVICE_EVENTS */
#ifdef CL_DEVICE_BUILT_IN_KERNELS
__LOG(_GHE_LOG_ALL, charptr, CL_DEVICE_BUILT_IN_KERNELS)
#endif /* CL_DEVICE_BUILT_IN_KERNELS */
#ifdef CL_DEVICE_PLATFORM
    if(LogLevel>=_GHE_LOG_KEY_PARS) {
        cl_platform_id clPlatf=
            (cl_platform_id)_ghf_getDevInf_uintptr(clDev, CL_DEVICE_PLATFORM,
                                                   &wSet.APIErr);
        if(clPlatf) {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG, /* ??????? */
                     "%s Platform: %04lx", pcDev, __GHM_U64STRIPTO2B(clPlatf));
            char pcTmpPrefix[64]="\0";
            snprintf(pcTmpPrefix, 64, "%s ", pcDev);
            _ghf_logWS_PlatfInfo(wSet,clPlatf,pcTmpPrefix);
        } else {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Platform: Undefined! clGetDeviceInfo returned %s(%d)",
                     pcDev, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            _ghf_logWS_Msg(wSet, pcLogMsg);
        }
    }
#endif /* CL_DEVICE_PLATFORM */
#ifdef CL_DEVICE_NAME
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_NAME)
#endif /* CL_DEVICE_NAME */
#ifdef CL_DEVICE_VENDOR
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_VENDOR)
#endif /* CL_DEVICE_VENDOR */
#ifdef CL_DRIVER_VERSION
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DRIVER_VERSION)
#endif /* CL_DRIVER_VERSION */
#ifdef CL_DEVICE_PROFILE
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_PROFILE)
#endif /* CL_DEVICE_PROFILE */
#ifdef CL_DEVICE_VERSION
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_VERSION)
#endif /* CL_DEVICE_VERSION */
#ifdef CL_DEVICE_OPENCL_C_VERSION
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_OPENCL_C_VERSION)
#endif /* CL_DEVICE_OPENCL_C_VERSION */
#ifdef CL_DEVICE_EXTENSIONS
__LOG(_GHE_LOG_KEY_PARS, charptr, CL_DEVICE_EXTENSIONS)
#endif /* CL_DEVICE_EXTENSIONS */
#ifdef CL_DEVICE_PRINTF_BUFFER_SIZE
__LOG(_GHE_LOG_KEY_PARS, size, CL_DEVICE_PRINTF_BUFFER_SIZE)
#endif /* CL_DEVICE_PRINTF_BUFFER_SIZE */
#ifdef CL_DEVICE_PREFERRED_INTEROP_USER_SYNC
    if(LogLevel>=_GHE_LOG_ALL)
        _ghf_logWS_DevInf_bool(wSet, clDev,
                               CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, pcDev,
                               "Is device preferred for "
                               "the user's responsibility for sync:",
                               "Yes", "No");
#endif /* CL_DEVICE_PREFERRED_INTEROP_USER_SYNC */
#ifdef CL_DEVICE_PARENT_DEVICE
__LOG(_GHE_LOG_ALL, clulong_as_hex, CL_DEVICE_PARENT_DEVICE)
#endif /* CL_DEVICE_PARENT_DEVICE */
#ifdef CL_DEVICE_PARTITION_MAX_SUB_DEVICES
__LOG(_GHE_LOG_KEY_PARS, cluint, CL_DEVICE_PARTITION_MAX_SUB_DEVICES)
#endif /* CL_DEVICE_PARTITION_MAX_SUB_DEVICES */
    /*
     * TODO:
     * CL_DEVICE_PARTITION_PROPERTIES
     * CL_DEVICE_PARTITION_AFFINITY_DOMAIN
     * CL_DEVICE_PARTITION_TYPE
     */
#ifdef CL_DEVICE_REFERENCE_COUNT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_REFERENCE_COUNT)
#endif /* CL_DEVICE_REFERENCE_COUNT */
#ifdef CL_DEVICE_SVM_CAPABILITIES
    if(LogLevel>=_GHE_LOG_ALL) {
        /* shared virtual memory allocation types the device supports */
        size_t szRes=0ul;
        cl_device_svm_capabilities cldsvmcInf;
        char pcStr[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetDeviceInfo(clDev, CL_DEVICE_SVM_CAPABILITIES,
                            sizeof(cl_device_svm_capabilities),
                            &cldsvmcInf, &szRes);
        if(cldsvmcInf==(cl_device_svm_capabilities)_GHM_UNDEFUINTVAL)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(cldsvmcInf==0)
                strncat(pcStr, "unsupported",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            else {
                if(cldsvmcInf%2)
                    strncat(pcStr,
                            "coarse-grain buffer sharing using clSVMAlloc; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldsvmcInf>>1)%2)
                    strncat(pcStr,
                            "fine-grain buffer sharing using clSVMAlloc; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldsvmcInf>>2)%2)
                    strncat(pcStr,
                            "sharing the host’s entire virtual memory "
                            "including memory allocated using malloc; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
                if((cldsvmcInf>>3)%2)
                    strncat(pcStr,
                            "atomic operations provide memory consistency "
                            "across the host and all devices supporting "
                            "fine-grain allocations; ",
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
            }
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Shared virtual memory allocation types "
                 "the device supports: %s", pcDev, pcStr);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_DEVICE_SVM_CAPABILITIES */
#ifdef CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT)
#endif /* CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT */
#ifdef CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT)
#endif /* CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT */
#ifdef CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT)
#endif /* CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT */
#ifdef CL_DEVICE_MAX_NUM_SUB_GROUPS
__LOG(_GHE_LOG_ALL, cluint, CL_DEVICE_MAX_NUM_SUB_GROUPS)
#endif /* CL_DEVICE_MAX_NUM_SUB_GROUPS */
        /*
         * TODO: CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS
         */
    return(_GHM_OK);
/**/
#undef __LOG
/**/
}

int32_t _ghf_logWS_DevInfoShort(      _GHT_WRKSET  wSet,
                                const cl_device_id clDev,
                                const char*  const pcPrefix) {
    /* TODO: make ifdefs */
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG]   ="\0",
         pcStr[_GHM_MAXLEN_OF_LOGMSG]      ="\0",
         pcDevPrefix[_GHM_MAXLEN_OF_LOGMSG]="\0";
    size_t szRes=0ul;
    cl_device_type clDevType=0ul;
    if(pcPrefix && pcPrefix[0])
        snprintf(pcDevPrefix, _GHM_MAXLEN_OF_LOGMSG,
                 "%s dev_0x%04lx |", pcPrefix, __GHM_U64STRIPTO2B(clDev));
    else snprintf(pcDevPrefix, _GHM_MAXLEN_OF_LOGMSG,
                  "dev_0x%04lx |", __GHM_U64STRIPTO2B(clDev));
    wSet.APIErr=
        clGetDeviceInfo(clDev, CL_DEVICE_TYPE,
                        sizeof(cl_device_type),&clDevType,&szRes);
    if(wSet.APIErr)
        snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                 "Undefined! clGetDeviceInfo/CL_DEVICE_TYPE returned %s(%d)",
                 _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
    else {
        if(clDevType%2)
            strncat(pcStr, "default",     _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
        if((clDevType>>1)%2)
            strncat(pcStr, "CPU",         _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
        if((clDevType>>2)%2)
            strncat(pcStr, "GPU",         _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
        if((clDevType>>3)%2)
            strncat(pcStr, "Accelerator", _GHM_MAXLEN_OF_LOGMSG-strlen(pcStr));
    }
    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
             "%s %s: %u units/%u MHz/%lu ns timer/%s", pcDevPrefix, pcStr,
             _ghf_getDevInf_cluint(clDev, CL_DEVICE_MAX_COMPUTE_UNITS,
                                   &wSet.APIErr),
             _ghf_getDevInf_cluint(clDev, CL_DEVICE_MAX_CLOCK_FREQUENCY,
                                   &wSet.APIErr),
             _ghf_getDevInf_size(  clDev, CL_DEVICE_PROFILING_TIMER_RESOLUTION,
                                   &wSet.APIErr),
             _ghf_getDevInf_bool(  clDev, CL_DEVICE_ENDIAN_LITTLE,
                                   &wSet.APIErr)?"little-endian":"big-endian");
    _ghf_logWS_Msg(wSet, pcLogMsg);
    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
             "%s Mem: %.3f MiB/%u bits address ", pcDevPrefix,
             ((flt32_t)_ghf_getDevInf_clulong(clDev, CL_DEVICE_GLOBAL_MEM_SIZE,
                                              &wSet.APIErr))/1024e0f/1024e0f,
             _ghf_getDevInf_cluint(clDev, CL_DEVICE_ADDRESS_BITS,&wSet.APIErr));
    _ghf_logWS_Msg(wSet, pcLogMsg);
    {
        char* pcVendor=_ghf_getDevInf_charptr(_ghf_getWS_Dev(wSet),
                                              CL_DEVICE_VENDOR, &wSet.APIErr),
            * pcModel=_ghf_getDevInf_charptr(_ghf_getWS_Dev(wSet),
                                              CL_DEVICE_NAME, &wSet.APIErr);
        __ghf_removePreNPostSpacesFromCharPtr(pcVendor);
        __ghf_removePreNPostSpacesFromCharPtr(pcModel);
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Vendor/model: %s / %s ", pcDevPrefix,
                 pcVendor?pcVendor:"Undefined",pcModel?pcModel:"Undefined");
        _ghf_logWS_Msg(wSet, pcLogMsg);
        if(pcVendor) { free(pcVendor); pcVendor=NULL; }
        if(pcModel)  { free(pcModel);  pcModel =NULL; }
    }
    {
        char* pcHWvers=_ghf_getDevInf_charptr(clDev, CL_DEVICE_VERSION,
                                              &wSet.APIErr),
            * pcHWlang=_ghf_getDevInf_charptr(clDev, CL_DEVICE_OPENCL_C_VERSION,
                                              &wSet.APIErr);
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s HW ver./lang ver.: %s / %s", pcDevPrefix,
                 pcHWvers?pcHWvers:"Undefined",
                 pcHWlang?pcHWlang:"Undefined");
        if(pcHWvers) { free(pcHWvers); pcHWvers=NULL; }
        if(pcHWlang) { free(pcHWlang); pcHWlang=NULL; }
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    {
        char* pcDRVvers=
            _ghf_getDevInf_charptr(clDev, CL_DRIVER_VERSION, &wSet.APIErr);
        uint64_t off=0ul;
        cl_platform_id clplidPlatf=
            (cl_platform_id)_ghf_getDevInf_uintptr(clDev,CL_DEVICE_PLATFORM,
                                                   &wSet.APIErr);
        if(wSet.APIErr)
            off+=(uint64_t)snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG, "Undefined");
        wSet.APIErr=clGetPlatformInfo(clplidPlatf, CL_PLATFORM_NAME, 0ul,
                                      NULL, &szRes);
        if(wSet.APIErr) {
            off+=(uint64_t)snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                                    "Undefined");
        } else {
            wSet.APIErr=clGetPlatformInfo(clplidPlatf, CL_PLATFORM_NAME,
                                          _GHM_MAXLEN_OF_LOGMSG-1ul, pcStr,
                                          &szRes);
            if(wSet.APIErr) {
                off+=(uint64_t)snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                                        "Undefined");
            } else off+=(szRes-1ul);
        }
        off+=(uint64_t)snprintf(&pcStr[off], _GHM_MAXLEN_OF_LOGMSG, "-ver.");
        wSet.APIErr=clGetPlatformInfo(clplidPlatf, CL_PLATFORM_VERSION, 0ul,
                                      NULL, &szRes);
        if(wSet.APIErr) {
            snprintf(&pcStr[off], _GHM_MAXLEN_OF_LOGMSG, "Undefined");
        } else {
            wSet.APIErr=clGetPlatformInfo(clplidPlatf, CL_PLATFORM_VERSION,
                                          _GHM_MAXLEN_OF_LOGMSG-off,&pcStr[off],
                                          &szRes);
            if(wSet.APIErr)
                snprintf(&pcStr[off], _GHM_MAXLEN_OF_LOGMSG, "Undefined");
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Drv ver./SW: %s / %s", pcDevPrefix,
                 pcDRVvers?pcDRVvers:"Undefined",
                 pcStr);
        if(pcDRVvers) { free(pcDRVvers); pcDRVvers=NULL; }
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    {
        char* pcExtensions=
            _ghf_getDevInf_charptr(clDev, CL_DEVICE_EXTENSIONS, &wSet.APIErr);
        if(wSet.APIErr || !pcExtensions)
            snprintf(pcStr, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetDeviceInfo/CL_DRIVER_VERSION "
                     "returned %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Extensions: %s",pcDevPrefix,
                 pcExtensions?pcExtensions:pcStr);
        if(pcExtensions) { free(pcExtensions); pcExtensions=NULL; }
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    return(_GHM_OK);
}

int32_t _ghf_logWS_ContextInfo(      _GHT_WRKSET wSet,
                               const cl_context  clCtx,
                               const _GHE_LOGLVL LogLevel) {
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG], pcCtx[64];
    size_t szRes=0ul;
    cl_uint cluInf=0u;
    snprintf(pcCtx, 64ul, "context_0x%04lx |", __GHM_U64STRIPTO2B(clCtx));
#ifdef CL_CONTEXT_REFERENCE_COUNT
    if(LogLevel>=_GHE_LOG_ALL) { /* refcount */
        wSet.APIErr=
            clGetContextInfo(clCtx, CL_CONTEXT_REFERENCE_COUNT,
                             sizeof(cl_uint), &cluInf, &szRes);
        if(wSet.APIErr)
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Reference count: Undefined! "
                     "clGetContextInfo returned oclerr %s(%d)",
                     pcCtx, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Reference count: %u", pcCtx, (uint32_t)cluInf);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
#endif /* CL_CONTEXT_REFERENCE_COUNT */
#ifdef CL_CONTEXT_NUM_DEVICES
    { /* number of devices */
        wSet.APIErr=
            clGetContextInfo(clCtx, CL_CONTEXT_NUM_DEVICES,
                             sizeof(cl_uint), &cluInf, &szRes);
        if(wSet.APIErr) {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Number of devices: Undefined! "
                     "clGetContextInfo returned oclerr %s(%d)",
                     pcCtx, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            _ghf_logWS_Msg(wSet, pcLogMsg);
        } else
            if(LogLevel>=_GHE_LOG_ALL) {
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s Number of devices: %u", pcCtx, (uint32_t)cluInf);
                _ghf_logWS_Msg(wSet, pcLogMsg);
        }
    }
#endif /* CL_CONTEXT_NUM_DEVICES */
#ifdef CL_CONTEXT_DEVICES
    if(LogLevel>=_GHE_LOG_KEY_PARS) { /* Devices in context */
        cl_device_id* pclDev=NULL;
        pclDev=malloc(sizeof(cl_device_id)*cluInf);
        if(pclDev) {
            wSet.APIErr=
                clGetContextInfo(clCtx, CL_CONTEXT_DEVICES,
                                 sizeof(cl_device_id)*cluInf, pclDev, &szRes);
            if(wSet.APIErr)
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s Device ID(s): Undefined! "
                         "clGetContextInfo returned oclerr %s(%d)",
                         pcCtx, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            else {
                cl_uint i=0u;
                char pcVal[24]="\0";
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s Device ID(s):", pcCtx);
                for(i=0u; i<cluInf; i++) {
                    snprintf(pcVal,24ul, " 0x%lx", (uint64_t)pclDev[i]);
                    strncat(pcLogMsg, pcVal,
                            _GHM_MAXLEN_OF_LOGMSG-strlen(pcLogMsg));
                }
                _ghf_logWS_Msg(wSet, pcLogMsg);
                {
                    char pcTmpPrefix[64]="\0";
                    snprintf(pcTmpPrefix, 64ul, "%s ", pcCtx);
                    for(i=0u; i<cluInf; i++)
                        _ghf_logWS_DevInfoShort(wSet, pclDev[i], pcTmpPrefix);
                }
            }
            if(pclDev) { free(pclDev); pclDev=NULL; }
        } else {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Device ID(s): %s", pcCtx,
                     "Undefined! Host memory allocation failed");
            _ghf_logWS_Msg(wSet, pcLogMsg);
        }
    }
#endif /* CL_CONTEXT_DEVICES */
#ifdef CL_CONTEXT_PROPERTIES
    if(LogLevel>=_GHE_LOG_ALL) { /* context properties */
        wSet.APIErr=
            clGetContextInfo(clCtx, CL_CONTEXT_PROPERTIES, 0ul, NULL, &szRes);
        if(wSet.APIErr) {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                     "%s Context properties: Undefined! "
                     "clGetContextInfo returned oclerr %s(%d)",
                     pcCtx, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            _ghf_logWS_Msg(wSet, pcLogMsg);
        } else {
            cl_context_properties* pclCtxProps=NULL;
            pclCtxProps=malloc(szRes);
            if(!pclCtxProps) return(_GHM_HOST_MEMALLOC_ERROR);
            wSet.APIErr=
                clGetContextInfo(clCtx, CL_CONTEXT_PROPERTIES,
                                 szRes, pclCtxProps, &szRes);
            if(!wSet.APIErr) {
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s Context properties:", pcCtx);
                _ghf_logWS_Msg(wSet, pcLogMsg);
                {
                    uint64_t i=0ul;
                    while(pclCtxProps[i]!=CL_CONTEXT_PLATFORM &&
                          pclCtxProps[i+2] ) i+=2;
                    if(pclCtxProps[i]==CL_CONTEXT_PLATFORM) {
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Platform: 0x%04lx",
                                 pcCtx, __GHM_U64STRIPTO2B(pclCtxProps[i+1]));
                        _ghf_logWS_Msg(wSet, pcLogMsg);
                        {
                            char pcTmpPrefix[64]="\0";
                            snprintf(pcTmpPrefix, 64ul, "%s  ", pcCtx);
                            _ghf_logWS_PlatfInfo(wSet,
                                  (cl_platform_id)pclCtxProps[i+1],pcTmpPrefix);
                        }
                    }
                }
                {
                    uint64_t i=0ul;
                    while(pclCtxProps[i]!=CL_CONTEXT_INTEROP_USER_SYNC &&
                          pclCtxProps[i+2] ) i+=2;
                    if(pclCtxProps[i]==CL_CONTEXT_INTEROP_USER_SYNC) {
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Is user responsible for sync: %s",
                                 pcCtx,((cl_bool) pclCtxProps[i+1])?"Yes":"No");
                        _ghf_logWS_Msg(wSet, pcLogMsg);
                    } else {
                        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                                 "%s  Is user responsible for sync: "
                                 "Undefined (presumable No)", pcCtx);
                        _ghf_logWS_Msg(wSet, pcLogMsg);
                    }
                }
            } else {
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s Context properties:", pcCtx);
                _ghf_logWS_Msg(wSet, pcLogMsg);
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s  Platform: Undefined", pcCtx);
                _ghf_logWS_Msg(wSet, pcLogMsg);
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                         "%s  Is user responsible for sync: "
                         "Undefined (presumable No)", pcCtx);
                _ghf_logWS_Msg(wSet, pcLogMsg);
            }
            if(pclCtxProps) { free(pclCtxProps); pclCtxProps=NULL; }
        }
    }
#endif /* CL_CONTEXT_PROPERTIES */
    return(_GHM_OK);
}

int32_t _ghf_logWS_BuildInfo(      _GHT_WRKSET  wSet,
                             const cl_program   clProgram,
                             const cl_device_id clDev,
                             const _GHE_LOGLVL  LogLevel,
                             const _GHE_BUILD_LOG_MODE BuildLogMode) {
    /* TODO: make ifdefs for queries */
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG],
         pcProgram[64];
    cl_build_status clStatus=0;
    snprintf(pcProgram, sizeof(pcProgram),
             "program_0x%04lx |", __GHM_U64STRIPTO2B(clProgram));
    { /* options */
        char* pcVal=NULL;
        size_t szRes=0ul;
        wSet.APIErr=
            clGetProgramBuildInfo(clProgram, clDev,
                                  CL_PROGRAM_BUILD_OPTIONS, 0ul, NULL, &szRes);
        if(wSet.APIErr)
            snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                     "%s Compiler options: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                     "%s Linker options: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                     "%s Build options: Undefined! "
#endif
                     "clGetDeviceInfo returned oclerr %s(%d)",
                     pcProgram, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            pcVal=malloc(szRes);
            if(pcVal) {
                wSet.APIErr=
                    clGetProgramBuildInfo(clProgram, clDev,
                                          CL_PROGRAM_BUILD_OPTIONS,
                                          szRes, pcVal, &szRes);
                if(wSet.APIErr)
                    snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                             "%s Compiler options: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Linker options: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Build options: Undefined! "
#endif
                             "clGetDeviceInfo returned oclerr %s(%d)",
                             pcProgram,
                             _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
                else {
                    pcVal[szRes-1]='\0';
                    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                             "%s Compiler options: %s",
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Linker options: %s",
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Build options: %s",
#endif
                             pcProgram, pcVal);
                }
                if(pcVal) { free(pcVal); pcVal=NULL; }
            } else
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                         "%s Compiler options: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                         "%s Linker options: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                         "%s Build options: Undefined! "
#endif
                         "Host memory allocation failed", pcProgram);
        }
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    { /* status */
        size_t szRes=0ul;
        char pcVal[_GHM_MAXLEN_OF_LOGMSG];
        wSet.APIErr=
            clGetProgramBuildInfo(clProgram, clDev,
                                  CL_PROGRAM_BUILD_STATUS,
                                  sizeof(cl_build_status), &clStatus, &szRes);
        if(wSet.APIErr)
            snprintf(pcVal, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetProgramBuildInfo returned oclerr %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else
            switch(clStatus) {
                case  0: strncpy(pcVal,"Success",_GHM_MAXLEN_OF_LOGMSG); break;
                case -1: strncpy(pcVal,"None",   _GHM_MAXLEN_OF_LOGMSG); break;
                case -2: strncpy(pcVal,"Error",  _GHM_MAXLEN_OF_LOGMSG); break;
                case -3:
                         strncpy(pcVal,"In progress",_GHM_MAXLEN_OF_LOGMSG);
                         break;
                default: strncpy(pcVal,"Unknown", _GHM_MAXLEN_OF_LOGMSG);
            }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                 "%s Compilation status: %s",
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                 "%s Linker status: %s",
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                 "%s Build status: %s",
#endif
                 pcProgram, pcVal);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    if(LogLevel>=_GHE_LOG_KEY_PARS) { /* binary type */
        cl_program_binary_type clBinType=0u;
        size_t szRes=0ul;
        char pcVal[_GHM_MAXLEN_OF_LOGMSG]="\0";
        wSet.APIErr=
            clGetProgramBuildInfo(clProgram, clDev, CL_PROGRAM_BINARY_TYPE,
                                  sizeof(cl_program_binary_type),
                                  &clBinType, &szRes);
        if(wSet.APIErr)
            snprintf(pcVal, _GHM_MAXLEN_OF_LOGMSG,
                     "Undefined! clGetProgramBuildInfo returned oclerr %s(%d)",
                     _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
        else {
            if(clBinType==CL_PROGRAM_BINARY_TYPE_NONE)
                strncat(pcVal, "none ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcVal));
            if(clBinType&CL_PROGRAM_BINARY_TYPE_COMPILED_OBJECT)
                strncat(pcVal, "object ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcVal));
            if(clBinType&CL_PROGRAM_BINARY_TYPE_LIBRARY)
                strncat(pcVal, "library ", _GHM_MAXLEN_OF_LOGMSG-strlen(pcVal));
            if(clBinType&CL_PROGRAM_BINARY_TYPE_EXECUTABLE)
                strncat(pcVal, "executable ",
                        _GHM_MAXLEN_OF_LOGMSG-strlen(pcVal));
            /* TODO: уточнить так ли идентифицируется SPIR */
            if(clBinType==CL_PROGRAM_BINARY_TYPE_INTERMEDIATE)
                snprintf(pcVal, _GHM_MAXLEN_OF_LOGMSG, "IR ");
        }
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "%s Binary type: %s", pcProgram, pcVal);
        _ghf_logWS_Msg(wSet, pcLogMsg);
    }
    { /* log */
        char* pcVal=NULL;
        size_t szRes=0ul;
        wSet.APIErr=
            clGetProgramBuildInfo(clProgram, clDev,
                                  CL_PROGRAM_BUILD_LOG, 0ul, NULL, &szRes);
        if(wSet.APIErr) {
            snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                     "%s Compilation Log: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                     "%s Linker Log: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                     "%s Build Log: Undefined! "
#endif
                     "clGetDeviceInfo returned oclerr %s(%d)",
                     pcProgram, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
            _ghf_logWS_Msg(wSet, pcLogMsg);
        } else {
            pcVal=malloc(szRes);
            if(!pcVal) {
                snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                         "%s Compilation Log: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                         "%s Linker Log: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                         "%s Build Log: Undefined! "
#endif
                         "Host memory allocation failed", pcProgram);
                _ghf_logWS_Msg(wSet, pcLogMsg);
            } else {
                wSet.APIErr=
                    clGetProgramBuildInfo(clProgram, clDev,
                                          CL_PROGRAM_BUILD_LOG,
                                          szRes, pcVal, &szRes);
                if(wSet.APIErr) {
                    snprintf(pcLogMsg,_GHM_MAXLEN_OF_LOGMSG,
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                             "%s Compilation Log: Undefined! "
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Linker Log: Undefined! "
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                             "%s Build Log: Undefined! "
#endif
                             "clGetDeviceInfo returned oclerr %s(%d)",
                             pcProgram,
                             _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr);
                    _ghf_logWS_Msg(wSet, pcLogMsg);
                } else {
                    if(clStatus || BuildLogMode) {
                        pcVal[szRes-1]='\0';
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "Compilation Log:");
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "Linker Log:");
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "Build Log:");
#endif
                        _ghf_logWS_Raw(wSet, pcVal);
#if defined(__OCLH_COMPILER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "End of compilation log");
#endif
#if defined(__OCLH_LINKER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "End of linker log");
#endif
#if !defined(__OCLH_COMPILER_ONLY_FLAG) && !defined(__OCLH_LINKER_ONLY_FLAG)
                        _ghf_logWS_Hdr(wSet, "End of build log");
#endif
                    }
                }
                if(pcVal) { free(pcVal); pcVal=NULL; }
            }
        }
    }
    return(_GHM_OK);
}

int32_t _ghf_logWS_KerInfo(_GHT_WRKSET wSet, const cl_kernel clKer) {
/**/
#define __LOGAPIERR_RET(___LOGERR_ARG) \
{ \
    char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG]; \
    snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG, \
            "kernel Undefined! clGetKernelInfo/%s returned oclerr %s(%d)", \
             ___LOGERR_ARG, _ghf_CLAPIErrString(wSet.APIErr), wSet.APIErr); \
    _ghf_logWS_Msg(wSet,pcLogMsg); \
    return(_GHM_OK); \
}
/**/
    /* TODO: make ifdefs */
    char *pcKerName=NULL,
         *pcKerAttrs=NULL;
    size_t szRes=0ul;
    cl_uint cluNofArgs=0u,
            cluRefCnt=0u;
    cl_context clCtx=NULL;
    cl_program clPrg=NULL;
    wSet.APIErr=clGetKernelInfo(clKer,CL_KERNEL_FUNCTION_NAME,0ul,NULL,&szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_FUNCTION_NAME")
    pcKerName=malloc(szRes);
    if(!pcKerName) {
        char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "kernel Undefined! Host memory allocation failed");
        _ghf_logWS_Msg(wSet,pcLogMsg); return(_GHM_OK);
    }
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_FUNCTION_NAME,
                                szRes, pcKerName, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_FUNCTION_NAME")
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_NUM_ARGS,
                                sizeof(cl_uint), &cluNofArgs, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_NUM_ARGS")
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_REFERENCE_COUNT,
                                sizeof(cl_uint), &cluRefCnt, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_REFERENCE_COUNT")
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_CONTEXT,
                                sizeof(cl_context), &clCtx, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_CONTEXT")
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_PROGRAM,
                                sizeof(cl_program), &clPrg, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_PROGRAM")
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_ATTRIBUTES, 0ul, NULL, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_ATTRIBUTES")
    pcKerAttrs=malloc(szRes);
    if(!pcKerAttrs) {
        char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "kernel Undefined! Host memory allocation failed");
        _ghf_logWS_Msg(wSet,pcLogMsg); return(_GHM_OK);
    }
    wSet.APIErr=clGetKernelInfo(clKer, CL_KERNEL_ATTRIBUTES,
                                szRes, pcKerAttrs, &szRes);
    if(wSet.APIErr) __LOGAPIERR_RET("CL_KERNEL_ATTRIBUTES")
    {
        char pcLogMsg[_GHM_MAXLEN_OF_LOGMSG];
        snprintf(pcLogMsg, _GHM_MAXLEN_OF_LOGMSG,
                 "kernel %s args:%u refcnt:%u ctx:0x%04lx "
                 "prog:0x%04lx attrs:\"%s\"",
                 pcKerName, cluNofArgs, cluRefCnt,
                 __GHM_U64STRIPTO2B(clCtx),
                 __GHM_U64STRIPTO2B(clPrg), pcKerAttrs);
        _ghf_logWS_Msg(wSet,pcLogMsg);
    }
    if(pcKerAttrs) { free(pcKerAttrs); pcKerAttrs=NULL; }
    if(pcKerName) { free(pcKerName); pcKerName=NULL; }
    return(_GHM_OK);
/**/
#undef __LOGAPIERR_RET
/**/
}
