diff -Nru clinfo-2.0.15.04.28/debian/changelog clinfo-2.1.16.01.12/debian/changelog --- clinfo-2.0.15.04.28/debian/changelog 2015-04-28 12:30:04.000000000 +0000 +++ clinfo-2.1.16.01.12/debian/changelog 2016-02-17 13:06:57.000000000 +0000 @@ -1,3 +1,11 @@ +clinfo (2.1.16.01.12-1) unstable; urgency=medium + + * New upstream release. + * Update Vcs-Git URL. + * Bump Standards-Version to 3.9.7, no changes needed. + + -- Andreas Beckmann Wed, 17 Feb 2016 14:06:43 +0100 + clinfo (2.0.15.04.28-1) unstable; urgency=medium * New upstream release. diff -Nru clinfo-2.0.15.04.28/debian/control clinfo-2.1.16.01.12/debian/control --- clinfo-2.0.15.04.28/debian/control 2015-04-28 12:30:04.000000000 +0000 +++ clinfo-2.1.16.01.12/debian/control 2016-02-17 13:06:57.000000000 +0000 @@ -8,10 +8,10 @@ Build-Depends: debhelper (>= 9), ocl-icd-opencl-dev | opencl-dev, -Standards-Version: 3.9.6 +Standards-Version: 3.9.7 Homepage: https://github.com/Oblomov/clinfo Vcs-Browser: https://anonscm.debian.org/cgit/pkg-opencl/clinfo.git -Vcs-Git: git://anonscm.debian.org/pkg-opencl/clinfo.git +Vcs-Git: https://anonscm.debian.org/git/pkg-opencl/clinfo.git Package: clinfo Architecture: any diff -Nru clinfo-2.0.15.04.28/debian/copyright clinfo-2.1.16.01.12/debian/copyright --- clinfo-2.0.15.04.28/debian/copyright 2015-04-28 12:30:04.000000000 +0000 +++ clinfo-2.1.16.01.12/debian/copyright 2016-02-17 13:06:57.000000000 +0000 @@ -10,7 +10,7 @@ Files: debian/* Copyright: 2013 Simon Richter - © 2014-2015 Andreas Beckmann + © 2014-2016 Andreas Beckmann License: GPL-3.0+ License: GPL-3.0+ diff -Nru clinfo-2.0.15.04.28/Makefile clinfo-2.1.16.01.12/Makefile --- clinfo-2.0.15.04.28/Makefile 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/Makefile 2016-01-12 10:51:23.000000000 +0000 @@ -12,11 +12,23 @@ LDLIBS=-lOpenCL endif +ifeq ($(PLATFORM),Linux) + LDLIBS += -ldl +endif + CFLAGS+=-std=c99 -g -Wall -Wextra +SPARSE ?= sparse +SPARSEFLAGS=-Wsparse-all -Wno-decl + clinfo: clinfo.o: clinfo.c $(HDR) clean: $(RM) clinfo.o clinfo + +sparse: clinfo.c + $(SPARSE) $(CPPFLAGS) $(CFLAGS) $(SPARSEFLAGS) $^ + +.PHONY: clean sparse diff -Nru clinfo-2.0.15.04.28/man/clinfo.1 clinfo-2.1.16.01.12/man/clinfo.1 --- clinfo-2.0.15.04.28/man/clinfo.1 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/man/clinfo.1 2016-01-12 10:51:23.000000000 +0000 @@ -1,4 +1,4 @@ -.TH CLINFO 1 "2015-04-28" "clinfo 2.0.15.04.28" +.TH CLINFO 1 "2016-01-12" "clinfo 2.1.16.01.12" .SH NAME @@ -41,7 +41,7 @@ .SH CONFORMING TO -OpenCL 1.1, OpenCL 1.2, OpenCL 2.0. +OpenCL 1.1, OpenCL 1.2, OpenCL 2.0, OpenCL 2.1. .SH EXTENSIONS @@ -139,7 +139,7 @@ .SH EXPERIMENTAL FEATURES .P -Support for OpenCL 2.0 properties is not fully tested. +Support for OpenCL 2.0 and OpenCL 2.1 properties is not fully tested. .P Raw (machine-parsable) output is considered experimental, the output format @@ -150,6 +150,13 @@ .B clGetICDLoaderInfoOCLICD extension function is found. +.P +The highest OpenCL version supported by the ICD loader is detected +with some trivial heuristics (symbols found); a notice is output +if this is lower than the highest platform OpenCL version, or +if the detected version doesn't match the one declared by the ICD +loader itself. + .SH BUGS The .B CL_DEVICE_GLOBAL_FREE_MEMORY_AMD diff -Nru clinfo-2.0.15.04.28/src/clinfo.c clinfo-2.1.16.01.12/src/clinfo.c --- clinfo-2.0.15.04.28/src/clinfo.c 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/src/clinfo.c 2016-01-12 10:51:23.000000000 +0000 @@ -4,6 +4,11 @@ #include #include +#include + +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT ((void*)0) +#endif /* Load STDC format macros (PRI*), or define them * for those crappy, non-standard compilers @@ -30,8 +35,22 @@ cl_bool has_amd_offline; /* has cl_amd_offline_devices extension */ }; +struct platform_info_checks { + int has_khr_icd; + cl_uint plat_version; +}; + cl_uint num_platforms; cl_platform_id *platform; +/* highest version exposed by any platform: if the OpenCL library (the ICD loader) + * has a lower version, problems may arise (such as API calls causing segfaults + * or any other unexpected behavior + */ +cl_uint max_plat_version; +/* auto-detected OpenCL version support for the ICD loader */ +cl_uint icdl_ocl_version_found = 10; +/* OpenCL version support declared by the ICD loader */ +cl_uint icdl_ocl_version; struct platform_data *pdata; /* maximum length of a platform's sname */ @@ -109,7 +128,7 @@ static const char l4cache[] = "L4 cache"; static const char* affinity_domain_str[] = { - numa, l4cache, l3cache, l2cache, l1cache, "next partitionalbe" + numa, l4cache, l3cache, l2cache, l1cache, "next partitionable" }; static const char* affinity_domain_ext_str[] = { @@ -208,21 +227,21 @@ "KRN()\n/* KRN(2)\nKRN(4)\nKRN(8)\nKRN(16) */\n", }; -const char *no_plat() +const char *no_plat(void) { return output_mode == CLINFO_HUMAN ? "No platform" : "CL_INVALID_PLATFORM"; } -const char *no_dev() +const char *no_dev(void) { return output_mode == CLINFO_HUMAN ? "No devices found in platform" : "CL_DEVICE_NOT_FOUND"; } -const char *no_dev_avail() +const char *no_dev_avail(void) { return output_mode == CLINFO_HUMAN ? "No devices available in platform" : @@ -251,6 +270,30 @@ int had_error = 0; const char *cur_sfx = empty_str; +/* parse a CL_DEVICE_VERSION or CL_PLATFORM_VERSION info to determine the OpenCL version. + * Returns an unsigned integer in the form major*10 + minor + */ +cl_uint +getOpenCLVersion(const char *version) +{ + cl_uint ret = 10; + long parse = 0; + const char *from = version; + char *next = NULL; + parse = strtol(from, &next, 10); + + if (next != from) { + ret = parse*10; + // skip the dot TODO should we actually check for the dot? + from = ++next; + parse = strtol(from, &next, 10); + if (next != from) + ret += parse; + } + return ret; +} + + /* print strbuf, prefixed by pname, skipping leading whitespace if skip is nonzero, * affixing cur_sfx */ static inline @@ -263,7 +306,7 @@ } int -platform_info_str(cl_platform_id pid, cl_platform_info param, const char* pname) +platform_info_str(cl_platform_id pid, cl_platform_info param, const char* pname, const struct platform_info_checks * chk UNUSED) { error = clGetPlatformInfo(pid, param, 0, NULL, &nusz); if (nusz > bufsz) { @@ -272,7 +315,7 @@ } had_error = REPORT_ERROR2("get %s size"); if (!had_error) { - error = clGetPlatformInfo(pid, param, bufsz, strbuf, 0); + error = clGetPlatformInfo(pid, param, bufsz, strbuf, NULL); had_error = REPORT_ERROR2("get %s"); } /* when only listing, do not print anything we're just gathering @@ -283,14 +326,32 @@ return had_error; } -struct platform_info_checks { - int has_khr_icd; -}; +int +platform_info_ulong(cl_platform_id pid, cl_platform_info param, const char* pname, const struct platform_info_checks * chk UNUSED) +{ + cl_ulong val = 0; + + error = clGetPlatformInfo(pid, param, sizeof(val), &val, NULL); + had_error = REPORT_ERROR2("get %s"); + /* when only listing, do not print anything we're just gathering + * information + */ + if (!list_only) { + if (had_error) + show_strbuf(pname, 0); + else + printf("%s" I1_STR "%" PRIu64 "%s\n", line_pfx, pname, val, cur_sfx); + } + return had_error; +} struct platform_info_traits { cl_platform_info param; // CL_PLATFORM_* const char *sname; // "CL_PLATFORM_*" const char *pname; // "Platform *" + const char *sfx; // suffix for the output in non-raw mode + /* pointer to function that shows the parameter */ + int (*show_func)(cl_platform_id pid, cl_platform_info param, const char *pname, const struct platform_info_checks *); /* pointer to function that checks if the parameter should be checked */ int (*check_func)(const struct platform_info_checks *); }; @@ -300,15 +361,21 @@ return chk->has_khr_icd; } -#define PINFO_COND(symbol, name, funcptr) { symbol, #symbol, "Platform " name, &funcptr } -#define PINFO(symbol, name) { symbol, #symbol, "Platform " name, NULL } +int plat_is_21(const struct platform_info_checks *chk) +{ + return !(chk->plat_version < 21); +} + +#define PINFO_COND(symbol, name, sfx, typ, funcptr) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, &funcptr } +#define PINFO(symbol, name, sfx, typ) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, NULL } struct platform_info_traits pinfo_traits[] = { - PINFO(CL_PLATFORM_NAME, "Name"), - PINFO(CL_PLATFORM_VENDOR, "Vendor"), - PINFO(CL_PLATFORM_VERSION, "Version"), - PINFO(CL_PLATFORM_PROFILE, "Profile"), - PINFO(CL_PLATFORM_EXTENSIONS, "Extensions"), - PINFO_COND(CL_PLATFORM_ICD_SUFFIX_KHR, "Extensions function suffix", khr_icd_p) + PINFO(CL_PLATFORM_NAME, "Name", NULL, str), + PINFO(CL_PLATFORM_VENDOR, "Vendor", NULL, str), + PINFO(CL_PLATFORM_VERSION, "Version", NULL, str), + PINFO(CL_PLATFORM_PROFILE, "Profile", NULL, str), + PINFO(CL_PLATFORM_EXTENSIONS, "Extensions", NULL, str), + PINFO_COND(CL_PLATFORM_HOST_TIMER_RESOLUTION, "Host timer resolution", "ns", ulong, plat_is_21), + PINFO_COND(CL_PLATFORM_ICD_SUFFIX_KHR, "Extensions function suffix", NULL, str, khr_icd_p) }; /* Print platform info and prepare arrays for device info */ @@ -318,20 +385,24 @@ cl_platform_id pid = platform[p]; size_t len = 0; - struct platform_info_checks pinfo_checks = { 0 }; + struct platform_info_checks pinfo_checks = { 0, 10 }; current_function = __func__; for (current_line = 0; current_line < ARRAY_SIZE(pinfo_traits); ++current_line) { const struct platform_info_traits *traits = pinfo_traits + current_line; + const char *pname = (output_mode == CLINFO_HUMAN ? + traits->pname : traits->sname); + current_param = traits->sname; if (traits->check_func && !traits->check_func(&pinfo_checks)) continue; - had_error = platform_info_str(pid, traits->param, - output_mode == CLINFO_HUMAN ? - traits->pname : traits->sname); + cur_sfx = (output_mode == CLINFO_HUMAN && traits->sfx) ? traits->sfx : empty_str; + + had_error = traits->show_func(pid, traits->param, + pname, &pinfo_checks); if (had_error) continue; @@ -348,6 +419,10 @@ memcpy(pdata[p].pname, strbuf, len); pdata[p].pname[len] = '\0'; break; + case CL_PLATFORM_VERSION: + /* compute numeric value for OpenCL version */ + pinfo_checks.plat_version = getOpenCLVersion(strbuf + 7); + break; case CL_PLATFORM_EXTENSIONS: pinfo_checks.has_khr_icd = !!strstr(strbuf, "cl_khr_icd"); pdata[p].has_amd_offline = !!strstr(strbuf, "cl_amd_offline_devices"); @@ -367,10 +442,14 @@ } + if (pinfo_checks.plat_version > max_plat_version) + max_plat_version = pinfo_checks.plat_version; + /* if no CL_PLATFORM_ICD_SUFFIX_KHR, use P### as short/symbolic name */ if (!pdata[p].sname) { - ALLOC(pdata[p].sname, 32, "platform symbolic name"); - sprintf(pdata[p].sname, "P%u", p); +#define SNAME_MAX 32 + ALLOC(pdata[p].sname, SNAME_MAX, "platform symbolic name"); + snprintf(pdata[p].sname, SNAME_MAX, "P%u", p); } len = strlen(pdata[p].sname); @@ -407,9 +486,9 @@ CL_CONTEXT_PLATFORM, (cl_context_properties)pid, 0, 0 }; cl_uint cursor = 0; - cl_context ctx = 0; - cl_program prg = 0; - cl_kernel krn = 0; + cl_context ctx = NULL; + cl_program prg = NULL; + cl_kernel krn = NULL; ctx = clCreateContext(ctxpft, 1, &dev, NULL, NULL, &error); RR_ERROR("create context"); @@ -441,7 +520,7 @@ sizeof(*wgm), wgm + cursor, NULL); RR_ERROR("get kernel info"); clReleaseKernel(krn); - krn = 0; + krn = NULL; } out: @@ -454,29 +533,6 @@ return ret; } -/* parse a CL_DEVICE_VERSION info to determine the OpenCL version. - * Returns an unsigned integer in the from major*10 + minor - */ -cl_uint -getOpenCLVersion(const char *version) -{ - cl_uint ret = 10; - long parse = 0; - const char *from = version; - char *next = NULL; - parse = strtol(from, &next, 10); - - if (next != from) { - ret = parse*10; - // skip the dot TODO should we actually check for the dot? - from = ++next; - parse = strtol(from, &next, 10); - if (next != from) - ret += parse; - } - return ret; -} - /* * Device properties/extensions used in traits checks, and relevant functions */ @@ -539,6 +595,12 @@ return !(chk->dev_version < 20); } +// device supports 2.1 +int dev_is_21(const struct device_info_checks *chk) +{ + return !(chk->dev_version < 21); +} + // device does not support 2.0 int dev_not_20(const struct device_info_checks *chk) { @@ -635,7 +697,7 @@ */ #define _GET_VAL \ - error = clGetDeviceInfo(dev, param, sizeof(val), &val, 0); \ + error = clGetDeviceInfo(dev, param, sizeof(val), &val, NULL); \ had_error = REPORT_ERROR2("get %s"); #define _GET_VAL_ARRAY \ @@ -692,7 +754,7 @@ } had_error = REPORT_ERROR2("get %s size"); if (!had_error) { - error = clGetDeviceInfo(dev, param, bufsz, strbuf, 0); + error = clGetDeviceInfo(dev, param, bufsz, strbuf, NULL); had_error = REPORT_ERROR2("get %s"); } return had_error; @@ -814,13 +876,13 @@ cl_ulong val = 0; GET_VAL; if (!had_error) { - int szval = 0; + size_t szval = 0; time_t time = val/UINT64_C(1000000000); - szval += sprintf(strbuf, "%" PRIu64 "ns (", val); - strcpy(strbuf + szval, ctime(&time)); - szval = strlen(strbuf) - 1; - strbuf[szval++] = ')'; - strbuf[szval++] = '\0'; + szval += snprintf(strbuf, bufsz, "%" PRIu64 "ns (", val); + szval += bufcpy(szval, ctime(&time)); + /* overwrite ctime's newline with the closing parenthesis */ + if (szval < bufsz) + strbuf[szval - 1] = ')'; } show_strbuf(pname, 0); return had_error; @@ -833,15 +895,11 @@ size_t szval = 0, numval = 0; GET_VAL_ARRAY; if (!had_error) { - const char *sep = (output_mode == CLINFO_HUMAN ? times_str : spc_str); - size_t sepsz = 1; size_t counter = 0; + set_separator(output_mode == CLINFO_HUMAN ? times_str : spc_str); szval = 0; for (counter = 0; counter < numval; ++counter) { - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } + add_separator(&szval); szval += snprintf(strbuf + szval, bufsz - szval - 1, "%" PRIuS, val[counter]); if (szval >= bufsz) { trunc_strbuf(); @@ -857,7 +915,7 @@ int device_info_wg(cl_device_id dev, cl_device_info param UNUSED, const char *pname, const struct device_info_checks *chk UNUSED) { - cl_platform_id val = 0; + cl_platform_id val = NULL; { /* shadow */ cl_device_info param = CL_DEVICE_PLATFORM; @@ -927,30 +985,24 @@ GET_VAL; if (!had_error) { /* iterate over device type strings, appending their textual form - * to strbuf. We use plain strcpy since we know that it's at least - * 1024 so we are safe. + * to strbuf. * TODO: check for extra bits/no bits */ - size_t szval = 0; cl_uint i = devtype_count - 1; /* skip CL_DEVICE_TYPE_ALL */ - const char *sep = (output_mode == CLINFO_HUMAN ? comma_str : vbar_str); - size_t sepsz = (output_mode == CLINFO_HUMAN ? 2 : 3); const char * const *devstr = (output_mode == CLINFO_HUMAN ? device_type_str : device_type_raw_str); + size_t szval = 0; + strbuf[szval] = '\0'; + set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str); for (; i > 0; --i) { /* assemble CL_DEVICE_TYPE_* from index i */ cl_device_type cur = (cl_device_type)(1) << (i-1); if (val & cur) { /* match: add separator if not first match */ - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } - strcpy(strbuf + szval, devstr[i]); - szval += strlen(devstr[i]); + add_separator(&szval); + szval += bufcpy(szval, devstr[i]); } } - strbuf[szval] = '\0'; } show_strbuf(pname, 0); /* we abuse global strbuf to pass the device type over to the caller */ @@ -1123,12 +1175,11 @@ { size_t numval = 0, szval = 0, cursor = 0, slen = 0; cl_device_partition_property *val = NULL; - - const char *sep = (output_mode == CLINFO_HUMAN ? comma_str : vbar_str); - size_t sepsz = (output_mode == CLINFO_HUMAN ? 2 : 3); const char * const *ptstr = (output_mode == CLINFO_HUMAN ? partition_type_str : partition_type_raw_str); + set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str); + GET_VAL_ARRAY; szval = 0; @@ -1137,10 +1188,7 @@ int str_idx = -1; /* add separator for values past the first */ - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } + add_separator(&szval); switch (val[cursor]) { case 0: str_idx = 1; break; @@ -1149,7 +1197,7 @@ case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN: str_idx = 4; break; case CL_DEVICE_PARTITION_BY_NAMES_INTEL: str_idx = 5; break; default: - szval += sprintf(strbuf + szval, "by (0x%" PRIXPTR ")", val[cursor]); + szval += snprintf(strbuf + szval, bufsz - szval - 1, "by (0x%" PRIXPTR ")", val[cursor]); break; } if (str_idx > 0) { @@ -1157,16 +1205,17 @@ slen = strlen(ptstr[str_idx]); if (output_mode == CLINFO_RAW && str_idx > 1) slen -= 4; - strncpy(strbuf + szval, ptstr[str_idx], slen); - szval += slen; + szval += bufcpy_len(szval, ptstr[str_idx], slen); + } + if (szval >= bufsz) { + trunc_strbuf(); + break; } } if (szval == 0) { - slen = strlen(ptstr[0]); - strcpy(strbuf, ptstr[0]); - szval += slen; - } - strbuf[szval] = '\0'; + bufcpy(szval, ptstr[0]); + } else if (szval < bufsz) + strbuf[szval] = '\0'; } show_strbuf(pname, 0); @@ -1180,12 +1229,11 @@ { size_t numval = 0, szval = 0, cursor = 0, slen = 0; cl_device_partition_property_ext *val = NULL; - - const char *sep = (output_mode == CLINFO_HUMAN ? comma_str : vbar_str); - size_t sepsz = (output_mode == CLINFO_HUMAN ? 2 : 3); const char * const *ptstr = (output_mode == CLINFO_HUMAN ? partition_type_str : partition_type_raw_str); + set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str); + GET_VAL_ARRAY; szval = 0; @@ -1194,10 +1242,7 @@ int str_idx = -1; /* add separator for values past the first */ - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } + add_separator(&szval); switch (val[cursor]) { case 0: str_idx = 1; break; @@ -1206,7 +1251,7 @@ case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT: str_idx = 4; break; case CL_DEVICE_PARTITION_BY_NAMES_EXT: str_idx = 5; break; default: - szval += sprintf(strbuf + szval, "by (0x%" PRIX64 ")", val[cursor]); + szval += snprintf(strbuf + szval, bufsz - szval - 1, "by (0x%" PRIX64 ")", val[cursor]); break; } if (str_idx > 0) { @@ -1215,13 +1260,18 @@ strncpy(strbuf + szval, ptstr[str_idx], slen); szval += slen; } + if (szval >= bufsz) { + trunc_strbuf(); + break; + } } if (szval == 0) { slen = strlen(ptstr[0]); - strcpy(strbuf, ptstr[0]); + memcpy(strbuf, ptstr[0], slen); szval += slen; } - strbuf[szval] = '\0'; + if (szval < bufsz) + strbuf[szval] = '\0'; } show_strbuf(pname, 0); @@ -1244,21 +1294,18 @@ */ size_t szval = 0; cl_uint i = 0; - const char *sep = (output_mode == CLINFO_HUMAN ? comma_str : vbar_str); - size_t sepsz = (output_mode == CLINFO_HUMAN ? 2 : 3); const char * const *affstr = (output_mode == CLINFO_HUMAN ? affinity_domain_str : affinity_domain_raw_str); + set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str); for (i = 0; i < affinity_domain_count; ++i) { cl_device_affinity_domain cur = (cl_device_affinity_domain)(1) << i; if (val & cur) { /* match: add separator if not first match */ - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } - strcpy(strbuf + szval, affstr[i]); - szval += strlen(affstr[i]); + add_separator(&szval); + szval += bufcpy(szval, affstr[i]); } + if (szval >= bufsz) + break; } } if (val || had_error) @@ -1271,12 +1318,11 @@ { size_t numval = 0, szval = 0, cursor = 0, slen = 0; cl_device_partition_property_ext *val = NULL; - - const char *sep = (output_mode == CLINFO_HUMAN ? comma_str : vbar_str); - size_t sepsz = (output_mode == CLINFO_HUMAN ? 2 : 3); const char * const *ptstr = (output_mode == CLINFO_HUMAN ? affinity_domain_ext_str : affinity_domain_raw_ext_str); + set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str); + GET_VAL_ARRAY; szval = 0; @@ -1285,10 +1331,7 @@ int str_idx = -1; /* add separator for values past the first */ - if (szval > 0) { - strcpy(strbuf + szval, sep); - szval += sepsz; - } + add_separator(&szval); switch (val[cursor]) { case CL_AFFINITY_DOMAIN_NUMA_EXT: str_idx = 0; break; @@ -1298,7 +1341,7 @@ case CL_AFFINITY_DOMAIN_L1_CACHE_EXT: str_idx = 4; break; case CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT: str_idx = 5; break; default: - szval += sprintf(strbuf + szval, " (0x%" PRIX64 ")", val[cursor]); + szval += snprintf(strbuf + szval, bufsz - szval - 1, " (0x%" PRIX64 ")", val[cursor]); break; } if (str_idx >= 0) { @@ -1308,6 +1351,10 @@ strncpy(strbuf + szval, str, slen); szval += slen; } + if (szval >= bufsz) { + trunc_strbuf(); + break; + } } strbuf[szval] = '\0'; } @@ -1364,9 +1411,9 @@ if (!had_error) { size_t szval = 0; cl_uint i = 0; - const char *sep = vbar_str; const char * const *fpstr = (output_mode == CLINFO_HUMAN ? fp_conf_str : fp_conf_raw_str); + set_separator(vbar_str); if (output_mode == CLINFO_HUMAN) { const char *why = na; switch (param) { @@ -1396,8 +1443,7 @@ szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s", line_pfx, fpstr[i], bool_str[!!(val & cur)]); } else if (val & cur) { - if (szval > 0) - szval += bufcpy(szval, sep); + add_separator(&szval); szval += bufcpy(szval, fpstr[i]); } } @@ -1419,17 +1465,16 @@ if (!had_error) { size_t szval = 0; cl_uint i = 0; - const char *sep = vbar_str; const char * const *qpstr = (output_mode == CLINFO_HUMAN ? queue_prop_str : queue_prop_raw_str); + set_separator(vbar_str); for (i = 0; i < queue_prop_count; ++i) { cl_command_queue_properties cur = (cl_command_queue_properties)(1) << i; if (output_mode == CLINFO_HUMAN) { szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s", line_pfx, qpstr[i], bool_str[!!(val & cur)]); } else if (val & cur) { - if (szval > 0) - szval += bufcpy(szval, sep); + add_separator(&szval); szval += bufcpy(szval, qpstr[i]); } } @@ -1451,17 +1496,16 @@ if (!had_error) { size_t szval = 0; cl_uint i = 0; - const char *sep = vbar_str; const char * const *qpstr = (output_mode == CLINFO_HUMAN ? execap_str : execap_raw_str); + set_separator(vbar_str); for (i = 0; i < execap_count; ++i) { cl_device_exec_capabilities cur = (cl_device_exec_capabilities)(1) << i; if (output_mode == CLINFO_HUMAN) { szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s", line_pfx, qpstr[i], bool_str[!!(val & cur)]); } else if (val & cur) { - if (szval > 0) - szval += bufcpy(szval, sep); + add_separator(&szval); szval += bufcpy(szval, qpstr[i]); } } @@ -1506,9 +1550,9 @@ if (!had_error) { size_t szval = 0; cl_uint i = 0; - const char *sep = vbar_str; const char * const *scstr = (output_mode == CLINFO_HUMAN ? svm_cap_str : svm_cap_raw_str); + set_separator(vbar_str); if (output_mode == CLINFO_HUMAN) { /* show 'why' it's being shown */ szval += sprintf(strbuf, "(%s%s%s)", @@ -1522,8 +1566,7 @@ szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s", line_pfx, scstr[i], bool_str[!!(val & cur)]); } else if (val & cur) { - if (szval > 0) - szval += bufcpy(szval, sep); + add_separator(&szval); szval += bufcpy(szval, scstr[i]); } } @@ -1607,6 +1650,7 @@ { CLINFO_BOTH, DINFO(CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, "Preferred work group size multiple", wg), NULL }, { CLINFO_BOTH, DINFO(CL_DEVICE_WARP_SIZE_NV, "Warp size (NV)", int), dev_has_nv }, { CLINFO_BOTH, DINFO(CL_DEVICE_WAVEFRONT_WIDTH_AMD, "Wavefront width (AMD)", int), dev_is_gpu_amd }, + { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_NUM_SUB_GROUPS, "Max sub-groups per work group", int), dev_is_21 }, /* Preferred/native vector widths: header is only presented in HUMAN case, that also pairs * PREFERRED and NATIVE in a single line */ @@ -1736,6 +1780,7 @@ /* Kernel execution capabilities */ { CLINFO_BOTH, DINFO(CL_DEVICE_EXECUTION_CAPABILITIES, "Execution capabilities", execap), NULL }, + { CLINFO_BOTH, DINFO(CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS, INDENT "Sub-group independent forward progress", bool), dev_is_21 }, { CLINFO_BOTH, DINFO(CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD, INDENT "Thread trace supported (AMD)", bool), dev_is_gpu_amd }, { CLINFO_BOTH, DINFO(CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, INDENT "Kernel execution timeout (NV)", bool), dev_has_nv }, { CLINFO_BOTH, DINFO(CL_DEVICE_GPU_OVERLAP_NV, "Concurrent copy and kernel execution (NV)", bool), dev_has_nv }, @@ -1744,6 +1789,7 @@ * or maybe it depends on some other device property? { CLINFO_BOTH, DINFO(CL_DEVICE_AVAILABLE_ASYNC_QUEUES_AMD, INDENT "Number of async queues (AMD)", int), dev_is_gpu_amd }, */ + { CLINFO_BOTH, DINFO(CL_DEVICE_IL_VERSION, INDENT "IL version", str), dev_is_21, }, { CLINFO_BOTH, DINFO(CL_DEVICE_SPIR_VERSIONS, INDENT "SPIR versions", str), dev_has_spir }, { CLINFO_BOTH, DINFO(CL_DEVICE_PRINTF_BUFFER_SIZE, "printf() buffer size", mem), dev_is_12 }, { CLINFO_BOTH, DINFO(CL_DEVICE_BUILT_IN_KERNELS, "Built-in kernels", str), dev_is_12 }, @@ -1768,15 +1814,15 @@ char *extensions = NULL; + /* pointer to the traits for CL_DEVICE_EXTENSIONS */ + const struct device_info_traits *extensions_traits = NULL; + struct device_info_checks chk; memset(&chk, 0, sizeof(chk)); chk.dev_version = 10; current_function = __func__; - /* pointer to the traits for CL_DEVICE_EXTENSIONS */ - const struct device_info_traits *extensions_traits = NULL; - for (current_line = 0; current_line < ARRAY_SIZE(dinfo_traits); ++current_line) { const struct device_info_traits *traits = dinfo_traits + current_line; @@ -2204,7 +2250,7 @@ } /* check behavior of clCreateContextFromType() with NULL cl_context_properties */ -void checkNullCtxFromType() +void checkNullCtxFromType(void) { size_t t; /* type iterator */ size_t i; /* generic iterator */ @@ -2328,6 +2374,7 @@ } printf("%s%s\n", def, strbuf); } + free(devs); } /* check the behavior of NULL platform in clGetDeviceIDs (see checkNullGetDevices) @@ -2395,9 +2442,25 @@ CL_ICDL_VENDOR=4, } cl_icdl_info; -/* Function pointer to the ICD loader function */ +/* Function pointer to the ICD loader info function */ cl_int (*clGetICDLoaderInfoOCLICD)(cl_icdl_info, size_t, void*, size_t*); +/* We want to auto-detect the OpenCL version supported by the ICD loader. + * To do this, we will progressively find symbols introduced in new APIs, + * until a NULL symbol is found. + */ + +struct icd_loader_test { + cl_uint version; + const char *symbol; +} icd_loader_tests[] = { + { 11, "clCreateSubBuffer" }, + { 12, "clCreateImage" }, + { 20, "clSVMAlloc" }, + { 21, "clGetHostTimer" }, + { 0, NULL } +}; + int icdl_info_str(cl_icdl_info param, const char* pname) { @@ -2421,6 +2484,8 @@ const char *pname; // "ICD loader *" }; +static const char * const oclicdl_pfx = "OCLICD"; + #define LINFO(symbol, name) { symbol, #symbol, "ICD loader " name } struct icdl_info_traits linfo_traits[] = { LINFO(CL_ICDL_NAME, "Name"), @@ -2429,12 +2494,32 @@ LINFO(CL_ICDL_OCL_VERSION, "Profile") }; +/* GCC < 4.6 does not support the diagnostic push _inside_ the function, + * so we have to put it outside + */ +#if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif -void oclIcdProps() +void oclIcdProps(void) { + /* First of all, we try to auto-detect the supported ICD loader version */ + int i = 0; + + do { + struct icd_loader_test check = icd_loader_tests[i]; + if (check.symbol == NULL) + break; + if (dlsym(RTLD_DEFAULT, check.symbol) == NULL) + break; + icdl_ocl_version_found = check.version; + ++i; + } while (1); + + /* We find the clGetICDLoaderInfoOCLICD extension address, and use it to query * the ICD loader properties. It should be noted however that - * clGetExtensionFunctionAddress is marked * deprecated as of OpenCL 1.2, so + * clGetExtensionFunctionAddress is marked deprecated as of OpenCL 1.2, so * to use it and compile cleanly we need disable the relevant warning. * It should be noted that in this specific case we cannot replace the * call to clGetExtensionFunctionAddress with a call to the superseding function @@ -2445,7 +2530,7 @@ #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4996) -#else +#elif defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) >= 46) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif @@ -2454,14 +2539,23 @@ #ifdef _MSC_VER #pragma warning(pop) -#else +#elif defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) >= 46) #pragma GCC diagnostic pop #endif if (clGetICDLoaderInfoOCLICD != NULL) { - puts("\nICD loader properties"); + /* TODO think of a sensible header in CLINFO_RAW */ + if (output_mode != CLINFO_RAW) + puts("\nICD loader properties"); current_function = __func__; + if (output_mode == CLINFO_RAW) { + line_pfx_len = strlen(oclicdl_pfx) + 5; + REALLOC(line_pfx, line_pfx_len, "line prefix OCL ICD"); + sprintf(strbuf, "[%s/*]", oclicdl_pfx); + sprintf(line_pfx, "%*s", -line_pfx_len, strbuf); + } + for (current_line = 0; current_line < ARRAY_SIZE(linfo_traits); ++current_line) { const struct icdl_info_traits *traits = linfo_traits + current_line; current_param = traits->sname; @@ -2469,16 +2563,45 @@ had_error = icdl_info_str(traits->param, output_mode == CLINFO_HUMAN ? traits->pname : traits->sname); + + if (!had_error && traits->param == CL_ICDL_OCL_VERSION) { + icdl_ocl_version = getOpenCLVersion(strbuf + 7); + } + } + } + + if (output_mode == CLINFO_HUMAN) { + if (icdl_ocl_version && + icdl_ocl_version != icdl_ocl_version_found) { + printf( "\tNOTE:\tyour OpenCL library declares to support OpenCL %u.%u,\n" + "\t\tbut it seems to support up to OpenCL %u.%u %s.\n", + icdl_ocl_version / 10, icdl_ocl_version % 10, + icdl_ocl_version_found / 10, icdl_ocl_version_found % 10, + icdl_ocl_version_found < icdl_ocl_version ? + "only" : "too"); + } + if (icdl_ocl_version_found < max_plat_version) { + printf( "\tNOTE:\tyour OpenCL library only supports OpenCL %u.%u,\n" + "\t\tbut some installed platforms support OpenCL %u.%u.\n" + "\t\tPrograms using %u.%u features may crash\n" + "\t\tor behave unexepectedly\n", + icdl_ocl_version_found / 10, icdl_ocl_version_found % 10, + max_plat_version / 10, max_plat_version % 10, + max_plat_version / 10, max_plat_version % 10); } } } -void version() +#if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46) +#pragma GCC diagnostic warning "-Wdeprecated-declarations" +#endif + +void version(void) { - puts("clinfo version 2.0.15.04.28"); + puts("clinfo version 2.1.16.01.12"); } -void usage() +void usage(void) { version(); puts("Display properties of all available OpenCL platforms and devices"); @@ -2563,7 +2686,8 @@ listPlatformsAndDevices(show_offline); } else { showDevices(show_offline); - checkNullBehavior(); + if (output_mode != CLINFO_RAW) + checkNullBehavior(); oclIcdProps(); } diff -Nru clinfo-2.0.15.04.28/src/error.h clinfo-2.1.16.01.12/src/error.h --- clinfo-2.0.15.04.28/src/error.h 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/src/error.h 2016-01-12 10:51:23.000000000 +0000 @@ -2,6 +2,9 @@ #include +#include "ext.h" +#include "fmtmacros.h" + cl_int error; int diff -Nru clinfo-2.0.15.04.28/src/ext.h clinfo-2.1.16.01.12/src/ext.h --- clinfo-2.0.15.04.28/src/ext.h 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/src/ext.h 2016-01-12 10:51:23.000000000 +0000 @@ -1,6 +1,9 @@ /* Include OpenCL header, and define OpenCL extensions, since what is and is not * available in the official headers is very system-dependent */ +#ifndef _EXT_H +#define _EXT_H + #ifdef __APPLE__ #include #else @@ -46,6 +49,13 @@ typedef cl_bitfield cl_device_svm_capabilities; #endif +#ifndef CL_VERSION_2_1 +#define CL_PLATFORM_HOST_TIMER_RESOLUTION 0x0905 +#define CL_DEVICE_IL_VERSION 0x105B +#define CL_DEVICE_MAX_NUM_SUB_GROUPS 0x105C +#define CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS 0x105D +#endif + /* * Extensions */ @@ -152,3 +162,4 @@ #define CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL 0x4104 #define CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL 0x4105 +#endif diff -Nru clinfo-2.0.15.04.28/src/fmtmacros.h clinfo-2.1.16.01.12/src/fmtmacros.h --- clinfo-2.0.15.04.28/src/fmtmacros.h 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/src/fmtmacros.h 2016-01-12 10:51:23.000000000 +0000 @@ -5,6 +5,9 @@ easier. */ +#ifndef _FMT_MACROS_H +#define _FMT_MACROS_H + #ifdef _WIN32 # include # include // size_t @@ -22,3 +25,4 @@ # define PRIuS "zu" #endif +#endif diff -Nru clinfo-2.0.15.04.28/src/strbuf.h clinfo-2.1.16.01.12/src/strbuf.h --- clinfo-2.0.15.04.28/src/strbuf.h 2015-04-28 06:40:30.000000000 +0000 +++ clinfo-2.1.16.01.12/src/strbuf.h 2016-01-12 10:51:23.000000000 +0000 @@ -3,6 +3,9 @@ */ #include +#include +#include +#include "fmtmacros.h" char *strbuf; size_t bufsz, nusz; @@ -14,7 +17,7 @@ bufsz = nusz; \ } \ if (REPORT_ERROR("get " param_str " size")) break; \ - error = cmd(__VA_ARGS__, param, bufsz, strbuf, 0); \ + error = cmd(__VA_ARGS__, param, bufsz, strbuf, NULL); \ REPORT_ERROR("get " param_str); \ } while (0) @@ -38,9 +41,8 @@ * returning the amount of bytes written (excluding the * closing NULL byte) */ -static inline size_t bufcpy(size_t offset, const char *str) +static inline size_t bufcpy_len(size_t offset, const char *str, size_t len) { - size_t len = strlen(str); size_t maxlen = bufsz - offset - 1; char *dst = strbuf + offset; int trunc = 0; @@ -63,3 +65,32 @@ strbuf[offset] = '\0'; return len; } + +/* As above, auto-compute string length */ +static inline size_t bufcpy(size_t offset, const char *str) +{ + return bufcpy_len(offset, str, strlen(str)); +} + + +/* Separators: we want to be able to prepend separators as needed to strbuf, + * which we do only if halfway through the buffer. The callers should first + * call a 'set_separator' and then use add_separator(&offset) to add it, where szval + * is an offset inside the buffer, which will be incremented as needed + */ + +const char *sep; +size_t sepsz; + +void set_separator(const char* _sep) +{ + sep = _sep; + sepsz = strlen(sep); +} + +/* Note that no overflow check is done: it is assumed that strbuf will have enough room */ +void add_separator(size_t *offset) +{ + if (*offset) + *offset += bufcpy_len(*offset, sep, sepsz); +}