1 /* Collect all available information on all available devices
2 * on all available OpenCL platforms present in the system
10 #define RTLD_DEFAULT ((void*)0)
13 /* ISO C forbids assignments between function pointers and void pointers,
14 * but POSIX allows it. To compile without warnings even in -pedantic mode,
15 * we use this horrible trick to get a function address from
16 * clGetExtensionFunctionAddress
18 #define PTR_FUNC_PTR *(void**)&
20 /* Load STDC format macros (PRI*), or define them
21 * for those crappy, non-standard compilers
23 #include "fmtmacros.h"
25 // Support for the horrible MS C compiler
27 #include "ms_support.h"
35 #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(*ar))
36 #define UNUSED __attribute__((unused))
38 struct platform_data {
39 char *pname; /* CL_PLATFORM_NAME */
40 char *sname; /* CL_PLATFORM_ICD_SUFFIX_KHR or surrogate */
41 cl_uint ndevs; /* number of devices */
42 cl_bool has_amd_offline; /* has cl_amd_offline_devices extension */
45 struct platform_info_checks {
50 cl_uint num_platforms;
51 cl_platform_id *platform;
52 /* highest version exposed by any platform: if the OpenCL library (the ICD loader)
53 * has a lower version, problems may arise (such as API calls causing segfaults
54 * or any other unexpected behavior
56 cl_uint max_plat_version;
57 /* auto-detected OpenCL version support for the ICD loader */
58 cl_uint icdl_ocl_version_found = 10;
59 /* OpenCL version support declared by the ICD loader */
60 cl_uint icdl_ocl_version;
62 struct platform_data *pdata;
63 /* maximum length of a platform's sname */
64 size_t platform_sname_maxlen;
65 /* maximum number of devices */
67 /* line prefix, used to identify the platform/device for each
68 * device property in RAW output mode */
74 cl_device_id *all_devices;
77 CLINFO_HUMAN = 1, /* more human readable */
78 CLINFO_RAW = 2, /* property-by-property */
79 CLINFO_BOTH = CLINFO_HUMAN | CLINFO_RAW
82 enum output_modes output_mode = CLINFO_HUMAN;
84 /* Specify if we should only be listing the platform and devices;
85 * can be done in both human and raw mode, and only the platform
86 * and device names (and number) will be shown
87 * TODO check if terminal supports UTF-8 and use Unicode line-drawing
88 * for the tree in list mode
90 cl_bool list_only = CL_FALSE;
92 static const char unk[] = "Unknown";
93 static const char none[] = "None";
94 static const char none_raw[] = "CL_NONE";
95 static const char na[] = "n/a"; // not available
96 static const char core[] = "core"; // not available
98 static const char bytes_str[] = " bytes";
99 static const char pixels_str[] = " pixels";
100 static const char images_str[] = " images";
102 static const char* bool_str[] = { "No", "Yes" };
103 static const char* bool_raw_str[] = { "CL_FALSE", "CL_TRUE" };
105 static const char* endian_str[] = { "Big-Endian", "Little-Endian" };
107 static const cl_device_type devtype[] = { 0,
108 CL_DEVICE_TYPE_DEFAULT, CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_GPU,
109 CL_DEVICE_TYPE_ACCELERATOR, CL_DEVICE_TYPE_CUSTOM, CL_DEVICE_TYPE_ALL };
111 const size_t devtype_count = ARRAY_SIZE(devtype);
113 static const char* device_type_str[] = { unk, "Default", "CPU", "GPU", "Accelerator", "Custom", "All" };
114 static const char* device_type_raw_str[] = { unk,
115 "CL_DEVICE_TYPE_DEFAULT", "CL_DEVICE_TYPE_CPU", "CL_DEVICE_TYPE_GPU",
116 "CL_DEVICE_TYPE_ACCELERATOR", "CL_DEVICE_TYPE_CUSTOM", "CL_DEVICE_TYPE_ALL"
119 static const char* partition_type_str[] = {
120 "none specified", none, "equally", "by counts", "by affinity domain", "by names (Intel)"
122 static const char* partition_type_raw_str[] = {
125 "CL_DEVICE_PARTITION_EQUALLY_EXT",
126 "CL_DEVICE_PARTITION_BY_COUNTS_EXT",
127 "CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT",
128 "CL_DEVICE_PARTITION_BY_NAMES_INTEL_EXT"
131 static const char numa[] = "NUMA";
132 static const char l1cache[] = "L1 cache";
133 static const char l2cache[] = "L2 cache";
134 static const char l3cache[] = "L3 cache";
135 static const char l4cache[] = "L4 cache";
137 static const char* affinity_domain_str[] = {
138 numa, l4cache, l3cache, l2cache, l1cache, "next partitionable"
141 static const char* affinity_domain_ext_str[] = {
142 numa, l4cache, l3cache, l2cache, l1cache, "next fissionable"
145 static const char* affinity_domain_raw_str[] = {
146 "CL_DEVICE_AFFINITY_DOMAIN_NUMA",
147 "CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE",
148 "CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE",
149 "CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE",
150 "CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE",
151 "CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE"
154 static const char* affinity_domain_raw_ext_str[] = {
155 "CL_AFFINITY_DOMAIN_NUMA_EXT",
156 "CL_AFFINITY_DOMAIN_L4_CACHE_EXT",
157 "CL_AFFINITY_DOMAIN_L3_CACHE_EXT",
158 "CL_AFFINITY_DOMAIN_L2_CACHE_EXT",
159 "CL_AFFINITY_DOMAIN_L1_CACHE_EXT",
160 "CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT"
163 const size_t affinity_domain_count = ARRAY_SIZE(affinity_domain_str);
165 static const char* fp_conf_str[] = {
166 "Denormals", "Infinity and NANs", "Round to nearest", "Round to zero",
167 "Round to infinity", "IEEE754-2008 fused multiply-add",
168 "Support is emulated in software",
169 "Correctly-rounded divide and sqrt operations"
172 static const char* fp_conf_raw_str[] = {
175 "CL_FP_ROUND_TO_NEAREST",
176 "CL_FP_ROUND_TO_ZERO",
177 "CL_FP_ROUND_TO_INF",
180 "CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT"
183 const size_t fp_conf_count = ARRAY_SIZE(fp_conf_str);
185 static const char* svm_cap_str[] = {
186 "Coarse-grained buffer sharing",
187 "Fine-grained buffer sharing",
188 "Fine-grained system sharing",
192 static const char* svm_cap_raw_str[] = {
193 "CL_DEVICE_SVM_COARSE_GRAIN_BUFFER",
194 "CL_DEVICE_SVM_FINE_GRAIN_BUFFER",
195 "CL_DEVICE_SVM_FINE_GRAIN_SYSTEM",
196 "CL_DEVICE_SVM_ATOMICS",
199 const size_t svm_cap_count = ARRAY_SIZE(svm_cap_str);
201 static const char* memsfx[] = {
202 "B", "KiB", "MiB", "GiB", "TiB"
205 const size_t memsfx_count = ARRAY_SIZE(memsfx);
207 static const char* lmem_type_str[] = { none, "Local", "Global" };
208 static const char* lmem_type_raw_str[] = { none_raw, "CL_LOCAL", "CL_GLOBAL" };
209 static const char* cache_type_str[] = { none, "Read-Only", "Read/Write" };
210 static const char* cache_type_raw_str[] = { none_raw, "CL_READ_ONLY_CACHE", "CL_READ_WRITE_CACHE" };
212 static const char* queue_prop_str[] = { "Out-of-order execution", "Profiling" };
213 static const char* queue_prop_raw_str[] = {
214 "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE",
215 "CL_QUEUE_PROFILING_ENABLE"
218 const size_t queue_prop_count = ARRAY_SIZE(queue_prop_str);
220 static const char* execap_str[] = { "Run OpenCL kernels", "Run native kernels" };
221 static const char* execap_raw_str[] = {
223 "CL_EXEC_NATIVE_KERNEL"
226 const size_t execap_count = ARRAY_SIZE(execap_str);
228 static const char* sources[] = {
229 "#define GWO(type) global type* restrict\n",
230 "#define GRO(type) global const type* restrict\n",
231 "#define BODY int i = get_global_id(0); out[i] = in1[i] + in2[i]\n",
232 "#define _KRN(T, N) void kernel sum##N(GWO(T##N) out, GRO(T##N) in1, GRO(T##N) in2) { BODY; }\n",
233 "#define KRN(N) _KRN(float, N)\n",
234 "KRN()\n/* KRN(2)\nKRN(4)\nKRN(8)\nKRN(16) */\n",
237 const char *no_plat(void)
239 return output_mode == CLINFO_HUMAN ?
241 "CL_INVALID_PLATFORM";
244 const char *no_dev(void)
246 return output_mode == CLINFO_HUMAN ?
247 "No devices found in platform" :
248 "CL_DEVICE_NOT_FOUND";
251 const char *no_dev_avail(void)
253 return output_mode == CLINFO_HUMAN ?
254 "No devices available in platform" :
255 "CL_DEVICE_NOT_AVAILABLE";
259 /* preferred workgroup size multiple for each kernel
260 * have not found a platform where the WG multiple changes,
261 * but keep this flexible (this can grow up to 5)
263 #define NUM_KERNELS 1
264 size_t wgm[NUM_KERNELS];
267 #define I0_STR "%-48s "
268 #define I1_STR " %-46s "
269 #define I2_STR " %-44s "
271 static const char empty_str[] = "";
272 static const char spc_str[] = " ";
273 static const char times_str[] = "x";
274 static const char comma_str[] = ", ";
275 static const char vbar_str[] = " | ";
278 const char *cur_sfx = empty_str;
280 /* parse a CL_DEVICE_VERSION or CL_PLATFORM_VERSION info to determine the OpenCL version.
281 * Returns an unsigned integer in the form major*10 + minor
284 getOpenCLVersion(const char *version)
288 const char *from = version;
290 parse = strtol(from, &next, 10);
294 // skip the dot TODO should we actually check for the dot?
296 parse = strtol(from, &next, 10);
304 /* print strbuf, prefixed by pname, skipping leading whitespace if skip is nonzero,
305 * affixing cur_sfx */
307 void show_strbuf(const char *pname, int skip)
309 printf("%s" I1_STR "%s%s\n",
311 (skip ? skip_leading_ws(strbuf) : strbuf),
312 had_error ? empty_str : cur_sfx);
316 platform_info_str(cl_platform_id pid, cl_platform_info param, const char* pname, const struct platform_info_checks * chk UNUSED)
318 error = clGetPlatformInfo(pid, param, 0, NULL, &nusz);
319 had_error = REPORT_ERROR2("get %s size");
322 REALLOC(strbuf, nusz, current_param);
325 error = clGetPlatformInfo(pid, param, bufsz, strbuf, NULL);
326 had_error = REPORT_ERROR2("get %s");
328 /* when only listing, do not print anything we're just gathering
332 show_strbuf(pname, 1);
337 platform_info_ulong(cl_platform_id pid, cl_platform_info param, const char* pname, const struct platform_info_checks * chk UNUSED)
341 error = clGetPlatformInfo(pid, param, sizeof(val), &val, NULL);
342 had_error = REPORT_ERROR2("get %s");
343 /* when only listing, do not print anything we're just gathering
348 show_strbuf(pname, 0);
350 printf("%s" I1_STR "%" PRIu64 "%s\n", line_pfx, pname, val, cur_sfx);
355 struct platform_info_traits {
356 cl_platform_info param; // CL_PLATFORM_*
357 const char *sname; // "CL_PLATFORM_*"
358 const char *pname; // "Platform *"
359 const char *sfx; // suffix for the output in non-raw mode
360 /* pointer to function that shows the parameter */
361 int (*show_func)(cl_platform_id pid, cl_platform_info param, const char *pname, const struct platform_info_checks *);
362 /* pointer to function that checks if the parameter should be checked */
363 int (*check_func)(const struct platform_info_checks *);
366 int khr_icd_p(const struct platform_info_checks *chk)
368 return chk->has_khr_icd;
371 int plat_is_21(const struct platform_info_checks *chk)
373 return !(chk->plat_version < 21);
376 #define PINFO_COND(symbol, name, sfx, typ, funcptr) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, &funcptr }
377 #define PINFO(symbol, name, sfx, typ) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, NULL }
378 struct platform_info_traits pinfo_traits[] = {
379 PINFO(CL_PLATFORM_NAME, "Name", NULL, str),
380 PINFO(CL_PLATFORM_VENDOR, "Vendor", NULL, str),
381 PINFO(CL_PLATFORM_VERSION, "Version", NULL, str),
382 PINFO(CL_PLATFORM_PROFILE, "Profile", NULL, str),
383 PINFO(CL_PLATFORM_EXTENSIONS, "Extensions", NULL, str),
384 PINFO_COND(CL_PLATFORM_HOST_TIMER_RESOLUTION, "Host timer resolution", "ns", ulong, plat_is_21),
385 PINFO_COND(CL_PLATFORM_ICD_SUFFIX_KHR, "Extensions function suffix", NULL, str, khr_icd_p)
388 /* Print platform info and prepare arrays for device info */
390 printPlatformInfo(cl_uint p)
392 cl_platform_id pid = platform[p];
395 struct platform_info_checks pinfo_checks = { 0, 10 };
397 current_function = __func__;
399 for (current_line = 0; current_line < ARRAY_SIZE(pinfo_traits); ++current_line) {
400 const struct platform_info_traits *traits = pinfo_traits + current_line;
401 const char *pname = (output_mode == CLINFO_HUMAN ?
402 traits->pname : traits->sname);
404 current_param = traits->sname;
406 if (traits->check_func && !traits->check_func(&pinfo_checks))
409 cur_sfx = (output_mode == CLINFO_HUMAN && traits->sfx) ? traits->sfx : empty_str;
411 had_error = traits->show_func(pid, traits->param,
412 pname, &pinfo_checks);
417 /* post-processing */
419 switch (traits->param) {
420 case CL_PLATFORM_NAME:
421 /* Store name for future reference */
422 len = strlen(strbuf);
423 ALLOC(pdata[p].pname, len+1, "platform name copy");
424 /* memcpy instead of strncpy since we already have the len
425 * and memcpy is possibly more optimized */
426 memcpy(pdata[p].pname, strbuf, len);
427 pdata[p].pname[len] = '\0';
429 case CL_PLATFORM_VERSION:
430 /* compute numeric value for OpenCL version */
431 pinfo_checks.plat_version = getOpenCLVersion(strbuf + 7);
433 case CL_PLATFORM_EXTENSIONS:
434 pinfo_checks.has_khr_icd = !!strstr(strbuf, "cl_khr_icd");
435 pdata[p].has_amd_offline = !!strstr(strbuf, "cl_amd_offline_devices");
437 case CL_PLATFORM_ICD_SUFFIX_KHR:
438 /* Store ICD suffix for future reference */
439 len = strlen(strbuf);
440 ALLOC(pdata[p].sname, len+1, "platform ICD suffix copy");
441 /* memcpy instead of strncpy since we already have the len
442 * and memcpy is possibly more optimized */
443 memcpy(pdata[p].sname, strbuf, len);
444 pdata[p].sname[len] = '\0';
452 if (pinfo_checks.plat_version > max_plat_version)
453 max_plat_version = pinfo_checks.plat_version;
455 /* if no CL_PLATFORM_ICD_SUFFIX_KHR, use P### as short/symbolic name */
456 if (!pdata[p].sname) {
458 ALLOC(pdata[p].sname, SNAME_MAX, "platform symbolic name");
459 snprintf(pdata[p].sname, SNAME_MAX, "P%u", p);
462 len = strlen(pdata[p].sname);
463 if (len > platform_sname_maxlen)
464 platform_sname_maxlen = len;
466 error = clGetDeviceIDs(pid, CL_DEVICE_TYPE_ALL, 0, NULL, &(pdata[p].ndevs));
467 if (error == CL_DEVICE_NOT_FOUND)
470 CHECK_ERROR("number of devices");
472 num_devs_all += pdata[p].ndevs;
474 if (pdata[p].ndevs > maxdevs)
475 maxdevs = pdata[p].ndevs;
479 getWGsizes(cl_platform_id pid, cl_device_id dev)
483 #define RR_ERROR(what) do { \
484 had_error = REPORT_ERROR(what); \
492 cl_context_properties ctxpft[] = {
493 CL_CONTEXT_PLATFORM, (cl_context_properties)pid,
496 cl_context ctx = NULL;
497 cl_program prg = NULL;
498 cl_kernel krn = NULL;
500 ctx = clCreateContext(ctxpft, 1, &dev, NULL, NULL, &error);
501 RR_ERROR("create context");
502 prg = clCreateProgramWithSource(ctx, ARRAY_SIZE(sources), sources, NULL, &error);
503 RR_ERROR("create program");
504 error = clBuildProgram(prg, 1, &dev, NULL, NULL, NULL);
505 had_error = REPORT_ERROR("build program");
509 /* for a program build failure, dump the log to stderr before bailing */
510 if (error == CL_BUILD_PROGRAM_FAILURE) {
511 /* Do not clobber strbuf, shadow it */
513 size_t bufsz = 0, nusz = 0;
514 GET_STRING(clGetProgramBuildInfo, CL_PROGRAM_BUILD_LOG, "CL_PROGRAM_BUILD_LOG", prg, dev);
515 if (error == CL_SUCCESS) {
518 fputs("=== CL_PROGRAM_BUILD_LOG ===\n", stderr);
519 fputs(strbuf, stderr);
527 for (cursor = 0; cursor < NUM_KERNELS; ++cursor) {
528 snprintf(strbuf, bufsz, "sum%u", 1<<cursor);
530 strbuf[3] = 0; // scalar kernel is called 'sum'
531 krn = clCreateKernel(prg, strbuf, &error);
532 RR_ERROR("create kernel");
533 error = clGetKernelWorkGroupInfo(krn, dev, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
534 sizeof(*wgm), wgm + cursor, NULL);
535 RR_ERROR("get kernel info");
536 clReleaseKernel(krn);
542 clReleaseKernel(krn);
544 clReleaseProgram(prg);
546 clReleaseContext(ctx);
551 * Device properties/extensions used in traits checks, and relevant functions
554 struct device_info_checks {
555 cl_device_type devtype;
556 cl_device_mem_cache_type cachetype;
557 cl_device_local_mem_type lmemtype;
558 cl_bool image_support;
559 cl_bool compiler_available;
564 char has_amd_svm[11];
565 char has_arm_svm[29];
566 char has_fission[22];
567 char has_atomic_counters[26];
568 char has_image2d_buffer[27];
569 char has_intel_local_thread[30];
570 char has_intel_AME[36];
571 char has_intel_AVC_ME[43];
572 char has_intel_planar_yuv[20];
573 char has_intel_required_subgroup_size[32];
574 char has_altera_dev_temp[29];
576 char has_qcom_ext_host_ptr[21];
577 char has_simultaneous_sharing[30];
581 #define DEFINE_EXT_CHECK(ext) int dev_has_##ext(const struct device_info_checks *chk) \
583 return !!(chk->has_##ext[0]); \
586 DEFINE_EXT_CHECK(half)
587 DEFINE_EXT_CHECK(double)
589 DEFINE_EXT_CHECK(amd)
590 DEFINE_EXT_CHECK(amd_svm)
591 DEFINE_EXT_CHECK(arm_svm)
592 DEFINE_EXT_CHECK(fission)
593 DEFINE_EXT_CHECK(atomic_counters)
594 DEFINE_EXT_CHECK(image2d_buffer)
595 DEFINE_EXT_CHECK(intel_local_thread)
596 DEFINE_EXT_CHECK(intel_AME)
597 DEFINE_EXT_CHECK(intel_AVC_ME)
598 DEFINE_EXT_CHECK(intel_planar_yuv)
599 DEFINE_EXT_CHECK(intel_required_subgroup_size)
600 DEFINE_EXT_CHECK(altera_dev_temp)
601 DEFINE_EXT_CHECK(spir)
602 DEFINE_EXT_CHECK(qcom_ext_host_ptr)
603 DEFINE_EXT_CHECK(simultaneous_sharing)
605 /* In the version checks we negate the opposite conditions
606 * instead of double-negating the actual condition
609 // device supports 1.2
610 int dev_is_12(const struct device_info_checks *chk)
612 return !(chk->dev_version < 12);
615 // device supports 2.0
616 int dev_is_20(const struct device_info_checks *chk)
618 return !(chk->dev_version < 20);
621 // device supports 2.1
622 int dev_is_21(const struct device_info_checks *chk)
624 return !(chk->dev_version < 21);
627 // device does not support 2.0
628 int dev_not_20(const struct device_info_checks *chk)
630 return !(chk->dev_version >= 20);
634 int dev_is_gpu(const struct device_info_checks *chk)
636 return !!(chk->devtype & CL_DEVICE_TYPE_GPU);
639 int dev_is_gpu_amd(const struct device_info_checks *chk)
641 return dev_is_gpu(chk) && dev_has_amd(chk);
644 int dev_has_svm(const struct device_info_checks *chk)
646 return dev_is_20(chk) || dev_has_amd_svm(chk);
649 int dev_has_partition(const struct device_info_checks *chk)
651 return dev_is_12(chk) || dev_has_fission(chk);
654 int dev_has_cache(const struct device_info_checks *chk)
656 return chk->cachetype != CL_NONE;
659 int dev_has_lmem(const struct device_info_checks *chk)
661 return chk->lmemtype != CL_NONE;
664 int dev_has_images(const struct device_info_checks *chk)
666 return chk->image_support;
669 int dev_has_images_12(const struct device_info_checks *chk)
671 return dev_has_images(chk) && dev_is_12(chk);
674 int dev_has_images_20(const struct device_info_checks *chk)
676 return dev_has_images(chk) && dev_is_20(chk);
679 int dev_has_compiler(const struct device_info_checks *chk)
681 return chk->compiler_available;
685 void identify_device_extensions(const char *extensions, struct device_info_checks *chk)
687 #define _HAS_EXT(ext) (strstr(extensions, ext))
688 #define HAS_EXT(ext) _HAS_EXT(#ext)
689 #define CPY_EXT(what, ext) do { \
690 strncpy(chk->has_##what, has, sizeof(ext)); \
691 chk->has_##what[sizeof(ext)-1] = '\0'; \
693 #define CHECK_EXT(what, ext) do { \
694 has = _HAS_EXT(#ext); \
695 if (has) CPY_EXT(what, #ext); \
699 CHECK_EXT(half, cl_khr_fp16);
700 CHECK_EXT(spir, cl_khr_spir);
701 CHECK_EXT(double, cl_khr_fp64);
702 if (!dev_has_double(chk))
703 CHECK_EXT(double, cl_amd_fp64);
704 if (!dev_has_double(chk))
705 CHECK_EXT(double, cl_APPLE_fp64_basic_ops);
706 CHECK_EXT(nv, cl_nv_device_attribute_query);
707 CHECK_EXT(amd, cl_amd_device_attribute_query);
708 CHECK_EXT(amd_svm, cl_amd_svm);
709 CHECK_EXT(arm_svm, cl_arm_shared_virtual_memory);
710 CHECK_EXT(fission, cl_ext_device_fission);
711 CHECK_EXT(atomic_counters, cl_ext_atomic_counters_64);
712 if (dev_has_atomic_counters(chk))
713 CHECK_EXT(atomic_counters, cl_ext_atomic_counters_32);
714 CHECK_EXT(image2d_buffer, cl_khr_image2d_from_buffer);
715 CHECK_EXT(intel_local_thread, cl_intel_exec_by_local_thread);
716 CHECK_EXT(intel_AME, cl_intel_advanced_motion_estimation);
717 CHECK_EXT(intel_AVC_ME, cl_intel_device_side_avc_motion_estimation);
718 CHECK_EXT(intel_planar_yuv, cl_intel_planar_yuv);
719 CHECK_EXT(intel_required_subgroup_size, cl_intel_required_subgroup_size);
720 CHECK_EXT(altera_dev_temp, cl_altera_device_temperature);
721 CHECK_EXT(qcom_ext_host_ptr, cl_qcom_ext_host_ptr);
722 CHECK_EXT(simultaneous_sharing, cl_intel_simultaneous_sharing);
728 * Device info print functions
732 error = clGetDeviceInfo(dev, param, sizeof(val), &val, NULL); \
733 had_error = REPORT_ERROR2("get %s");
735 #define _GET_VAL_ARRAY \
736 error = clGetDeviceInfo(dev, param, 0, NULL, &szval); \
737 had_error = REPORT_ERROR2("get number of %s"); \
738 numval = szval/sizeof(val); \
740 REALLOC(val, numval, current_param); \
741 error = clGetDeviceInfo(dev, param, szval, val, NULL); \
742 had_error = REPORT_ERROR("get %s"); \
745 #define GET_VAL do { \
749 #define GET_VAL_ARRAY do { \
753 #define _FMT_VAL(fmt) \
755 show_strbuf(pname, 0); \
757 printf("%s" I1_STR fmt "%s\n", line_pfx, pname, val, cur_sfx);
759 #define FMT_VAL(fmt) do { \
763 #define SHOW_VAL(fmt) do { \
768 #define DEFINE_DEVINFO_SHOW(how, type, fmt) \
769 int device_info_##how(cl_device_id dev, cl_device_info param, const char *pname, \
770 const struct device_info_checks *chk UNUSED) \
777 /* Get string-type info without showing it */
778 int device_info_str_get(cl_device_id dev, cl_device_info param, const char *pname,
779 const struct device_info_checks *chk UNUSED)
781 current_param = pname;
782 error = clGetDeviceInfo(dev, param, 0, NULL, &nusz);
783 had_error = REPORT_ERROR2("get %s size");
786 REALLOC(strbuf, nusz, current_param);
789 error = clGetDeviceInfo(dev, param, bufsz, strbuf, NULL);
790 had_error = REPORT_ERROR2("get %s");
795 int device_info_str(cl_device_id dev, cl_device_info param, const char *pname,
796 const struct device_info_checks *chk)
798 had_error = device_info_str_get(dev, param, pname, chk);
799 show_strbuf(pname, 1);
803 DEFINE_DEVINFO_SHOW(int, cl_uint, "%u")
804 DEFINE_DEVINFO_SHOW(hex, cl_uint, "0x%x")
805 DEFINE_DEVINFO_SHOW(long, cl_ulong, "%" PRIu64)
806 DEFINE_DEVINFO_SHOW(sz, size_t, "%" PRIuS)
808 int device_info_bool(cl_device_id dev, cl_device_info param, const char *pname,
809 const struct device_info_checks *chk UNUSED)
812 const char * const * str = (output_mode == CLINFO_HUMAN ?
813 bool_str : bool_raw_str);
816 show_strbuf(pname, 0);
818 printf("%s" I1_STR "%s%s\n", line_pfx, pname, str[val], cur_sfx);
819 /* abuse strbuf to pass the bool value up to the caller,
820 * this is used e.g. by CL_DEVICE_IMAGE_SUPPORT
822 memcpy(strbuf, &val, sizeof(val));
827 int device_info_bits(cl_device_id dev, cl_device_info param, const char *pname,
828 const struct device_info_checks *chk UNUSED)
833 sprintf(strbuf, "%u bits (%u bytes)", val, val/8);
834 show_strbuf(pname, 0);
839 size_t strbuf_mem(cl_ulong val, size_t szval)
843 while (dbl > 1024 && sfx < memsfx_count) {
847 return sprintf(strbuf + szval, " (%.4lg%s)",
851 int device_info_mem(cl_device_id dev, cl_device_info param, const char *pname,
852 const struct device_info_checks *chk UNUSED)
858 szval += sprintf(strbuf, "%" PRIu64, val);
859 if (output_mode == CLINFO_HUMAN && val > 1024)
860 strbuf_mem(val, szval);
862 show_strbuf(pname, 0);
866 int device_info_mem_int(cl_device_id dev, cl_device_info param, const char *pname,
867 const struct device_info_checks *chk UNUSED)
873 szval += sprintf(strbuf, "%u", val);
874 if (output_mode == CLINFO_HUMAN && val > 1024)
875 strbuf_mem(val, szval);
877 show_strbuf(pname, 0);
881 int device_info_free_mem_amd(cl_device_id dev, cl_device_info param, const char *pname,
882 const struct device_info_checks *chk UNUSED)
885 size_t szval = 0, numval = 0;
890 for (cursor = 0; cursor < numval; ++cursor) {
895 szval += sprintf(strbuf + szval, "%" PRIuS, val[cursor]);
896 if (output_mode == CLINFO_HUMAN)
897 szval += strbuf_mem(val[cursor]*UINT64_C(1024), szval);
900 show_strbuf(pname, 0);
905 int device_info_time_offset(cl_device_id dev, cl_device_info param, const char *pname,
906 const struct device_info_checks *chk UNUSED)
912 time_t time = val/UINT64_C(1000000000);
913 szval += snprintf(strbuf, bufsz, "%" PRIu64 "ns (", val);
914 szval += bufcpy(szval, ctime(&time));
915 /* overwrite ctime's newline with the closing parenthesis */
917 strbuf[szval - 1] = ')';
919 show_strbuf(pname, 0);
923 int device_info_szptr(cl_device_id dev, cl_device_info param, const char *pname,
924 const struct device_info_checks *chk UNUSED)
927 size_t szval = 0, numval = 0;
931 set_separator(output_mode == CLINFO_HUMAN ? times_str : spc_str);
933 for (counter = 0; counter < numval; ++counter) {
934 add_separator(&szval);
935 szval += snprintf(strbuf + szval, bufsz - szval - 1, "%" PRIuS, val[counter]);
936 if (szval >= bufsz) {
942 show_strbuf(pname, 0);
947 int device_info_wg(cl_device_id dev, cl_device_info param UNUSED, const char *pname,
948 const struct device_info_checks *chk UNUSED)
950 cl_platform_id val = NULL;
953 cl_device_info param = CL_DEVICE_PLATFORM;
954 current_param = "CL_DEVICE_PLATFORM";
957 current_param = pname;
959 had_error = getWGsizes(val, dev);
961 sprintf(strbuf, "%" PRIuS, wgm[0]);
963 show_strbuf(pname, 0);
967 int device_info_img_sz_2d(cl_device_id dev, cl_device_info param, const char *pname,
968 const struct device_info_checks *chk UNUSED)
970 size_t width = 0, height = 0, val = 0;
971 GET_VAL; /* HEIGHT */
974 param = CL_DEVICE_IMAGE2D_MAX_WIDTH;
975 current_param = "CL_DEVICE_IMAGE2D_MAX_WIDTH";
979 sprintf(strbuf, "%" PRIuS "x%" PRIuS, width, height);
982 show_strbuf(pname, 0);
986 int device_info_img_sz_intel_planar_yuv(cl_device_id dev, cl_device_info param, const char *pname,
987 const struct device_info_checks *chk UNUSED)
989 size_t width = 0, height = 0, val = 0;
990 GET_VAL; /* HEIGHT */
993 param = CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL;
994 current_param = "CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL";
998 sprintf(strbuf, "%" PRIuS "x%" PRIuS, width, height);
1001 show_strbuf(pname, 0);
1006 int device_info_img_sz_3d(cl_device_id dev, cl_device_info param, const char *pname,
1007 const struct device_info_checks *chk UNUSED)
1009 size_t width = 0, height = 0, depth = 0, val = 0;
1010 GET_VAL; /* HEIGHT */
1013 param = CL_DEVICE_IMAGE3D_MAX_WIDTH;
1014 current_param = "CL_DEVICE_IMAGE3D_MAX_WIDTH";
1018 param = CL_DEVICE_IMAGE3D_MAX_DEPTH;
1019 current_param = "CL_DEVICE_IMAGE3D_MAX_DEPTH";
1023 sprintf(strbuf, "%" PRIuS "x%" PRIuS "x%" PRIuS,
1024 width, height, depth);
1028 show_strbuf(pname, 0);
1033 int device_info_devtype(cl_device_id dev, cl_device_info param, const char *pname,
1034 const struct device_info_checks *chk UNUSED)
1036 cl_device_type val = 0;
1039 /* iterate over device type strings, appending their textual form
1041 * TODO: check for extra bits/no bits
1043 cl_uint i = devtype_count - 1; /* skip CL_DEVICE_TYPE_ALL */
1044 const char * const *devstr = (output_mode == CLINFO_HUMAN ?
1045 device_type_str : device_type_raw_str);
1047 strbuf[szval] = '\0';
1048 set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str);
1049 for (; i > 0; --i) {
1050 /* assemble CL_DEVICE_TYPE_* from index i */
1051 cl_device_type cur = (cl_device_type)(1) << (i-1);
1053 /* match: add separator if not first match */
1054 add_separator(&szval);
1055 szval += bufcpy(szval, devstr[i]);
1059 show_strbuf(pname, 0);
1060 /* we abuse global strbuf to pass the device type over to the caller */
1062 memcpy(strbuf, &val, sizeof(val));
1066 int device_info_cachetype(cl_device_id dev, cl_device_info param, const char *pname,
1067 const struct device_info_checks *chk UNUSED)
1069 cl_device_mem_cache_type val = 0;
1072 const char * const *ar = (output_mode == CLINFO_HUMAN ?
1073 cache_type_str : cache_type_raw_str);
1076 show_strbuf(pname, 0);
1077 /* we abuse global strbuf to pass the cache type over to the caller */
1079 memcpy(strbuf, &val, sizeof(val));
1083 int device_info_lmemtype(cl_device_id dev, cl_device_info param, const char *pname,
1084 const struct device_info_checks *chk UNUSED)
1086 cl_device_local_mem_type val = 0;
1089 const char * const *ar = (output_mode == CLINFO_HUMAN ?
1090 lmem_type_str : lmem_type_raw_str);
1093 show_strbuf(pname, 0);
1094 /* we abuse global strbuf to pass the lmem type over to the caller */
1096 memcpy(strbuf, &val, sizeof(val));
1100 /* stringify a cl_device_topology_amd */
1101 void devtopo_str(const cl_device_topology_amd *devtopo)
1103 switch (devtopo->raw.type) {
1105 if (output_mode == CLINFO_HUMAN)
1106 sprintf(strbuf, "(%s)", na);
1108 sprintf(strbuf, none_raw);
1110 case CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD:
1111 sprintf(strbuf, "PCI-E, %02x:%02x.%u",
1112 (cl_uchar)(devtopo->pcie.bus),
1113 devtopo->pcie.device, devtopo->pcie.function);
1116 sprintf(strbuf, "<unknown (%u): %u %u %u %u %u>",
1118 devtopo->raw.data[0], devtopo->raw.data[1],
1119 devtopo->raw.data[2],
1120 devtopo->raw.data[3], devtopo->raw.data[4]);
1124 int device_info_devtopo_amd(cl_device_id dev, cl_device_info param, const char *pname,
1125 const struct device_info_checks *chk UNUSED)
1127 cl_device_topology_amd val;
1129 /* TODO how to do this in CLINFO_RAW mode */
1133 show_strbuf(pname, 0);
1137 /* we assemble a cl_device_topology_amd struct from the NVIDIA info */
1138 int device_info_devtopo_nv(cl_device_id dev, cl_device_info param, const char *pname,
1139 const struct device_info_checks *chk UNUSED)
1141 cl_device_topology_amd devtopo;
1144 devtopo.raw.type = CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD;
1146 GET_VAL; /* CL_DEVICE_PCI_BUS_ID_NV */
1149 devtopo.pcie.bus = val & 0xff;
1151 param = CL_DEVICE_PCI_SLOT_ID_NV;
1152 current_param = "CL_DEVICE_PCI_SLOT_ID_NV";
1157 devtopo.pcie.device = val >> 3;
1158 devtopo.pcie.function = val & 7;
1159 devtopo_str(&devtopo);
1163 show_strbuf(pname, 0);
1167 /* NVIDIA Compute Capability */
1168 int device_info_cc_nv(cl_device_id dev, cl_device_info param, const char *pname,
1169 const struct device_info_checks *chk UNUSED)
1171 cl_uint major = 0, val = 0;
1172 GET_VAL; /* MAJOR */
1175 param = CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV;
1176 current_param = "CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV";
1179 snprintf(strbuf, bufsz, "%u.%u", major, val);
1182 show_strbuf(pname, 0);
1187 int device_info_gfxip_amd(cl_device_id dev, cl_device_info param, const char *pname,
1188 const struct device_info_checks *chk UNUSED)
1190 cl_uint major = 0, val = 0;
1191 GET_VAL; /* MAJOR */
1194 param = CL_DEVICE_GFXIP_MINOR_AMD;
1195 current_param = "CL_DEVICE_GFXIP_MINOR_AMD";
1198 snprintf(strbuf, bufsz, "%u.%u", major, val);
1201 show_strbuf(pname, 0);
1206 /* Device Partition, CLINFO_HUMAN header */
1207 int device_info_partition_header(cl_device_id dev UNUSED, cl_device_info param UNUSED,
1208 const char *pname, const struct device_info_checks *chk)
1210 int is_12 = dev_is_12(chk);
1211 int has_fission = dev_has_fission(chk);
1212 size_t szval = snprintf(strbuf, bufsz, "(%s%s%s)",
1213 (is_12 ? core : empty_str),
1214 (is_12 && has_fission ? comma_str : empty_str),
1219 show_strbuf(pname, 0);
1220 had_error = CL_SUCCESS;
1224 /* Device partition properties */
1225 int device_info_partition_types(cl_device_id dev, cl_device_info param, const char *pname,
1226 const struct device_info_checks *chk UNUSED)
1228 size_t numval = 0, szval = 0, cursor = 0, slen = 0;
1229 cl_device_partition_property *val = NULL;
1230 const char * const *ptstr = (output_mode == CLINFO_HUMAN ?
1231 partition_type_str : partition_type_raw_str);
1233 set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str);
1239 for (cursor = 0; cursor < numval; ++cursor) {
1242 /* add separator for values past the first */
1243 add_separator(&szval);
1245 switch (val[cursor]) {
1246 case 0: str_idx = 1; break;
1247 case CL_DEVICE_PARTITION_EQUALLY: str_idx = 2; break;
1248 case CL_DEVICE_PARTITION_BY_COUNTS: str_idx = 3; break;
1249 case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN: str_idx = 4; break;
1250 case CL_DEVICE_PARTITION_BY_NAMES_INTEL: str_idx = 5; break;
1252 szval += snprintf(strbuf + szval, bufsz - szval - 1, "by <unknown> (0x%" PRIXPTR ")", val[cursor]);
1256 /* string length, minus _EXT */
1257 slen = strlen(ptstr[str_idx]);
1258 if (output_mode == CLINFO_RAW && str_idx > 1)
1260 szval += bufcpy_len(szval, ptstr[str_idx], slen);
1262 if (szval >= bufsz) {
1268 bufcpy(szval, ptstr[0]);
1269 } else if (szval < bufsz)
1270 strbuf[szval] = '\0';
1273 show_strbuf(pname, 0);
1279 int device_info_partition_types_ext(cl_device_id dev, cl_device_info param, const char *pname,
1280 const struct device_info_checks *chk UNUSED)
1282 size_t numval = 0, szval = 0, cursor = 0, slen = 0;
1283 cl_device_partition_property_ext *val = NULL;
1284 const char * const *ptstr = (output_mode == CLINFO_HUMAN ?
1285 partition_type_str : partition_type_raw_str);
1287 set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str);
1293 for (cursor = 0; cursor < numval; ++cursor) {
1296 /* add separator for values past the first */
1297 add_separator(&szval);
1299 switch (val[cursor]) {
1300 case 0: str_idx = 1; break;
1301 case CL_DEVICE_PARTITION_EQUALLY_EXT: str_idx = 2; break;
1302 case CL_DEVICE_PARTITION_BY_COUNTS_EXT: str_idx = 3; break;
1303 case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT: str_idx = 4; break;
1304 case CL_DEVICE_PARTITION_BY_NAMES_EXT: str_idx = 5; break;
1306 szval += snprintf(strbuf + szval, bufsz - szval - 1, "by <unknown> (0x%" PRIX64 ")", val[cursor]);
1311 slen = strlen(ptstr[str_idx]);
1312 strncpy(strbuf + szval, ptstr[str_idx], slen);
1315 if (szval >= bufsz) {
1321 slen = strlen(ptstr[0]);
1322 memcpy(strbuf, ptstr[0], slen);
1326 strbuf[szval] = '\0';
1329 show_strbuf(pname, 0);
1336 /* Device partition affinity domains */
1337 int device_info_partition_affinities(cl_device_id dev, cl_device_info param, const char *pname,
1338 const struct device_info_checks *chk UNUSED)
1340 cl_device_affinity_domain val;
1342 if (!had_error && val) {
1343 /* iterate over affinity domain strings appending their textual form
1345 * TODO: check for extra bits/no bits
1349 const char * const *affstr = (output_mode == CLINFO_HUMAN ?
1350 affinity_domain_str : affinity_domain_raw_str);
1351 set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str);
1352 for (i = 0; i < affinity_domain_count; ++i) {
1353 cl_device_affinity_domain cur = (cl_device_affinity_domain)(1) << i;
1355 /* match: add separator if not first match */
1356 add_separator(&szval);
1357 szval += bufcpy(szval, affstr[i]);
1363 if (val || had_error)
1364 show_strbuf(pname, 0);
1368 int device_info_partition_affinities_ext(cl_device_id dev, cl_device_info param, const char *pname,
1369 const struct device_info_checks *chk UNUSED)
1371 size_t numval = 0, szval = 0, cursor = 0, slen = 0;
1372 cl_device_partition_property_ext *val = NULL;
1373 const char * const *ptstr = (output_mode == CLINFO_HUMAN ?
1374 affinity_domain_ext_str : affinity_domain_raw_ext_str);
1376 set_separator(output_mode == CLINFO_HUMAN ? comma_str : vbar_str);
1382 for (cursor = 0; cursor < numval; ++cursor) {
1385 /* add separator for values past the first */
1386 add_separator(&szval);
1388 switch (val[cursor]) {
1389 case CL_AFFINITY_DOMAIN_NUMA_EXT: str_idx = 0; break;
1390 case CL_AFFINITY_DOMAIN_L4_CACHE_EXT: str_idx = 1; break;
1391 case CL_AFFINITY_DOMAIN_L3_CACHE_EXT: str_idx = 2; break;
1392 case CL_AFFINITY_DOMAIN_L2_CACHE_EXT: str_idx = 3; break;
1393 case CL_AFFINITY_DOMAIN_L1_CACHE_EXT: str_idx = 4; break;
1394 case CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT: str_idx = 5; break;
1396 szval += snprintf(strbuf + szval, bufsz - szval - 1, "<unknown> (0x%" PRIX64 ")", val[cursor]);
1401 const char *str = ptstr[str_idx];
1403 strncpy(strbuf + szval, str, slen);
1406 if (szval >= bufsz) {
1411 strbuf[szval] = '\0';
1414 show_strbuf(pname, 0);
1420 /* Preferred / native vector widths */
1421 int device_info_vecwidth(cl_device_id dev, cl_device_info param, const char *pname,
1422 const struct device_info_checks *chk)
1424 cl_uint preferred = 0, val = 0;
1429 /* we get called with PREFERRED, NATIVE is at +0x30 offset, except for HALF,
1430 * which is at +0x08 */
1431 param += (param == CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF ? 0x08 : 0x30);
1432 /* TODO update current_param */
1437 const char *ext = (param == CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF ?
1438 chk->has_half : (param == CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE ?
1439 chk->has_double : NULL));
1440 szval = sprintf(strbuf, "%8u / %-8u", preferred, val);
1442 sprintf(strbuf + szval, " (%s)", *ext ? ext : na);
1445 show_strbuf(pname, 0);
1449 /* Floating-point configurations */
1450 int device_info_fpconf(cl_device_id dev, cl_device_info param, const char *pname,
1451 const struct device_info_checks *chk)
1453 cl_device_fp_config val = 0;
1455 (param == CL_DEVICE_SINGLE_FP_CONFIG) ||
1456 (param == CL_DEVICE_HALF_FP_CONFIG && dev_has_half(chk)) ||
1457 (param == CL_DEVICE_DOUBLE_FP_CONFIG && dev_has_double(chk)));
1461 had_error = CL_SUCCESS;
1466 const char * const *fpstr = (output_mode == CLINFO_HUMAN ?
1467 fp_conf_str : fp_conf_raw_str);
1468 set_separator(vbar_str);
1469 if (output_mode == CLINFO_HUMAN) {
1470 const char *why = na;
1472 case CL_DEVICE_HALF_FP_CONFIG:
1474 why = chk->has_half;
1476 case CL_DEVICE_SINGLE_FP_CONFIG:
1479 case CL_DEVICE_DOUBLE_FP_CONFIG:
1481 why = chk->has_double;
1484 /* "this can't happen" (unless OpenCL starts supporting _other_ floating-point formats, maybe) */
1485 fprintf(stderr, "unsupported floating-point configuration parameter %s\n", pname);
1488 /* show 'why' it's being shown */
1489 szval += sprintf(strbuf, "(%s)", why);
1492 for (i = 0; i < fp_conf_count; ++i) {
1493 cl_device_fp_config cur = (cl_device_fp_config)(1) << i;
1494 if (output_mode == CLINFO_HUMAN) {
1495 szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s",
1496 line_pfx, fpstr[i], bool_str[!!(val & cur)]);
1497 } else if (val & cur) {
1498 add_separator(&szval);
1499 szval += bufcpy(szval, fpstr[i]);
1505 /* only print this for HUMAN output or if we actually got the value */
1506 if (output_mode == CLINFO_HUMAN || get_it)
1507 show_strbuf(pname, 0);
1511 /* Queue properties */
1512 int device_info_qprop(cl_device_id dev, cl_device_info param, const char *pname,
1513 const struct device_info_checks *chk)
1515 cl_command_queue_properties val = 0;
1520 const char * const *qpstr = (output_mode == CLINFO_HUMAN ?
1521 queue_prop_str : queue_prop_raw_str);
1522 set_separator(vbar_str);
1523 for (i = 0; i < queue_prop_count; ++i) {
1524 cl_command_queue_properties cur = (cl_command_queue_properties)(1) << i;
1525 if (output_mode == CLINFO_HUMAN) {
1526 szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s",
1527 line_pfx, qpstr[i], bool_str[!!(val & cur)]);
1528 } else if (val & cur) {
1529 add_separator(&szval);
1530 szval += bufcpy(szval, qpstr[i]);
1533 if (output_mode == CLINFO_HUMAN && param == CL_DEVICE_QUEUE_PROPERTIES &&
1534 dev_has_intel_local_thread(chk))
1535 sprintf(strbuf + szval, "\n%s" I2_STR "%s",
1536 line_pfx, "Local thread execution (Intel)", bool_str[CL_TRUE]);
1538 show_strbuf(pname, 0);
1542 /* Execution capbilities */
1543 int device_info_execap(cl_device_id dev, cl_device_info param, const char *pname,
1544 const struct device_info_checks *chk UNUSED)
1546 cl_device_exec_capabilities val = 0;
1551 const char * const *qpstr = (output_mode == CLINFO_HUMAN ?
1552 execap_str : execap_raw_str);
1553 set_separator(vbar_str);
1554 for (i = 0; i < execap_count; ++i) {
1555 cl_device_exec_capabilities cur = (cl_device_exec_capabilities)(1) << i;
1556 if (output_mode == CLINFO_HUMAN) {
1557 szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s",
1558 line_pfx, qpstr[i], bool_str[!!(val & cur)]);
1559 } else if (val & cur) {
1560 add_separator(&szval);
1561 szval += bufcpy(szval, qpstr[i]);
1565 show_strbuf(pname, 0);
1569 /* Arch bits and endianness (HUMAN) */
1570 int device_info_arch(cl_device_id dev, cl_device_info param, const char *pname,
1571 const struct device_info_checks *chk UNUSED)
1582 param = CL_DEVICE_ENDIAN_LITTLE;
1583 current_param = "CL_DEVICE_ENDIAN_LITTLE";
1586 sprintf(strbuf, "%u, %s", bits, endian_str[val]);
1588 show_strbuf(pname, 0);
1592 /* SVM capabilities */
1593 int device_info_svm_cap(cl_device_id dev, cl_device_info param, const char *pname,
1594 const struct device_info_checks *chk)
1596 cl_device_svm_capabilities val = 0;
1597 const int is_20 = dev_is_20(chk);
1598 const int has_amd_svm = (param == CL_DEVICE_SVM_CAPABILITIES && dev_has_amd_svm(chk));
1605 const char * const *scstr = (output_mode == CLINFO_HUMAN ?
1606 svm_cap_str : svm_cap_raw_str);
1607 set_separator(vbar_str);
1608 if (output_mode == CLINFO_HUMAN && param == CL_DEVICE_SVM_CAPABILITIES) {
1609 /* show 'why' it's being shown */
1610 szval += sprintf(strbuf, "(%s%s%s)",
1611 (is_20 ? core : empty_str),
1612 (is_20 && has_amd_svm ? comma_str : empty_str),
1615 for (i = 0; i < svm_cap_count; ++i) {
1616 cl_device_svm_capabilities cur = (cl_device_svm_capabilities)(1) << i;
1617 if (output_mode == CLINFO_HUMAN) {
1618 szval += sprintf(strbuf + szval, "\n%s" I2_STR "%s",
1619 line_pfx, scstr[i], bool_str[!!(val & cur)]);
1620 } else if (val & cur) {
1621 add_separator(&szval);
1622 szval += bufcpy(szval, scstr[i]);
1627 show_strbuf(pname, 0);
1632 * Device info traits
1635 /* A CL_FALSE param means "just print pname" */
1637 struct device_info_traits {
1638 enum output_modes output_mode;
1639 cl_device_info param; // CL_DEVICE_*
1640 const char *sname; // "CL_DEVICE_*"
1641 const char *pname; // "Device *"
1642 const char *sfx; // suffix for the output in non-raw mode
1643 /* pointer to function that shows the parameter */
1644 int (*show_func)(cl_device_id dev, cl_device_info param, const char *pname, const struct device_info_checks *);
1645 /* pointer to function that checks if the parameter should be checked */
1646 int (*check_func)(const struct device_info_checks *);
1649 #define DINFO_SFX(symbol, name, sfx, typ) symbol, #symbol, name, sfx, device_info_##typ
1650 #define DINFO(symbol, name, typ) symbol, #symbol, name, NULL, device_info_##typ
1652 struct device_info_traits dinfo_traits[] = {
1653 { CLINFO_BOTH, DINFO(CL_DEVICE_NAME, "Device Name", str), NULL },
1654 { CLINFO_BOTH, DINFO(CL_DEVICE_VENDOR, "Device Vendor", str), NULL },
1655 { CLINFO_BOTH, DINFO(CL_DEVICE_VENDOR_ID, "Device Vendor ID", hex), NULL },
1656 { CLINFO_BOTH, DINFO(CL_DEVICE_VERSION, "Device Version", str), NULL },
1657 { CLINFO_BOTH, DINFO(CL_DRIVER_VERSION, "Driver Version", str), NULL },
1658 { CLINFO_BOTH, DINFO(CL_DEVICE_OPENCL_C_VERSION, "Device OpenCL C Version", str), NULL },
1659 { CLINFO_BOTH, DINFO(CL_DEVICE_EXTENSIONS, "Device Extensions", str_get), NULL },
1660 { CLINFO_BOTH, DINFO(CL_DEVICE_TYPE, "Device Type", devtype), NULL },
1662 { CLINFO_BOTH, DINFO(CL_DEVICE_AVAILABLE, "Device Available", bool), NULL },
1664 { CLINFO_BOTH, DINFO(CL_DEVICE_PROFILE, "Device Profile", str), NULL },
1665 { CLINFO_BOTH, DINFO(CL_DEVICE_BOARD_NAME_AMD, "Device Board Name (AMD)", str), dev_has_amd },
1666 { CLINFO_BOTH, DINFO(CL_DEVICE_TOPOLOGY_AMD, "Device Topology (AMD)", devtopo_amd), dev_has_amd },
1668 /* Device Topology (NV) is multipart, so different for HUMAN and RAW */
1669 { CLINFO_HUMAN, DINFO(CL_DEVICE_PCI_BUS_ID_NV, "Device Topology (NV)", devtopo_nv), dev_has_nv },
1670 { CLINFO_RAW, DINFO(CL_DEVICE_PCI_BUS_ID_NV, "Device PCI bus (NV)", int), dev_has_nv },
1671 { CLINFO_RAW, DINFO(CL_DEVICE_PCI_SLOT_ID_NV, "Device PCI slot (NV)", int), dev_has_nv },
1673 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_COMPUTE_UNITS, "Max compute units", int), NULL },
1674 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, "SIMD per compute unit (AMD)", int), dev_is_gpu_amd },
1675 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_WIDTH_AMD, "SIMD width (AMD)", int), dev_is_gpu_amd },
1676 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, "SIMD instruction width (AMD)", int), dev_is_gpu_amd },
1677 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_MAX_CLOCK_FREQUENCY, "Max clock frequency", "MHz", int), NULL },
1679 /* Device Compute Capability (NV) is multipart, so different for HUMAN and RAW */
1680 { CLINFO_HUMAN, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, "Compute Capability (NV)", cc_nv), dev_has_nv },
1681 { CLINFO_RAW, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, INDENT "Compute Capability Major (NV)", int), dev_has_nv },
1682 { CLINFO_RAW, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, INDENT "Compute Capability Minor (NV)", int), dev_has_nv },
1684 /* GFXIP (AMD) is multipart, so different for HUMAN and RAW */
1685 /* TODO: find a better human-friendly name than GFXIP; v3 of the cl_amd_device_attribute_query
1686 * extension specification calls it “core engine GFXIP”, which honestly is not better than
1687 * our name choice. */
1688 { CLINFO_HUMAN, DINFO(CL_DEVICE_GFXIP_MAJOR_AMD, "Graphics IP (AMD)", gfxip_amd), dev_is_gpu_amd },
1689 { CLINFO_RAW, DINFO(CL_DEVICE_GFXIP_MAJOR_AMD, INDENT "Graphics IP MAJOR (AMD)", int), dev_is_gpu_amd },
1690 { CLINFO_RAW, DINFO(CL_DEVICE_GFXIP_MINOR_AMD, INDENT "Graphics IP MINOR (AMD)", int), dev_is_gpu_amd },
1692 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_CORE_TEMPERATURE_ALTERA, "Core Temperature (Altera)", " C", int), dev_has_altera_dev_temp },
1694 /* Device partition support: summary is only presented in HUMAN case */
1695 { CLINFO_HUMAN, DINFO(CL_DEVICE_PARTITION_MAX_SUB_DEVICES, "Device Partition", partition_header), dev_has_partition },
1696 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_MAX_SUB_DEVICES, INDENT "Max number of sub-devices", int), dev_is_12 },
1697 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_PROPERTIES, INDENT "Supported partition types", partition_types), dev_is_12 },
1698 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_AFFINITY_DOMAIN, INDENT "Supported affinity domains", partition_affinities), dev_is_12 },
1699 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_TYPES_EXT, INDENT "Supported partition types (ext)", partition_types_ext), dev_has_fission },
1700 { CLINFO_BOTH, DINFO(CL_DEVICE_AFFINITY_DOMAINS_EXT, INDENT "Supported affinity domains (ext)", partition_affinities_ext), dev_has_fission },
1702 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, "Max work item dimensions", int), NULL },
1703 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_ITEM_SIZES, "Max work item sizes", szptr), NULL },
1704 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_GROUP_SIZE, "Max work group size", sz), NULL },
1706 { CLINFO_BOTH, DINFO(CL_DEVICE_COMPILER_AVAILABLE, "Compiler Available", bool), NULL },
1707 { CLINFO_BOTH, DINFO(CL_DEVICE_LINKER_AVAILABLE, "Linker Available", bool), dev_is_12 },
1708 { CLINFO_BOTH, DINFO(CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, "Preferred work group size multiple", wg), dev_has_compiler },
1709 { CLINFO_BOTH, DINFO(CL_DEVICE_WARP_SIZE_NV, "Warp size (NV)", int), dev_has_nv },
1710 { CLINFO_BOTH, DINFO(CL_DEVICE_WAVEFRONT_WIDTH_AMD, "Wavefront width (AMD)", int), dev_is_gpu_amd },
1711 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_NUM_SUB_GROUPS, "Max sub-groups per work group", int), dev_is_21 },
1712 { CLINFO_BOTH, DINFO(CL_DEVICE_SUB_GROUP_SIZES_INTEL, "Sub-group sizes (Intel)", szptr), dev_has_intel_required_subgroup_size },
1714 /* Preferred/native vector widths: header is only presented in HUMAN case, that also pairs
1715 * PREFERRED and NATIVE in a single line */
1716 #define DINFO_VECWIDTH(Type, type) \
1717 { CLINFO_HUMAN, DINFO(CL_DEVICE_PREFERRED_VECTOR_WIDTH_##Type, INDENT #type, vecwidth), NULL }, \
1718 { CLINFO_RAW, DINFO(CL_DEVICE_PREFERRED_VECTOR_WIDTH_##Type, INDENT #type, int), NULL }, \
1719 { CLINFO_RAW, DINFO(CL_DEVICE_NATIVE_VECTOR_WIDTH_##Type, INDENT #type, int), NULL }
1721 { CLINFO_HUMAN, DINFO(CL_FALSE, "Preferred / native vector sizes", str), NULL },
1722 DINFO_VECWIDTH(CHAR, char),
1723 DINFO_VECWIDTH(SHORT, short),
1724 DINFO_VECWIDTH(INT, int),
1725 DINFO_VECWIDTH(LONG, long),
1726 DINFO_VECWIDTH(HALF, half),
1727 DINFO_VECWIDTH(FLOAT, float),
1728 DINFO_VECWIDTH(DOUBLE, double),
1730 /* Floating point configurations */
1731 #define DINFO_FPCONF(Type, type, cond) \
1732 { CLINFO_BOTH, DINFO(CL_DEVICE_##Type##_FP_CONFIG, #type "-precision Floating-point support", fpconf), NULL }
1734 DINFO_FPCONF(HALF, Half, dev_has_half),
1735 DINFO_FPCONF(SINGLE, Single, NULL),
1736 DINFO_FPCONF(DOUBLE, Double, dev_has_double),
1738 /* Address bits and endianness are written together for HUMAN, separate for RAW */
1739 { CLINFO_HUMAN, DINFO(CL_DEVICE_ADDRESS_BITS, "Address bits", arch), NULL },
1740 { CLINFO_RAW, DINFO(CL_DEVICE_ADDRESS_BITS, "Address bits", int), NULL },
1741 { CLINFO_RAW, DINFO(CL_DEVICE_ENDIAN_LITTLE, "Little Endian", bool), NULL },
1744 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_SIZE, "Global memory size", mem), NULL },
1745 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, "Global free memory (AMD)", free_mem_amd), dev_is_gpu_amd },
1746 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, "Global memory channels (AMD)", int), dev_is_gpu_amd },
1747 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, "Global memory banks per channel (AMD)", int), dev_is_gpu_amd },
1748 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, "Global memory bank width (AMD)", bytes_str, int), dev_is_gpu_amd },
1749 { CLINFO_BOTH, DINFO(CL_DEVICE_ERROR_CORRECTION_SUPPORT, "Error Correction support", bool), NULL },
1750 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_MEM_ALLOC_SIZE, "Max memory allocation", mem), NULL },
1751 { CLINFO_BOTH, DINFO(CL_DEVICE_HOST_UNIFIED_MEMORY, "Unified memory for Host and Device", bool), NULL },
1752 { CLINFO_BOTH, DINFO(CL_DEVICE_INTEGRATED_MEMORY_NV, "Integrated memory (NV)", bool), dev_has_nv },
1754 { CLINFO_BOTH, DINFO(CL_DEVICE_SVM_CAPABILITIES, "Shared Virtual Memory (SVM) capabilities", svm_cap), dev_has_svm },
1755 { CLINFO_BOTH, DINFO(CL_DEVICE_SVM_CAPABILITIES_ARM, "Shared Virtual Memory (SVM) capabilities (ARM)", svm_cap), dev_has_arm_svm },
1758 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, "Minimum alignment for any data type", bytes_str, int), NULL },
1759 { CLINFO_HUMAN, DINFO(CL_DEVICE_MEM_BASE_ADDR_ALIGN, "Alignment of base address", bits), NULL },
1760 { CLINFO_RAW, DINFO(CL_DEVICE_MEM_BASE_ADDR_ALIGN, "Alignment of base address", int), NULL },
1762 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PAGE_SIZE_QCOM, "Page size (QCOM)", bytes_str, sz), dev_has_qcom_ext_host_ptr },
1763 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM, "Externa memory padding (QCOM)", bytes_str, sz), dev_has_qcom_ext_host_ptr },
1765 /* Atomics alignment, with HUMAN-only header */
1766 { CLINFO_HUMAN, DINFO(CL_FALSE, "Preferred alignment for atomics", str), dev_is_20 },
1767 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT, INDENT "SVM", bytes_str, int), dev_is_20 },
1768 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT, INDENT "Global", bytes_str, int), dev_is_20 },
1769 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT, INDENT "Local", bytes_str, int), dev_is_20 },
1771 /* Global variables. TODO some 1.2 devices respond to this too */
1772 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, "Max size for global variable", mem), dev_is_20 },
1773 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, "Preferred total size of global vars", mem), dev_is_20 },
1775 /* Global memory cache */
1776 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, "Global Memory cache type", cachetype), NULL },
1777 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, "Global Memory cache size", sz), dev_has_cache },
1778 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, "Global Memory cache line", " bytes", int), dev_has_cache },
1781 { CLINFO_BOTH, DINFO(CL_DEVICE_IMAGE_SUPPORT, "Image support", bool), NULL },
1782 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_SAMPLERS, INDENT "Max number of samplers per kernel", int), dev_has_images },
1783 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, INDENT "Max size for 1D images from buffer", pixels_str, sz), dev_has_images_12 },
1784 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, INDENT "Max 1D or 2D image array size", images_str, sz), dev_has_images_12 },
1785 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, INDENT "Base address alignment for 2D image buffers", bytes_str, sz), dev_has_image2d_buffer },
1786 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_IMAGE_PITCH_ALIGNMENT, INDENT "Pitch alignment for 2D image buffers", bytes_str, sz), dev_has_image2d_buffer },
1788 /* Image dimensions are split for RAW, combined for HUMAN */
1789 { CLINFO_HUMAN, DINFO_SFX(CL_DEVICE_IMAGE2D_MAX_HEIGHT, INDENT "Max 2D image size", pixels_str, img_sz_2d), dev_has_images },
1790 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE2D_MAX_HEIGHT, INDENT "Max 2D image height", sz), dev_has_images },
1791 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE2D_MAX_WIDTH, INDENT "Max 2D image width", sz), dev_has_images },
1792 { CLINFO_HUMAN, DINFO_SFX(CL_DEVICE_PLANAR_YUV_MAX_HEIGHT_INTEL, INDENT "Max planar YUV image size", pixels_str, img_sz_2d), dev_has_intel_planar_yuv },
1793 { CLINFO_RAW, DINFO(CL_DEVICE_PLANAR_YUV_MAX_HEIGHT_INTEL, INDENT "Max planar YUV image height", sz), dev_has_intel_planar_yuv },
1794 { CLINFO_RAW, DINFO(CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL, INDENT "Max planar YUV image width", sz), dev_has_intel_planar_yuv },
1795 { CLINFO_HUMAN, DINFO_SFX(CL_DEVICE_IMAGE3D_MAX_HEIGHT, INDENT "Max 3D image size", pixels_str, img_sz_3d), dev_has_images },
1796 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_HEIGHT, INDENT "Max 3D image height", sz), dev_has_images },
1797 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_WIDTH, INDENT "Max 3D image width", sz), dev_has_images },
1798 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_DEPTH, INDENT "Max 3D image depth", sz), dev_has_images },
1800 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_READ_IMAGE_ARGS, INDENT "Max number of read image args", int), dev_has_images },
1801 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WRITE_IMAGE_ARGS, INDENT "Max number of write image args", int), dev_has_images },
1802 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, INDENT "Max number of read/write image args", int), dev_has_images_20 },
1805 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_PIPE_ARGS, "Max number of pipe args", int), dev_is_20 },
1806 { CLINFO_BOTH, DINFO(CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS, "Max active pipe reservations", int), dev_is_20 },
1807 { CLINFO_BOTH, DINFO(CL_DEVICE_PIPE_MAX_PACKET_SIZE, "Max pipe packet size", mem_int), dev_is_20 },
1810 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_TYPE, "Local memory type", lmemtype), NULL },
1811 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_SIZE, "Local memory size", mem), dev_has_lmem },
1812 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, "Local memory syze per CU (AMD)", mem), dev_is_gpu_amd },
1813 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_BANKS_AMD, "Local memory banks (AMD)", int), dev_is_gpu_amd },
1814 { CLINFO_BOTH, DINFO(CL_DEVICE_REGISTERS_PER_BLOCK_NV, "Registers per block (NV)", int), dev_has_nv },
1816 /* Constant memory */
1817 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, "Max constant buffer size", mem), NULL },
1818 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_CONSTANT_ARGS, "Max number of constant args", int), NULL },
1820 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_PARAMETER_SIZE, "Max size of kernel argument", mem), NULL },
1821 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ATOMIC_COUNTERS_EXT, "Max number of atomic counters", sz), dev_has_atomic_counters },
1823 /* Queue properties */
1824 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_PROPERTIES, "Queue properties", qprop), dev_not_20 },
1825 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_PROPERTIES, "Queue properties (on host)", qprop), dev_is_20 },
1826 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, "Queue properties (on device)", qprop), dev_is_20 },
1827 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE, INDENT "Preferred size", mem), dev_is_20 },
1828 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, INDENT "Max size", mem), dev_is_20 },
1829 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ON_DEVICE_QUEUES, "Max queues on device", int), dev_is_20 },
1830 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ON_DEVICE_EVENTS, "Max events on device", int), dev_is_20 },
1833 { CLINFO_BOTH, DINFO(CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, "Prefer user sync for interop", bool), dev_is_12 },
1834 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL, "Number of simulataneous interops (Intel)", int), dev_has_simultaneous_sharing },
1835 /* TODO: this needs defines for the possible values of the context interops,
1836 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL, "Simulataneous interops", interop_list), dev_has_simultaneous_sharing },
1839 /* Profiling resolution */
1840 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PROFILING_TIMER_RESOLUTION, "Profiling timer resolution", "ns", sz), NULL },
1841 { CLINFO_HUMAN, DINFO(CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, "Profiling timer offset since Epoch (AMD)", time_offset), dev_has_amd },
1842 { CLINFO_RAW, DINFO(CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, "Profiling timer offset since Epoch (AMD)", long), dev_has_amd },
1844 /* Kernel execution capabilities */
1845 { CLINFO_BOTH, DINFO(CL_DEVICE_EXECUTION_CAPABILITIES, "Execution capabilities", execap), NULL },
1846 { CLINFO_BOTH, DINFO(CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS, INDENT "Sub-group independent forward progress", bool), dev_is_21 },
1847 { CLINFO_BOTH, DINFO(CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD, INDENT "Thread trace supported (AMD)", bool), dev_is_gpu_amd },
1848 { CLINFO_BOTH, DINFO(CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, INDENT "Kernel execution timeout (NV)", bool), dev_has_nv },
1849 { CLINFO_BOTH, DINFO(CL_DEVICE_GPU_OVERLAP_NV, "Concurrent copy and kernel execution (NV)", bool), dev_has_nv },
1850 { CLINFO_BOTH, DINFO(CL_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT_NV, INDENT "Number of async copy engines", int), dev_has_nv },
1851 /* TODO FIXME Current drivers don't seem to respond to this, should probably be queried based on driver version,
1852 * or maybe it depends on some other device property?
1853 { CLINFO_BOTH, DINFO(CL_DEVICE_AVAILABLE_ASYNC_QUEUES_AMD, INDENT "Number of async queues (AMD)", int), dev_is_gpu_amd },
1855 { CLINFO_BOTH, DINFO(CL_DEVICE_IL_VERSION, INDENT "IL version", str), dev_is_21, },
1856 { CLINFO_BOTH, DINFO(CL_DEVICE_SPIR_VERSIONS, INDENT "SPIR versions", str), dev_has_spir },
1857 { CLINFO_BOTH, DINFO(CL_DEVICE_PRINTF_BUFFER_SIZE, "printf() buffer size", mem), dev_is_12 },
1858 { CLINFO_BOTH, DINFO(CL_DEVICE_BUILT_IN_KERNELS, "Built-in kernels", str), dev_is_12 },
1859 { CLINFO_BOTH, DINFO(CL_DEVICE_ME_VERSION_INTEL, "Motion Estimation accelerator version (Intel)", int), dev_has_intel_AME },
1860 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_VERSION_INTEL, INDENT "Device-side AVC Motion Estimation version", int), dev_has_intel_AVC_ME },
1861 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_SUPPORTS_TEXTURE_SAMPLER_USE_INTEL, INDENT INDENT "Supports texture sampler use", bool), dev_has_intel_AVC_ME },
1862 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_SUPPORTS_PREEMPTION_INTEL, INDENT INDENT "Supports preemption", bool), dev_has_intel_AVC_ME },
1865 /* Process all the device info in the traits, except if param_whitelist is not NULL,
1866 * in which case only those in the whitelist will be processed.
1867 * If present, the whitelist should be sorted in the order of appearance of the parameters
1868 * in the traits table, and terminated by the value CL_FALSE
1872 printDeviceInfo(const cl_device_id *device, cl_uint d,
1873 const cl_device_info *param_whitelist) /* list of device info to process, or NULL */
1875 cl_device_id dev = device[d];
1877 char *extensions = NULL;
1879 /* pointer to the traits for CL_DEVICE_EXTENSIONS */
1880 const struct device_info_traits *extensions_traits = NULL;
1882 struct device_info_checks chk;
1883 memset(&chk, 0, sizeof(chk));
1884 chk.dev_version = 10;
1886 current_function = __func__;
1888 for (current_line = 0; current_line < ARRAY_SIZE(dinfo_traits); ++current_line) {
1890 const struct device_info_traits *traits = dinfo_traits + current_line;
1891 const char *pname = (output_mode == CLINFO_HUMAN ?
1892 traits->pname : traits->sname);
1894 current_param = traits->sname;
1896 /* Whitelist check: finish if done traversing the list,
1897 * skip current param if it's not the right one
1899 if (param_whitelist) {
1900 if (*param_whitelist == CL_FALSE)
1902 if (traits->param != *param_whitelist)
1907 /* skip if it's not for this output mode */
1908 if (!(output_mode & traits->output_mode))
1911 if (traits->check_func && !traits->check_func(&chk))
1914 cur_sfx = (output_mode == CLINFO_HUMAN && traits->sfx) ? traits->sfx : empty_str;
1916 /* Handle headers */
1917 if (traits->param == CL_FALSE) {
1919 show_strbuf(pname, 0);
1920 had_error = CL_FALSE;
1924 had_error = traits->show_func(dev, traits->param,
1927 if (traits->param == CL_DEVICE_EXTENSIONS) {
1928 /* make a backup of the extensions string, regardless of
1930 size_t len = strlen(strbuf);
1931 extensions_traits = traits;
1932 ALLOC(extensions, len+1, "extensions");
1933 memcpy(extensions, strbuf, len);
1934 extensions[len] = '\0';
1940 switch (traits->param) {
1941 case CL_DEVICE_VERSION:
1942 /* compute numeric value for OpenCL version */
1943 chk.dev_version = getOpenCLVersion(strbuf + 7);
1945 case CL_DEVICE_EXTENSIONS:
1946 identify_device_extensions(extensions, &chk);
1948 case CL_DEVICE_TYPE:
1949 /* strbuf was abused to give us the dev type */
1950 memcpy(&(chk.devtype), strbuf, sizeof(chk.devtype));
1952 case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE:
1953 /* strbuf was abused to give us the cache type */
1954 memcpy(&(chk.cachetype), strbuf, sizeof(chk.cachetype));
1956 case CL_DEVICE_LOCAL_MEM_TYPE:
1957 /* strbuf was abused to give us the lmem type */
1958 memcpy(&(chk.lmemtype), strbuf, sizeof(chk.lmemtype));
1960 case CL_DEVICE_IMAGE_SUPPORT:
1961 /* strbuf was abused to give us boolean value */
1962 memcpy(&(chk.image_support), strbuf, sizeof(chk.image_support));
1964 case CL_DEVICE_COMPILER_AVAILABLE:
1965 /* strbuf was abused to give us boolean value */
1966 memcpy(&(chk.compiler_available), strbuf, sizeof(chk.compiler_available));
1974 // and finally the extensions, if we retrieved them
1976 printf("%s" I1_STR "%s\n", line_pfx, (output_mode == CLINFO_HUMAN ?
1977 extensions_traits->pname :
1978 extensions_traits->sname), extensions);
1983 /* list of allowed properties for AMD offline devices */
1984 /* everything else seems to be set to 0, and all the other string properties
1985 * actually segfault the driver */
1987 static const cl_device_info amd_offline_info_whitelist[] = {
1989 /* These are present, but all the same, so just skip them:
1991 CL_DEVICE_VENDOR_ID,
1994 CL_DEVICE_OPENCL_C_VERSION,
1996 CL_DEVICE_EXTENSIONS,
1998 CL_DEVICE_MAX_WORK_GROUP_SIZE,
2002 /* process offline devices from the cl_amd_offline_devices extension */
2003 int processOfflineDevicesAMD(cl_uint p)
2007 cl_platform_id pid = platform[p];
2008 cl_device_id *device = NULL;
2011 cl_context_properties ctxpft[] = {
2012 CL_CONTEXT_PLATFORM, (cl_context_properties)pid,
2013 CL_CONTEXT_OFFLINE_DEVICES_AMD, (cl_context_properties)CL_TRUE,
2017 cl_context ctx = NULL;
2020 printf("%s" I0_STR, line_pfx,
2021 (output_mode == CLINFO_HUMAN ?
2022 "Number of offline devices (AMD)" : "#OFFDEVICES"));
2024 ctx = clCreateContextFromType(ctxpft, CL_DEVICE_TYPE_ALL, NULL, NULL, &error);
2025 RR_ERROR("create context");
2027 error = clGetContextInfo(ctx, CL_CONTEXT_NUM_DEVICES, sizeof(num_devs), &num_devs, NULL);
2028 RR_ERROR("get num devs");
2030 ALLOC(device, num_devs, "offline devices");
2032 error = clGetContextInfo(ctx, CL_CONTEXT_DEVICES, num_devs*sizeof(*device), device, NULL);
2033 RR_ERROR("get devs");
2036 printf("%d\n", num_devs);
2038 for (d = 0; d < num_devs; ++d) {
2041 if (output_mode == CLINFO_HUMAN)
2044 if (d == num_devs - 1 && output_mode != CLINFO_RAW)
2046 had_error = device_info_str_get(device[d], CL_DEVICE_NAME, "CL_DEVICE_NAME", NULL);
2047 printf("%s%u: %s\n", line_pfx, d, strbuf);
2049 if (line_pfx_len > 0) {
2050 sprintf(strbuf, "[%s/%u]", pdata[p].sname, -d);
2051 sprintf(line_pfx, "%*s", -line_pfx_len, strbuf);
2053 printDeviceInfo(device, d, amd_offline_info_whitelist);
2054 if (d < num_devs - 1)
2061 had_error = CL_FALSE;
2065 clReleaseContext(ctx);
2070 void listPlatformsAndDevices(cl_bool show_offline)
2073 cl_device_id *device;
2075 if (output_mode == CLINFO_RAW)
2076 sprintf(strbuf, "%u", num_platforms);
2078 sprintf(strbuf, " +-- %sDevice #", (show_offline ? "Offline" : ""));
2080 line_pfx_len = strlen(strbuf) + 1;
2081 REALLOC(line_pfx, line_pfx_len, "line prefix");
2083 for (p = 0, device = all_devices; p < num_platforms; device += pdata[p++].ndevs) {
2084 printf("%s%u: %s\n",
2085 (output_mode == CLINFO_HUMAN ? "Platform #" : ""),
2087 if (output_mode == CLINFO_RAW)
2088 sprintf(line_pfx, "%u:", p);
2090 sprintf(line_pfx, " +-- Device #");
2092 if (pdata[p].ndevs > 0) {
2093 error = clGetDeviceIDs(platform[p], CL_DEVICE_TYPE_ALL, pdata[p].ndevs, device, NULL);
2094 CHECK_ERROR("device IDs");
2095 for (d = 0; d < pdata[p].ndevs; ++d) {
2097 if (output_mode == CLINFO_HUMAN)
2100 cl_bool last_device = (d == pdata[p].ndevs - 1 && output_mode != CLINFO_RAW &&
2101 (!show_offline || !pdata[p].has_amd_offline));
2104 had_error = device_info_str_get(device[d], CL_DEVICE_NAME, "CL_DEVICE_NAME", NULL);
2105 printf("%s%u: %s\n", line_pfx, d, strbuf);
2111 if (show_offline && pdata[p].has_amd_offline) {
2112 if (output_mode == CLINFO_RAW)
2113 sprintf(line_pfx, "%u*", p);
2115 sprintf(line_pfx, " +-- Offline Device #");
2116 had_error = processOfflineDevicesAMD(p);
2123 void showDevices(cl_bool show_offline)
2126 cl_device_id *device;
2128 /* TODO consider enabling this for both output modes */
2129 if (output_mode == CLINFO_RAW) {
2130 sprintf(strbuf, "%u", maxdevs);
2131 line_pfx_len = platform_sname_maxlen + strlen(strbuf) + 4;
2132 REALLOC(line_pfx, line_pfx_len, "line prefix");
2135 for (p = 0, device = all_devices; p < num_platforms; device += pdata[p++].ndevs) {
2136 if (line_pfx_len > 0) {
2137 sprintf(strbuf, "[%s/*]", pdata[p].sname);
2138 sprintf(line_pfx, "%*s", -line_pfx_len, strbuf);
2140 printf("%s" I1_STR "%s\n",
2142 (output_mode == CLINFO_HUMAN ?
2143 pinfo_traits[0].pname : pinfo_traits[0].sname),
2145 printf("%s" I0_STR "%u\n",
2147 (output_mode == CLINFO_HUMAN ?
2148 "Number of devices" : "#DEVICES"),
2151 if (pdata[p].ndevs > 0) {
2152 error = clGetDeviceIDs(platform[p], CL_DEVICE_TYPE_ALL, pdata[p].ndevs, device, NULL);
2153 CHECK_ERROR("device IDs");
2155 for (d = 0; d < pdata[p].ndevs; ++d) {
2156 if (line_pfx_len > 0) {
2157 sprintf(strbuf, "[%s/%u]", pdata[p].sname, d);
2158 sprintf(line_pfx, "%*s", -line_pfx_len, strbuf);
2160 printDeviceInfo(device, d, NULL);
2161 if (d < pdata[p].ndevs - 1)
2166 if (show_offline && pdata[p].has_amd_offline) {
2168 had_error = processOfflineDevicesAMD(p);
2176 /* check the behavior of clGetPlatformInfo() when given a NULL platform ID */
2177 void checkNullGetPlatformName(void)
2179 current_param = "CL_PLATFORM_NAME";
2181 error = clGetPlatformInfo(NULL, CL_PLATFORM_NAME, bufsz, strbuf, NULL);
2182 if (error == CL_INVALID_PLATFORM) {
2183 bufcpy(0, no_plat());
2185 current_line = __LINE__+1;
2186 had_error = REPORT_ERROR2("get %s");
2188 printf(I1_STR "%s\n",
2189 "clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...)", strbuf);
2192 /* check the behavior of clGetDeviceIDs() when given a NULL platform ID;
2193 * return the index of the default platform in our array of platform IDs,
2194 * or num_platforms (which is an invalid platform index) in case of errors
2195 * or no platform or device found.
2197 cl_uint checkNullGetDevices(void)
2199 cl_uint i = 0; /* generic iterator */
2200 cl_device_id dev = NULL; /* sample device */
2201 cl_platform_id plat = NULL; /* detected platform */
2203 cl_uint found = 0; /* number of platforms found */
2204 cl_uint pidx = num_platforms; /* index of the platform found */
2205 cl_uint numdevs = 0;
2207 current_function = __func__;
2208 current_param = "device IDs";
2210 error = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, 0, NULL, &numdevs);
2211 /* TODO we should check other CL_DEVICE_TYPE_* combinations, since a smart
2212 * implementation might give you a different default platform for GPUs
2214 * Of course the “no devices” case would then need to be handled differently.
2215 * The logic might be maintained similarly, provided we also gather
2216 * the number of devices of each type for each platform, although it's
2217 * obviously more likely to have multiple platforms with no devices
2222 case CL_INVALID_PLATFORM:
2223 bufcpy(0, no_plat());
2225 case CL_DEVICE_NOT_FOUND:
2226 /* No devices were found, see if there are platforms with
2227 * no devices, and if there's only one, assume this is the
2228 * one being used as default by the ICD loader */
2229 for (i = 0; i < num_platforms; ++i) {
2230 if (pdata[i].ndevs == 0) {
2243 bufcpy(0, (output_mode == CLINFO_HUMAN ?
2244 "<error: 0 devices, no matching platform!>" :
2245 "CL_DEVICE_NOT_FOUND | CL_INVALID_PLATFORM"));
2248 bufcpy(0, (output_mode == CLINFO_HUMAN ?
2250 pdata[pidx].sname));
2252 default: /* found > 1 */
2253 bufcpy(0, (output_mode == CLINFO_HUMAN ?
2254 "<error: 0 devices, multiple matching platforms!>" :
2255 "CL_DEVICE_NOT_FOUND | ????"));
2260 current_line = __LINE__+1;
2261 had_error = REPORT_ERROR2("get number of %s");
2265 /* Determine platform by looking at the CL_DEVICE_PLATFORM of
2266 * one of the devices */
2267 error = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, 1, &dev, NULL);
2268 current_line = __LINE__+1;
2269 had_error = REPORT_ERROR2("get %s");
2273 current_param = "CL_DEVICE_PLATFORM";
2274 error = clGetDeviceInfo(dev, CL_DEVICE_PLATFORM,
2275 sizeof(plat), &plat, NULL);
2276 current_line = __LINE__+1;
2277 had_error = REPORT_ERROR2("get %s");
2281 for (i = 0; i < num_platforms; ++i) {
2282 if (platform[i] == plat) {
2284 sprintf(strbuf, "%s [%s]",
2285 (output_mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
2290 if (i == num_platforms) {
2291 sprintf(strbuf, "<error: platform 0x%p not found>", (void*)plat);
2294 printf(I1_STR "%s\n",
2295 "clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...)", strbuf);
2299 void checkNullCtx(cl_uint pidx, const cl_device_id *dev, const char *which)
2301 cl_context ctx = clCreateContext(NULL, 1, dev, NULL, NULL, &error);
2303 current_function = __func__;
2304 current_param = which;
2305 current_line = __LINE__+2;
2307 had_error = REPORT_ERROR2("create context with device from %s platform");
2309 sprintf(strbuf, "%s [%s]",
2310 (output_mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
2313 clReleaseContext(ctx);
2318 /* check behavior of clCreateContextFromType() with NULL cl_context_properties */
2319 void checkNullCtxFromType(void)
2321 size_t t; /* type iterator */
2322 size_t i; /* generic iterator */
2324 cl_context ctx = NULL;
2328 size_t cursz = ndevs*sizeof(cl_device_id);
2329 cl_platform_id plat = NULL;
2330 cl_device_id *devs = NULL;
2332 const char *platname_prop = (output_mode == CLINFO_HUMAN ?
2333 pinfo_traits[0].pname :
2334 pinfo_traits[0].sname);
2336 const char *devname_prop = (output_mode == CLINFO_HUMAN ?
2337 dinfo_traits[0].pname :
2338 dinfo_traits[0].sname);
2340 ALLOC(devs, ndevs, "context devices");
2342 current_function = __func__;
2343 for (t = 2; t < devtype_count; ++t) { /* we skip 0 and _DEFAULT */
2344 current_param = device_type_raw_str[t];
2346 sprintf(strbuf, "clCreateContextFromType(NULL, %s)", current_param);
2347 sprintf(def, I1_STR, strbuf);
2349 current_line = __LINE__+1;
2350 ctx = clCreateContextFromType(NULL, devtype[t], NULL, NULL, &error);
2353 case CL_INVALID_PLATFORM:
2354 bufcpy(0, no_plat()); break;
2355 case CL_DEVICE_NOT_FOUND:
2356 case CL_INVALID_DEVICE_TYPE: /* e.g. _CUSTOM device on 1.1 platform */
2357 bufcpy(0, no_dev()); break;
2358 case CL_DEVICE_NOT_AVAILABLE:
2359 bufcpy(0, no_dev_avail()); break;
2361 had_error = REPORT_ERROR2("create context from type %s");
2365 /* get the devices */
2366 current_param = "CL_CONTEXT_DEVICES";
2367 current_line = __LINE__+2;
2369 error = clGetContextInfo(ctx, CL_CONTEXT_DEVICES, 0, NULL, &szval);
2370 had_error = REPORT_ERROR2("get %s size");
2373 if (szval > cursz) {
2374 REALLOC(devs, szval, "context devices");
2378 current_line = __LINE__+1;
2379 error = clGetContextInfo(ctx, CL_CONTEXT_DEVICES, cursz, devs, NULL);
2380 had_error = REPORT_ERROR2("get %s");
2383 ndevs = szval/sizeof(cl_device_id);
2385 bufcpy(0, "<error: context created with no devices>");
2388 /* get the platform from the first device */
2389 current_param = "CL_DEVICE_PLATFORM";
2390 current_line = __LINE__+1;
2391 error = clGetDeviceInfo(*devs, CL_DEVICE_PLATFORM, sizeof(plat), &plat, NULL);
2392 had_error = REPORT_ERROR2("get %s");
2397 for (i = 0; i < num_platforms; ++i) {
2398 if (platform[i] == plat)
2401 if (i == num_platforms) {
2402 sprintf(strbuf, "<error: platform 0x%p not found>", (void*)plat);
2405 szval += sprintf(strbuf, "%s (%" PRIuS ")",
2406 (output_mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
2408 szval += snprintf(strbuf + szval, bufsz - szval, "\n" I2_STR "%s",
2409 platname_prop, pdata[i].pname);
2411 for (i = 0; i < ndevs; ++i) {
2413 /* for each device, show the device name */
2414 /* TODO some other unique ID too, e.g. PCI address, if available? */
2416 szval += snprintf(strbuf + szval, bufsz - szval, "\n" I2_STR, devname_prop);
2417 if (szval >= bufsz) {
2422 current_param = "CL_DEVICE_NAME";
2423 current_line = __LINE__+1;
2424 error = clGetDeviceInfo(devs[i], CL_DEVICE_NAME, bufsz - szval, strbuf + szval, &szname);
2425 had_error = REPORT_ERROR2("get %s");
2428 szval += szname - 1;
2433 break; /* had an error earlier, bail */
2438 clReleaseContext(ctx);
2441 printf("%s%s\n", def, strbuf);
2446 /* check the behavior of NULL platform in clGetDeviceIDs (see checkNullGetDevices)
2447 * and in clCreateContext() */
2448 void checkNullBehavior(void)
2450 cl_device_id *dev = NULL;
2454 printf("NULL platform behavior\n");
2456 checkNullGetPlatformName();
2458 pidx = checkNullGetDevices();
2460 /* If there's a default platform, and it has devices, try
2461 * creating a context with its first device and see if it works */
2463 if (pidx == num_platforms) {
2464 bufcpy(0, no_plat());
2465 } else if (pdata[pidx].ndevs == 0) {
2466 bufcpy(0, no_dev());
2470 while (p < num_platforms && p != pidx) {
2471 dev += pdata[p++].ndevs;
2473 if (p < num_platforms) {
2474 checkNullCtx(pidx, dev, "default");
2476 /* this shouldn't happen, but still ... */
2477 bufcpy(0, "<error: overflow in default platform scan>");
2480 printf(I1_STR "%s\n", "clCreateContext(NULL, ...) [default]", strbuf);
2482 /* Look for a device from a non-default platform, if there are any */
2483 if (pidx == num_platforms || num_platforms > 1) {
2486 while (p < num_platforms && (p == pidx || pdata[p].ndevs == 0)) {
2487 dev += pdata[p++].ndevs;
2489 if (p < num_platforms) {
2490 checkNullCtx(p, dev, "non-default");
2492 bufcpy(0, "<error: no devices in non-default plaforms>");
2494 printf(I1_STR "%s\n", "clCreateContext(NULL, ...) [other]", strbuf);
2497 checkNullCtxFromType();
2502 /* Get properties of the ocl-icd loader, if available */
2503 /* All properties are currently char[] */
2505 CL_ICDL_OCL_VERSION=1,
2511 /* Function pointer to the ICD loader info function */
2512 cl_int (*clGetICDLoaderInfoOCLICD)(cl_icdl_info, size_t, void*, size_t*);
2514 /* We want to auto-detect the OpenCL version supported by the ICD loader.
2515 * To do this, we will progressively find symbols introduced in new APIs,
2516 * until a NULL symbol is found.
2519 struct icd_loader_test {
2522 } icd_loader_tests[] = {
2523 { 11, "clCreateSubBuffer" },
2524 { 12, "clCreateImage" },
2525 { 20, "clSVMAlloc" },
2526 { 21, "clGetHostTimer" },
2531 icdl_info_str(cl_icdl_info param, const char* pname)
2533 error = clGetICDLoaderInfoOCLICD(param, 0, NULL, &nusz);
2534 had_error = REPORT_ERROR2("get %s size");
2537 REALLOC(strbuf, nusz, current_param);
2540 error = clGetICDLoaderInfoOCLICD(param, bufsz, strbuf, NULL);
2541 had_error = REPORT_ERROR2("get %s");
2543 show_strbuf(pname, 1);
2547 struct icdl_info_traits {
2548 cl_icdl_info param; // CL_ICDL_*
2549 const char *sname; // "CL_ICDL_*"
2550 const char *pname; // "ICD loader *"
2553 static const char * const oclicdl_pfx = "OCLICD";
2555 #define LINFO(symbol, name) { symbol, #symbol, "ICD loader " name }
2556 struct icdl_info_traits linfo_traits[] = {
2557 LINFO(CL_ICDL_NAME, "Name"),
2558 LINFO(CL_ICDL_VENDOR, "Vendor"),
2559 LINFO(CL_ICDL_VERSION, "Version"),
2560 LINFO(CL_ICDL_OCL_VERSION, "Profile")
2563 /* GCC < 4.6 does not support the diagnostic push _inside_ the function,
2564 * so we have to put it outside
2566 #if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46)
2567 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2570 void oclIcdProps(void)
2572 /* First of all, we try to auto-detect the supported ICD loader version */
2576 struct icd_loader_test check = icd_loader_tests[i];
2577 if (check.symbol == NULL)
2579 if (dlsym(RTLD_DEFAULT, check.symbol) == NULL)
2581 icdl_ocl_version_found = check.version;
2586 /* We find the clGetICDLoaderInfoOCLICD extension address, and use it to query
2587 * the ICD loader properties. It should be noted however that
2588 * clGetExtensionFunctionAddress is marked deprecated as of OpenCL 1.2, so
2589 * to use it and compile cleanly we need disable the relevant warning.
2590 * It should be noted that in this specific case we cannot replace the
2591 * call to clGetExtensionFunctionAddress with a call to the superseding function
2592 * clGetExtensionFunctionAddressForPlatform because the extension is in the
2593 * loader itself, not in a specific platform.
2597 #pragma warning(push)
2598 #pragma warning(disable : 4996)
2599 #elif defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) >= 46)
2600 #pragma GCC diagnostic push
2601 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
2604 PTR_FUNC_PTR clGetICDLoaderInfoOCLICD = clGetExtensionFunctionAddress("clGetICDLoaderInfoOCLICD");
2607 #pragma warning(pop)
2608 #elif defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) >= 46)
2609 #pragma GCC diagnostic pop
2612 if (clGetICDLoaderInfoOCLICD != NULL) {
2613 /* TODO think of a sensible header in CLINFO_RAW */
2614 if (output_mode != CLINFO_RAW)
2615 puts("\nICD loader properties");
2616 current_function = __func__;
2618 if (output_mode == CLINFO_RAW) {
2619 line_pfx_len = strlen(oclicdl_pfx) + 5;
2620 REALLOC(line_pfx, line_pfx_len, "line prefix OCL ICD");
2621 sprintf(strbuf, "[%s/*]", oclicdl_pfx);
2622 sprintf(line_pfx, "%*s", -line_pfx_len, strbuf);
2625 for (current_line = 0; current_line < ARRAY_SIZE(linfo_traits); ++current_line) {
2626 const struct icdl_info_traits *traits = linfo_traits + current_line;
2627 current_param = traits->sname;
2629 had_error = icdl_info_str(traits->param,
2630 output_mode == CLINFO_HUMAN ?
2631 traits->pname : traits->sname);
2633 if (!had_error && traits->param == CL_ICDL_OCL_VERSION) {
2634 icdl_ocl_version = getOpenCLVersion(strbuf + 7);
2639 if (output_mode == CLINFO_HUMAN) {
2640 if (icdl_ocl_version &&
2641 icdl_ocl_version != icdl_ocl_version_found) {
2642 printf( "\tNOTE:\tyour OpenCL library declares to support OpenCL %u.%u,\n"
2643 "\t\tbut it seems to support up to OpenCL %u.%u %s.\n",
2644 icdl_ocl_version / 10, icdl_ocl_version % 10,
2645 icdl_ocl_version_found / 10, icdl_ocl_version_found % 10,
2646 icdl_ocl_version_found < icdl_ocl_version ?
2649 if (icdl_ocl_version_found < max_plat_version) {
2650 printf( "\tNOTE:\tyour OpenCL library only supports OpenCL %u.%u,\n"
2651 "\t\tbut some installed platforms support OpenCL %u.%u.\n"
2652 "\t\tPrograms using %u.%u features may crash\n"
2653 "\t\tor behave unexepectedly\n",
2654 icdl_ocl_version_found / 10, icdl_ocl_version_found % 10,
2655 max_plat_version / 10, max_plat_version % 10,
2656 max_plat_version / 10, max_plat_version % 10);
2661 #if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46)
2662 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
2667 puts("clinfo version 2.1.16.01.12");
2673 puts("Display properties of all available OpenCL platforms and devices");
2674 puts("Usage: clinfo [options ...]\n");
2676 puts("\t--human\t\thuman-friendly output (default)");
2677 puts("\t--raw\t\traw output");
2678 puts("\t--offline\talso show offline devices");
2679 puts("\t--list, -l\tonly list the platforms and devices by name");
2680 puts("\t-h, -?\t\tshow usage");
2681 puts("\t--version, -v\tshow version\n");
2682 puts("Defaults to raw mode if invoked with");
2683 puts("a name that contains the string \"raw\"");
2686 int main(int argc, char *argv[])
2691 cl_bool show_offline = CL_FALSE;
2693 /* if there's a 'raw' in the program name, switch to raw output mode */
2694 if (strstr(argv[0], "raw"))
2695 output_mode = CLINFO_RAW;
2697 /* process command-line arguments */
2698 while (++a < argc) {
2699 if (!strcmp(argv[a], "--raw"))
2700 output_mode = CLINFO_RAW;
2701 else if (!strcmp(argv[a], "--human"))
2702 output_mode = CLINFO_HUMAN;
2703 else if (!strcmp(argv[a], "--offline"))
2704 show_offline = CL_TRUE;
2705 else if (!strcmp(argv[a], "-l") || !strcmp(argv[a], "--list"))
2706 list_only = CL_TRUE;
2707 else if (!strcmp(argv[a], "-?") || !strcmp(argv[a], "-h")) {
2710 } else if (!strcmp(argv[a], "--version") || !strcmp(argv[a], "-v")) {
2714 fprintf(stderr, "ignoring unknown command-line parameter %s\n", argv[a]);
2719 ALLOC(strbuf, 1024, "general string buffer");
2722 error = clGetPlatformIDs(0, NULL, &num_platforms);
2723 if (error != CL_PLATFORM_NOT_FOUND_KHR)
2724 CHECK_ERROR("number of platforms");
2727 printf(I0_STR "%u\n",
2728 (output_mode == CLINFO_HUMAN ?
2729 "Number of platforms" : "#PLATFORMS"),
2734 ALLOC(platform, num_platforms, "platform IDs");
2735 error = clGetPlatformIDs(num_platforms, platform, NULL);
2736 CHECK_ERROR("platform IDs");
2738 ALLOC(pdata, num_platforms, "platform data");
2739 ALLOC(line_pfx, 1, "line prefix");
2741 for (p = 0; p < num_platforms; ++p) {
2742 printPlatformInfo(p);
2747 if (num_devs_all > 0) {
2748 ALLOC(all_devices, num_devs_all, "device IDs");
2752 listPlatformsAndDevices(show_offline);
2754 showDevices(show_offline);
2755 if (output_mode != CLINFO_RAW)
2756 checkNullBehavior();