1 /* Collect all available information on all available devices
2 * on all available OpenCL platforms present in the system
8 /* We will want to check for symbols in the OpenCL library.
9 * On Windows, we must get the module handle for it, on Unix-like
10 * systems we can just use RTLD_DEFAULT
14 # define dlsym GetProcAddress
15 # define DL_MODULE GetModuleHandle("OpenCL")
19 # define DL_MODULE RTLD_DEFAULT
21 # define DL_MODULE ((void*)0) /* This would be RTLD_DEFAULT */
25 /* Load STDC format macros (PRI*), or define them
26 * for those crappy, non-standard compilers
28 #include "fmtmacros.h"
30 // More support for the horrible MS C compiler
32 #include "ms_support.h"
45 #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(*ar))
48 #define UNUSED(x) x __attribute__((unused))
51 struct platform_data {
52 char *pname; /* CL_PLATFORM_NAME */
53 char *sname; /* CL_PLATFORM_ICD_SUFFIX_KHR or surrogate */
54 cl_uint ndevs; /* number of devices */
55 cl_bool has_amd_offline; /* has cl_amd_offline_devices extension */
58 struct platform_info_checks {
61 cl_bool has_amd_object_metadata;
62 cl_bool has_extended_versioning;
63 cl_bool has_external_memory;
64 cl_bool has_semaphore;
65 cl_bool has_external_semaphore;
68 struct platform_list {
69 /* Number of platforms in the system */
70 cl_uint num_platforms;
71 /* Total number of devices across all platforms */
73 /* Number of devices allocated in all_devs array */
75 /* Highest OpenCL version supported by any platform.
76 * If the OpenCL library / ICD loader only supports
77 * a lower version, problems may arise (such as
78 * API calls causing segfaults or any other unexpected
81 cl_uint max_plat_version;
82 /* Largest number of devices on any platform */
84 /* Length of the longest platform sname */
86 /* Array of platform IDs */
87 cl_platform_id *platform;
88 /* Array of device IDs (across all platforms) */
89 cl_device_id *all_devs;
90 /* Array of offsets in all_devs where the devices
91 * of each platform begin */
93 /* Array of clinfo-specific platform data */
94 struct platform_data *pdata;
95 /* Array of clinfo-specific platform checks */
96 struct platform_info_checks *platform_checks;
100 init_plist(struct platform_list *plist)
102 plist->num_platforms = 0;
103 plist->ndevs_total = 0;
104 plist->alloc_devs = 0;
105 plist->max_plat_version = 0;
107 plist->max_sname_len = 0;
108 plist->platform = NULL;
109 plist->all_devs = NULL;
110 plist->dev_offset = NULL;
112 plist->platform_checks = NULL;
115 void plist_devs_reserve(struct platform_list *plist, cl_uint amount)
117 if (amount > plist->alloc_devs) {
118 REALLOC(plist->all_devs, amount, "all devices");
119 plist->alloc_devs = amount;
125 alloc_plist(struct platform_list *plist, const struct opt_out *output)
127 cl_uint num_platforms = plist->num_platforms;
128 if (output->null_platform)
130 ALLOC(plist->platform, num_platforms, "platform IDs");
131 ALLOC(plist->dev_offset, num_platforms, "platform device list offset");
132 /* The actual sizing for this will change as we gather platform info,
133 * but assume at least one device per platform
135 plist_devs_reserve(plist, num_platforms);
136 ALLOC(plist->pdata, num_platforms, "platform data");
137 ALLOC(plist->platform_checks, num_platforms, "platform checks data");
138 return num_platforms;
141 free_plist(struct platform_list *plist)
143 free(plist->platform);
144 free(plist->all_devs);
145 free(plist->dev_offset);
146 for (cl_uint p = 0 ; p < plist->num_platforms; ++p) {
147 free(plist->pdata[p].sname);
148 free(plist->pdata[p].pname);
151 free(plist->platform_checks);
156 get_platform_devs(const struct platform_list *plist, cl_uint p)
158 return plist->all_devs + plist->dev_offset[p];
162 get_platform_dev(const struct platform_list *plist, cl_uint p, cl_uint d)
164 return get_platform_devs(plist, p)[d];
167 /* Data for the OpenCL library / ICD loader */
169 /* auto-detected OpenCL version support for the ICD loader */
170 cl_uint detected_version;
171 /* OpenCL version support declared by the ICD loader */
172 cl_uint reported_version;
175 /* line prefix, used to identify the platform/device for each
176 * device property in RAW output mode */
180 #define CHECK_SIZE(ret, loc, val, cmd, ...) do { \
181 /* check if the issue is with param size */ \
182 if (output->check_size && ret->err == CL_INVALID_VALUE) { \
184 if (cmd(__VA_ARGS__, 0, NULL, &_actual_sz) == CL_SUCCESS) { \
185 REPORT_SIZE_MISMATCH(&(ret->err_str), loc, _actual_sz, sizeof(val)); \
190 static const char unk[] = "Unknown";
191 static const char none[] = "None";
192 static const char none_raw[] = "CL_NONE";
193 static const char na[] = "n/a"; // not available
194 static const char na_wrap[] = "(n/a)"; // not available
195 static const char core[] = "core";
197 static const char bytes_str[] = " bytes";
198 static const char pixels_str[] = " pixels";
199 static const char images_str[] = " images";
201 static const char* bool_str[] = { "No", "Yes" };
202 static const char* bool_raw_str[] = { "CL_FALSE", "CL_TRUE" };
203 static const char* bool_json_str[] = { "false", "true" };
205 static const char* endian_str[] = { "Big-Endian", "Little-Endian" };
207 static const cl_device_type devtype[] = { 0,
208 CL_DEVICE_TYPE_DEFAULT, CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_GPU,
209 CL_DEVICE_TYPE_ACCELERATOR, CL_DEVICE_TYPE_CUSTOM, CL_DEVICE_TYPE_ALL };
211 const size_t devtype_count = ARRAY_SIZE(devtype);
212 /* number of actual device types, without ALL */
213 const size_t actual_devtype_count = ARRAY_SIZE(devtype) - 1;
215 static const char* device_type_str[] = { unk, "Default", "CPU", "GPU", "Accelerator", "Custom", "All" };
216 static const char* device_type_raw_str[] = { unk,
217 "CL_DEVICE_TYPE_DEFAULT", "CL_DEVICE_TYPE_CPU", "CL_DEVICE_TYPE_GPU",
218 "CL_DEVICE_TYPE_ACCELERATOR", "CL_DEVICE_TYPE_CUSTOM", "CL_DEVICE_TYPE_ALL"
221 static const char* partition_type_str[] = {
222 none, "equally", "by counts", "by affinity domain", "by names (Intel)"
224 static const char* partition_type_raw_str[] = {
226 "CL_DEVICE_PARTITION_EQUALLY_EXT",
227 "CL_DEVICE_PARTITION_BY_COUNTS_EXT",
228 "CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT",
229 "CL_DEVICE_PARTITION_BY_NAMES_INTEL_EXT"
232 static const char* atomic_cap_str[] = {
233 "relaxed", "acquire/release", "sequentially-consistent",
234 "work-item scope", "work-group scope", "device scope", "all-devices scope"
236 static const char* atomic_cap_raw_str[] = {
237 "CL_DEVICE_ATOMIC_ORDER_RELAXED",
238 "CL_DEVICE_ATOMIC_ORDER_ACQ_REL",
239 "CL_DEVICE_ATOMIC_ORDER_SEQ_CST",
240 "CL_DEVICE_ATOMIC_SCOPE_WORK_ITEM",
241 "CL_DEVICE_ATOMIC_SCOPE_WORK_GROUP",
242 "CL_DEVICE_ATOMIC_SCOPE_DEVICE",
243 "CL_DEVICE_ATOMIC_SCOPE_ALL_DEVICES"
245 const size_t atomic_cap_count = ARRAY_SIZE(atomic_cap_str);
247 static const char *device_enqueue_cap_str[] = {
248 "supported", "replaceable default queue"
251 static const char *device_enqueue_cap_raw_str[] = {
252 "CL_DEVICE_QUEUE_SUPPORTED",
253 "CL_DEVICE_QUEUE_REPLACEABLE_DEFAULT"
255 const size_t device_enqueue_cap_count = ARRAY_SIZE(atomic_cap_str);
257 static const char *command_buffer_str[] = {
258 "kernel printf", "device side enqueue", "simultaneous use", "out of order",
261 static const char *command_buffer_raw_str[] = {
262 "CL_COMMAND_BUFFER_CAPABILITY_KERNEL_PRINTF_KHR",
263 "CL_COMMAND_BUFFER_CAPABILITY_DEVICE_SIDE_ENQUEUE_KHR",
264 "CL_COMMAND_BUFFER_CAPABILITY_SIMULTANEOUS_USE_KHR",
265 "CL_COMMAND_BUFFER_CAPABILITY_OUT_OF_ORDER_KHR",
268 const size_t command_buffer_count = ARRAY_SIZE(command_buffer_str);
270 static const char *mutable_dispatch_str[] = {
278 static const char *mutable_dispatch_raw_str[] = {
279 "CL_MUTABLE_DISPATCH_GLOBAL_OFFSET_KHR",
280 "CL_MUTABLE_DISPATCH_GLOBAL_SIZE_KHR",
281 "CL_MUTABLE_DISPATCH_LOCAL_SIZE_KHR",
282 "CL_MUTABLE_DISPATCH_ARGUMENTS_KHR",
283 "CL_MUTABLE_DISPATCH_EXEC_INFO_KHR",
286 const size_t mutable_dispatch_count = ARRAY_SIZE(mutable_dispatch_str);
288 static const char numa[] = "NUMA";
289 static const char l1cache[] = "L1 cache";
290 static const char l2cache[] = "L2 cache";
291 static const char l3cache[] = "L3 cache";
292 static const char l4cache[] = "L4 cache";
294 static const char* affinity_domain_str[] = {
295 numa, l4cache, l3cache, l2cache, l1cache, "next partitionable"
298 static const char* affinity_domain_ext_str[] = {
299 numa, l4cache, l3cache, l2cache, l1cache, "next fissionable"
302 static const char* affinity_domain_raw_str[] = {
303 "CL_DEVICE_AFFINITY_DOMAIN_NUMA",
304 "CL_DEVICE_AFFINITY_DOMAIN_L4_CACHE",
305 "CL_DEVICE_AFFINITY_DOMAIN_L3_CACHE",
306 "CL_DEVICE_AFFINITY_DOMAIN_L2_CACHE",
307 "CL_DEVICE_AFFINITY_DOMAIN_L1_CACHE",
308 "CL_DEVICE_AFFINITY_DOMAIN_NEXT_PARTITIONABLE"
311 static const char* affinity_domain_raw_ext_str[] = {
312 "CL_AFFINITY_DOMAIN_NUMA_EXT",
313 "CL_AFFINITY_DOMAIN_L4_CACHE_EXT",
314 "CL_AFFINITY_DOMAIN_L3_CACHE_EXT",
315 "CL_AFFINITY_DOMAIN_L2_CACHE_EXT",
316 "CL_AFFINITY_DOMAIN_L1_CACHE_EXT",
317 "CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT"
320 const size_t affinity_domain_count = ARRAY_SIZE(affinity_domain_str);
322 static const char *terminate_capability_str[] = {
326 static const char *terminate_capability_raw_str[] = {
327 "CL_DEVICE_TERMINATE_CAPABILITY_CONTEXT_KHR"
330 const size_t terminate_capability_count = ARRAY_SIZE(terminate_capability_str);
332 static const char *terminate_capability_arm_str[] = {
333 "Controlled Success",
334 "Controlled Failurure",
338 static const char * terminate_capability_arm_raw_str[] = {
339 "CL_DEVICE_CONTROLLED_TERMINATION_SUCCESS_ARM",
340 "CL_DEVICE_CONTROLLED_TERMINATION_FAILURE_ARM",
341 "CL_DEVICE_CONTROLLED_TERMINATION_QUERY_ARM"
344 const size_t terminate_capability_arm_count = ARRAY_SIZE(terminate_capability_arm_str);
346 static const char* fp_conf_str[] = {
347 "Denormals", "Infinity and NANs", "Round to nearest", "Round to zero",
348 "Round to infinity", "IEEE754-2008 fused multiply-add",
349 "Support is emulated in software",
350 "Correctly-rounded divide and sqrt operations"
353 static const char* fp_conf_raw_str[] = {
356 "CL_FP_ROUND_TO_NEAREST",
357 "CL_FP_ROUND_TO_ZERO",
358 "CL_FP_ROUND_TO_INF",
361 "CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT"
364 const size_t fp_conf_count = ARRAY_SIZE(fp_conf_str);
366 static const char* svm_cap_str[] = {
367 "Coarse-grained buffer sharing",
368 "Fine-grained buffer sharing",
369 "Fine-grained system sharing",
373 static const char* svm_cap_raw_str[] = {
374 "CL_DEVICE_SVM_COARSE_GRAIN_BUFFER",
375 "CL_DEVICE_SVM_FINE_GRAIN_BUFFER",
376 "CL_DEVICE_SVM_FINE_GRAIN_SYSTEM",
377 "CL_DEVICE_SVM_ATOMICS",
380 const size_t svm_cap_count = ARRAY_SIZE(svm_cap_str);
382 static const char * intel_usm_cap_str[] = {
385 "USM concurrent access",
386 "USM concurrent atomic access"
389 static const char * intel_usm_cap_raw_str[] = {
390 "CL_UNIFIED_SHARED_MEMORY_ACCESS_INTEL",
391 "CL_UNIFIED_SHARED_MEMORY_ATOMIC_ACCESS_INTEL",
392 "CL_UNIFIED_SHARED_MEMORY_CONCURRENT_ACCESS_INTEL",
393 "CL_UNIFIED_SHARED_MEMORY_CONCURRENT_ATOMIC_ACCESS_INTEL",
396 const size_t intel_usm_cap_count = ARRAY_SIZE(intel_usm_cap_str);
398 static const char* arm_scheduling_controls_str[] = {
400 "Work-group batch size",
401 "Work-group batch size modifier",
403 "Register allocation",
405 "Compute unit batch queue size",
408 static const char* arm_scheduling_controls_raw_str[] = {
409 "CL_DEVICE_SCHEDULING_KERNEL_BATCHING_ARM",
410 "CL_DEVICE_SCHEDULING_WORKGROUP_BATCH_SIZE_ARM",
411 "CL_DEVICE_SCHEDULING_WORKGROUP_BATCH_SIZE_MODIFIER_ARM",
412 "CL_DEVICE_SCHEDULING_DEFERRED_FLUSH_ARM",
413 "CL_DEVICE_SCHEDULING_REGISTER_ALLOCATION_ARM",
414 "CL_DEVICE_SCHEDULING_WARP_THROTTLING_ARM",
415 "CL_DEVICE_SCHEDULING_COMPUTE_UNIT_BATCH_QUEUE_SIZE_ARM",
418 const size_t arm_scheduling_controls_count = ARRAY_SIZE(arm_scheduling_controls_str);
420 static const char* ext_mem_handle_str[] = {
431 static const char* ext_mem_handle_raw_str[] = {
432 "CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_FD_KHR",
433 "CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_WIN32_KHR",
434 "CL_EXTERNAL_MEMORY_HANDLE_OPAQUE_WIN32_KMT_KHR",
435 "CL_EXTERNAL_MEMORY_HANDLE_D3D11_TEXTURE_KHR",
436 "CL_EXTERNAL_MEMORY_HANDLE_D3D11_TEXTURE_KMT_KHR",
437 "CL_EXTERNAL_MEMORY_HANDLE_D3D12_HEAP_KHR",
438 "CL_EXTERNAL_MEMORY_HANDLE_D3D12_RESOURCE_KHR",
439 "CL_EXTERNAL_MEMORY_HANDLE_DMA_BUF_KHR",
442 const size_t ext_mem_handle_count = ARRAY_SIZE(ext_mem_handle_str);
443 const size_t ext_mem_handle_offset = 0x2060;
445 static const char* semaphore_type_str[] = {
448 static const char* semaphore_type_raw_str[] = {
449 "CL_SEMAPHORE_TYPE_BINARY_KHR"
451 const size_t semaphore_type_count = ARRAY_SIZE(semaphore_type_str);
452 const size_t semaphore_type_offset = 1;
454 static const char* semaphore_handle_str[] = {
461 static const char* semaphore_handle_raw_str[] = {
462 "CL_SEMAPHORE_HANDLE_OPAQUE_FD_KHR",
463 "CL_SEMAPHORE_HANDLE_OPAQUE_WIN32_KHR",
464 "CL_SEMAPHORE_HANDLE_OPAQUE_WIN32_KMT_KHR",
465 "CL_SEMAPHORE_HANDLE_SYNC_FD_KHR",
466 "CL_SEMAPHORE_HANDLE_D3D12_FENCE_KHR",
468 const size_t semaphore_handle_count = ARRAY_SIZE(semaphore_handle_str);
469 const size_t semaphore_handle_offset = 0x2055;
471 /* SI suffixes for memory sizes. Note that in OpenCL most of them are
472 * passed via a cl_ulong, which at most can mode 16 EiB, but hey,
473 * let's be forward-thinking ;-)
475 static const char* memsfx[] = {
476 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
479 const size_t memsfx_end = ARRAY_SIZE(memsfx) + 1;
481 static const char* lmem_type_str[] = { none, "Local", "Global" };
482 static const char* lmem_type_raw_str[] = { none_raw, "CL_LOCAL", "CL_GLOBAL" };
483 static const char* cache_type_str[] = { none, "Read-Only", "Read/Write" };
484 static const char* cache_type_raw_str[] = { none_raw, "CL_READ_ONLY_CACHE", "CL_READ_WRITE_CACHE" };
486 static const char* queue_prop_str[] = { "Out-of-order execution", "Profiling" };
487 static const char* queue_prop_raw_str[] = {
488 "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE",
489 "CL_QUEUE_PROFILING_ENABLE"
492 const size_t queue_prop_count = ARRAY_SIZE(queue_prop_str);
494 static const char* intel_queue_cap_str[] = {
495 "create single-queue events",
496 "create cross-queue events",
497 "single-queue wait list",
498 "cross-queue wait list",
504 "transfer buffer rect",
510 "transfer buffer to image",
511 "transfer image to buffer",
524 "no sync operations",
527 static const char* intel_queue_cap_raw_str[] = {
528 "CL_QUEUE_CAPABILITY_CREATE_SINGLE_QUEUE_EVENTS_INTEL",
529 "CL_QUEUE_CAPABILITY_CREATE_CROSS_QUEUE_EVENTS_INTEL",
530 "CL_QUEUE_CAPABILITY_SINGLE_QUEUE_EVENT_WAIT_LIST_INTEL",
531 "CL_QUEUE_CAPABILITY_CROSS_QUEUE_EVENT_WAIT_LIST_INTEL",
532 "CL_QUEUE_CAPABILITY_UNKNOWN_4",
533 "CL_QUEUE_CAPABILITY_UNKNOWN_5",
534 "CL_QUEUE_CAPABILITY_UNKNOWN_6",
535 "CL_QUEUE_CAPABILITY_UNKNOWN_7",
536 "CL_QUEUE_CAPABILITY_TRANSFER_BUFFER_INTEL",
537 "CL_QUEUE_CAPABILITY_TRANSFER_BUFFER_RECT_INTEL",
538 "CL_QUEUE_CAPABILITY_MAP_BUFFER_INTEL",
539 "CL_QUEUE_CAPABILITY_FILL_BUFFER_INTEL",
540 "CL_QUEUE_CAPABILITY_TRANSFER_IMAGE_INTEL",
541 "CL_QUEUE_CAPABILITY_MAP_IMAGE_INTEL",
542 "CL_QUEUE_CAPABILITY_FILL_IMAGE_INTEL",
543 "CL_QUEUE_CAPABILITY_TRANSFER_BUFFER_IMAGE_INTEL",
544 "CL_QUEUE_CAPABILITY_TRANSFER_IMAGE_BUFFER_INTEL",
545 "CL_QUEUE_CAPABILITY_UNKNOWN_17",
546 "CL_QUEUE_CAPABILITY_UNKNOWN_18",
547 "CL_QUEUE_CAPABILITY_UNKNOWN_19",
548 "CL_QUEUE_CAPABILITY_UNKNOWN_20",
549 "CL_QUEUE_CAPABILITY_UNKNOWN_21",
550 "CL_QUEUE_CAPABILITY_UNKNOWN_22",
551 "CL_QUEUE_CAPABILITY_UNKNOWN_23",
552 "CL_QUEUE_CAPABILITY_MARKER_INTEL",
553 "CL_QUEUE_CAPABILITY_BARRIER_INTEL",
554 "CL_QUEUE_CAPABILITY_KERNEL_INTEL",
555 "CL_QUEUE_CAPABILITY_UNKNOWN_27",
556 "CL_QUEUE_CAPABILITY_UNKNOWN_28",
557 "CL_QUEUE_NO_SYNC_OPERATIONS_INTEL",
560 const size_t intel_queue_cap_count = ARRAY_SIZE(intel_queue_cap_str);
562 static const char* execap_str[] = { "Run OpenCL kernels", "Run native kernels" };
563 static const char* execap_raw_str[] = {
565 "CL_EXEC_NATIVE_KERNEL"
568 const size_t execap_count = ARRAY_SIZE(execap_str);
570 static const char* intel_features_str[] = { "DP4A", "DPAS" };
571 static const char* intel_features_raw_str[] = { "CL_DEVICE_FEATURE_FLAG_DP4A_INTEL", "CL_DEVICE_FEATURE_FLAG_DPAS_INTEL" };
573 const size_t intel_features_count = ARRAY_SIZE(intel_features_str);
575 static const char* sources[] = {
576 "#define GWO(type) global type* restrict\n",
577 "#define GRO(type) global const type* restrict\n",
578 "#define BODY int i = get_global_id(0); out[i] = in1[i] + in2[i]\n",
579 "#define _KRN(T, N) kernel void sum##N(GWO(T##N) out, GRO(T##N) in1, GRO(T##N) in2) { BODY; }\n",
580 "#define KRN(N) _KRN(float, N)\n",
581 "KRN()\n/* KRN(2)\nKRN(4)\nKRN(8)\nKRN(16) */\n",
584 const char *num_devs_header(const struct opt_out *output, cl_bool these_are_offline)
586 return output->mode == CLINFO_HUMAN ?
587 (these_are_offline ? "Number of offine devices (AMD)" : "Number of devices") :
588 (these_are_offline ? "#OFFDEVICES" : "#DEVICES");
591 const char *not_specified(const struct opt_out *output)
593 return output->mode == CLINFO_HUMAN ?
597 const char *no_plat(const struct opt_out *output)
599 return output->mode == CLINFO_HUMAN ?
601 "CL_INVALID_PLATFORM";
604 const char *invalid_dev_type(const struct opt_out *output)
606 return output->mode == CLINFO_HUMAN ?
607 "Invalid device type for platform" :
608 "CL_INVALID_DEVICE_TYPE";
611 const char *invalid_dev_value(const struct opt_out *output)
613 return output->mode == CLINFO_HUMAN ?
614 "Invalid device type value for platform" :
618 const char *no_dev_found(const struct opt_out *output)
620 return output->mode == CLINFO_HUMAN ?
621 "No devices found in platform" :
622 "CL_DEVICE_NOT_FOUND";
625 const char *no_dev_avail(const struct opt_out *output)
627 return output->mode == CLINFO_HUMAN ?
628 "No devices available in platform" :
629 "CL_DEVICE_NOT_AVAILABLE";
632 /* OpenCL context interop names */
634 typedef struct cl_interop_name {
637 /* 5 because that's the largest we know of,
638 * 2 because it's HUMAN, RAW */
639 const char *value[5][2];
642 static const cl_interop_name cl_interop_names[] = {
643 { /* cl_khr_gl_sharing */
645 CL_CGL_SHAREGROUP_KHR,
647 { "GL", "CL_GL_CONTEXT_KHR" },
648 { "EGL", "CL_EGL_DISPALY_KHR" },
649 { "GLX", "CL_GLX_DISPLAY_KHR" },
650 { "WGL", "CL_WGL_HDC_KHR" },
651 { "CGL", "CL_CGL_SHAREGROUP_KHR" }
654 { /* cl_khr_dx9_media_sharing */
655 CL_CONTEXT_ADAPTER_D3D9_KHR,
656 CL_CONTEXT_ADAPTER_DXVA_KHR,
658 { "D3D9 (KHR)", "CL_CONTEXT_ADAPTER_D3D9_KHR" },
659 { "D3D9Ex (KHR)", "CL_CONTEXT_ADAPTER_D3D9EX_KHR" },
660 { "DXVA (KHR)", "CL_CONTEXT_ADAPTER_DXVA_KHR" }
663 { /* cl_khr_d3d10_sharing */
664 CL_CONTEXT_D3D10_DEVICE_KHR,
665 CL_CONTEXT_D3D10_DEVICE_KHR,
667 { "D3D10", "CL_CONTEXT_D3D10_DEVICE_KHR" }
670 { /* cl_khr_d3d11_sharing */
671 CL_CONTEXT_D3D11_DEVICE_KHR,
672 CL_CONTEXT_D3D11_DEVICE_KHR,
674 { "D3D11", "CL_CONTEXT_D3D11_DEVICE_KHR" }
677 /* cl_intel_dx9_media_sharing is split in two because the allowed values are not consecutive */
678 { /* cl_intel_dx9_media_sharing part 1 */
679 CL_CONTEXT_D3D9_DEVICE_INTEL,
680 CL_CONTEXT_D3D9_DEVICE_INTEL,
682 { "D3D9 (INTEL)", "CL_CONTEXT_D3D9_DEVICE_INTEL" }
685 { /* cl_intel_dx9_media_sharing part 2 */
686 CL_CONTEXT_D3D9EX_DEVICE_INTEL,
687 CL_CONTEXT_DXVA_DEVICE_INTEL,
689 { "D3D9Ex (INTEL)", "CL_CONTEXT_D3D9EX_DEVICE_INTEL" },
690 { "DXVA (INTEL)", "CL_CONTEXT_DXVA_DEVICE_INTEL" }
693 { /* cl_intel_va_api_media_sharing */
694 CL_CONTEXT_VA_API_DISPLAY_INTEL,
695 CL_CONTEXT_VA_API_DISPLAY_INTEL,
697 { "VA-API", "CL_CONTEXT_VA_API_DISPLAY_INTEL" }
702 const size_t num_known_interops = ARRAY_SIZE(cl_interop_names);
706 #define I0_STR "%-48s "
707 #define I1_STR " %-46s "
708 #define I2_STR " %-44s "
710 /* New line and a full padding */
711 static const char full_padding[] = "\n"
712 INDENT INDENT INDENT INDENT INDENT
713 INDENT INDENT INDENT INDENT INDENT
714 INDENT INDENT INDENT INDENT INDENT
715 INDENT INDENT INDENT INDENT INDENT
716 INDENT INDENT INDENT INDENT INDENT;
718 static const char empty_str[] = "";
719 static const char spc_str[] = " ";
720 static const char times_str[] = "x";
721 static const char comma_str[] = ", ";
722 static const char vbar_str[] = " | ";
724 const char *cur_sfx = empty_str;
726 /* parse a CL_DEVICE_VERSION or CL_PLATFORM_VERSION info to determine the OpenCL version.
727 * Returns an unsigned integer in the form major*10 + minor
730 getOpenCLVersion(const char *version)
734 const char *from = version;
736 parse = strtol(from, &next, 10);
740 // skip the dot TODO should we actually check for the dot?
742 parse = strtol(from, &next, 10);
749 #define SPLIT_CL_VERSION(ver) ((ver)/10), ((ver)%10)
751 /* OpenCL 3.0 introduced “proper” versioning, in the form of a major.minor.patch struct
752 * packed into a single cl_uint (type aliased to cl_version)
754 struct unpacked_cl_version {
760 struct unpacked_cl_version unpack_cl_version(cl_uint version)
762 struct unpacked_cl_version ret;
763 ret.major = (version >> 22);
764 ret.minor = (version >> 12) & ((1<<10)-1);
765 ret.patch = version & ((1<<12)-1);
769 void strbuf_version(const char *what, struct _strbuf *str, const char *before, cl_uint version, const char *after)
771 struct unpacked_cl_version u = unpack_cl_version(version);
772 strbuf_append(what, str, "%s%" PRIu32 ".%" PRIu32 ".%" PRIu32 "%s",
773 before, u.major, u.minor, u.patch, after);
776 void set_common_separator(const struct opt_out *output)
778 set_separator(output->json || output->mode == CLINFO_HUMAN ? comma_str : vbar_str);
781 void strbuf_name_version(const char *what, struct _strbuf *str, const cl_name_version *ext, size_t num_exts,
782 const struct opt_out *output)
784 realloc_strbuf(str, num_exts*(CL_NAME_VERSION_MAX_NAME_SIZE + 256), "extension versions");
785 set_separator(output->mode == CLINFO_HUMAN ? full_padding : output->json ? comma_str : spc_str);
787 strbuf_append_str(what, str, "{");
789 for (size_t i = 0; i < num_exts; ++i) {
790 const cl_name_version *e = ext + i;
791 if (i > 0) strbuf_append_str(what, str, sep);
792 if (output->json || output->mode == CLINFO_HUMAN) {
793 struct unpacked_cl_version u = unpack_cl_version(e->version);
794 strbuf_append(what, str,
796 "\"%s\" : { \"raw\" : %" PRIu32 ", \"version\" : \"%d.%d.%d\" }" :
797 "%-65s%#8" PRIx32 " (%d.%d.%d)",
798 e->name, e->version, u.major, u.minor, u.patch);
800 strbuf_append(what, str, "%s:%#" PRIx32, e->name, e->version);
804 strbuf_append_str(what, str, " }");
808 void strbuf_named_uint(const char *what, struct _strbuf *str, const cl_uint *ext, size_t num_exts, const struct opt_out *output,
809 const char* const* human_str, const char* const* raw_str, const size_t count, const size_t offset)
811 const char *quote = output->json ? "\"" : "";
812 const char * const * name_str = output->mode == CLINFO_HUMAN ? human_str : raw_str;
813 set_common_separator(output);
815 strbuf_append_str_len(what, str, "[ ", 2);
817 for (size_t cursor = 0; cursor < num_exts; ++cursor) {
818 /* add separator for values past the first */
819 if (cursor > 0) strbuf_append_str(what, str, sep);
821 cl_uint val = ext[cursor];
822 cl_bool known = (val >= offset && val < offset + count);
824 strbuf_append(what, str, "%s%s%s", quote, name_str[val - offset], quote);
826 strbuf_append(what, str, "%s%#" PRIx32 "%s", quote, val, quote);
829 strbuf_append_str_len(what, str, " ]", 2);
832 void strbuf_ext_mem(const char *what, struct _strbuf *str, const cl_external_memory_handle_type_khr *ext, size_t num_exts,
833 const struct opt_out *output)
835 strbuf_named_uint(what, str, ext, num_exts, output,
836 ext_mem_handle_str, ext_mem_handle_raw_str, ext_mem_handle_count, ext_mem_handle_offset);
839 void strbuf_semaphore_type(const char *what, struct _strbuf *str, const cl_semaphore_type_khr *ext, size_t num_exts,
840 const struct opt_out *output)
842 strbuf_named_uint(what, str, ext, num_exts, output,
843 semaphore_type_str, semaphore_type_raw_str, semaphore_type_count, semaphore_type_offset);
846 void strbuf_ext_semaphore_handle(const char *what, struct _strbuf *str, const cl_external_semaphore_handle_type_khr *ext, size_t num_exts,
847 const struct opt_out *output)
849 strbuf_named_uint(what, str, ext, num_exts, output,
850 semaphore_handle_str, semaphore_handle_raw_str, semaphore_handle_count, semaphore_handle_offset);
854 /* print strbuf, prefixed by pname, skipping leading whitespace if skip is nonzero,
855 * affixing cur_sfx */
857 void show_strbuf(const struct _strbuf *strbuf, const char *pname, int skip, cl_int err)
859 printf("%s" I1_STR "%s%s\n",
861 (skip ? skip_leading_ws(strbuf->buf) : strbuf->buf),
862 err ? empty_str : cur_sfx);
865 /* print a JSON string version of NULL-terminated string str, escaping \ and " and wrapping it all in "
868 void json_stringify(const char *str)
872 if (*str == '\\' || *str == '"')
880 /* print JSON version of strbuf, prefixed by pname, skipping leading whitespace if skip is nonzero,
881 * quoting and escaping as string if is_string is nonzero
884 void json_strbuf(const struct _strbuf *strbuf, const char *pname, cl_uint n, cl_bool is_string)
886 printf("%s\"%s\" : ", (n > 0 ? comma_str : spc_str), pname);
888 json_stringify(strbuf->buf);
890 fputs(strbuf->buf, stdout);
894 platform_info_str(struct platform_info_ret *ret,
895 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
896 const struct opt_out* UNUSED(output))
898 GET_STRING_LOC(ret, loc, clGetPlatformInfo, loc->plat, loc->param.plat);
899 ret->needs_escaping = CL_TRUE;
903 platform_info_ulong(struct platform_info_ret *ret,
904 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
905 const struct opt_out *output)
907 ret->err = REPORT_ERROR_LOC(ret,
908 clGetPlatformInfo(loc->plat, loc->param.plat, sizeof(ret->value.u64), &ret->value.u64, NULL),
910 CHECK_SIZE(ret, loc, ret->value.u64, clGetPlatformInfo, loc->plat, loc->param.plat);
911 strbuf_append(loc->pname, &ret->str, "%" PRIu64, ret->value.u64);
915 platform_info_sz(struct platform_info_ret *ret,
916 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
917 const struct opt_out *output)
919 ret->err = REPORT_ERROR_LOC(ret,
920 clGetPlatformInfo(loc->plat, loc->param.plat, sizeof(ret->value.s), &ret->value.s, NULL),
922 CHECK_SIZE(ret, loc, ret->value.s, clGetPlatformInfo, loc->plat, loc->param.plat);
923 strbuf_append(loc->pname, &ret->str, "%" PRIuS, ret->value.s);
927 platform_info_version(struct platform_info_ret *ret,
928 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
929 const struct opt_out *output)
931 ret->err = REPORT_ERROR_LOC(ret,
932 clGetPlatformInfo(loc->plat, loc->param.plat, sizeof(ret->value.u32), &ret->value.u32, NULL),
934 CHECK_SIZE(ret, loc, ret->value.u32, clGetPlatformInfo, loc->plat, loc->param.plat);
936 strbuf_append(loc->pname, &ret->str,
937 output->json ? "{ \"raw\" : %" PRIu32 ", \"version\" :" : "%#" PRIx32,
939 if (output->json || output->mode == CLINFO_HUMAN) {
940 strbuf_version(loc->pname, &ret->str,
941 output->json ? " \"" : " (",
943 output->json ? "\" }" : ")");
949 platform_info_ext_version(struct platform_info_ret *ret,
950 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
951 const struct opt_out *output)
953 cl_name_version *ext = NULL;
955 ret->err = REPORT_ERROR_LOC(ret,
956 clGetPlatformInfo(loc->plat, loc->param.plat, 0, NULL, &nusz),
959 REALLOC(ext, nusz, loc->sname);
960 ret->err = REPORT_ERROR_LOC(ret,
961 clGetPlatformInfo(loc->plat, loc->param.plat, nusz, ext, NULL),
965 size_t num_exts = nusz / sizeof(*ext);
966 strbuf_name_version(loc->pname, &ret->str, ext, num_exts, output);
972 platform_info_ext_mem(struct platform_info_ret *ret,
973 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
974 const struct opt_out *output)
976 cl_external_memory_handle_type_khr *ext = NULL;
978 ret->err = REPORT_ERROR_LOC(ret,
979 clGetPlatformInfo(loc->plat, loc->param.plat, 0, NULL, &nusz),
982 REALLOC(ext, nusz, loc->sname);
983 ret->err = REPORT_ERROR_LOC(ret,
984 clGetPlatformInfo(loc->plat, loc->param.plat, nusz, ext, NULL),
988 size_t num_exts = nusz / sizeof(*ext);
989 strbuf_ext_mem(loc->pname, &ret->str, ext, num_exts, output);
995 platform_info_semaphore_types(struct platform_info_ret *ret,
996 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
997 const struct opt_out *output)
999 cl_semaphore_type_khr *ext = NULL;
1001 ret->err = REPORT_ERROR_LOC(ret,
1002 clGetPlatformInfo(loc->plat, loc->param.plat, 0, NULL, &nusz),
1003 loc, "get %s size");
1005 REALLOC(ext, nusz, loc->sname);
1006 ret->err = REPORT_ERROR_LOC(ret,
1007 clGetPlatformInfo(loc->plat, loc->param.plat, nusz, ext, NULL),
1011 size_t num_exts = nusz / sizeof(*ext);
1012 strbuf_semaphore_type(loc->pname, &ret->str, ext, num_exts, output);
1018 platform_info_ext_semaphore_handles(struct platform_info_ret *ret,
1019 const struct info_loc *loc, const struct platform_info_checks* UNUSED(chk),
1020 const struct opt_out *output)
1022 cl_external_semaphore_handle_type_khr *ext = NULL;
1024 ret->err = REPORT_ERROR_LOC(ret,
1025 clGetPlatformInfo(loc->plat, loc->param.plat, 0, NULL, &nusz),
1026 loc, "get %s size");
1028 REALLOC(ext, nusz, loc->sname);
1029 ret->err = REPORT_ERROR_LOC(ret,
1030 clGetPlatformInfo(loc->plat, loc->param.plat, nusz, ext, NULL),
1034 size_t num_exts = nusz / sizeof(*ext);
1035 strbuf_ext_semaphore_handle(loc->pname, &ret->str, ext, num_exts, output);
1040 struct platform_info_traits {
1041 cl_platform_info param; // CL_PLATFORM_*
1042 const char *sname; // "CL_PLATFORM_*"
1043 const char *pname; // "Platform *"
1044 const char *sfx; // suffix for the output in non-raw mode
1045 /* pointer to function that retrieves the parameter */
1046 void (*show_func)(struct platform_info_ret *,
1047 const struct info_loc *, const struct platform_info_checks *,
1048 const struct opt_out *);
1049 /* pointer to function that checks if the parameter should be retrieved */
1050 cl_bool (*check_func)(const struct platform_info_checks *);
1053 cl_bool khr_icd_p(const struct platform_info_checks *chk)
1055 return chk->has_khr_icd;
1058 cl_bool plat_is_12(const struct platform_info_checks *chk)
1060 return !(chk->plat_version < 12);
1063 cl_bool plat_is_20(const struct platform_info_checks *chk)
1065 return !(chk->plat_version < 20);
1068 cl_bool plat_is_21(const struct platform_info_checks *chk)
1070 return !(chk->plat_version < 21);
1073 cl_bool plat_is_30(const struct platform_info_checks *chk)
1075 return !(chk->plat_version < 30);
1078 cl_bool plat_has_amd_object_metadata(const struct platform_info_checks *chk)
1080 return chk->has_amd_object_metadata;
1083 cl_bool plat_has_ext_ver(const struct platform_info_checks *chk)
1085 return plat_is_30(chk) || chk->has_extended_versioning;
1088 cl_bool plat_has_ext_mem(const struct platform_info_checks *chk)
1090 return chk->has_external_memory;
1093 cl_bool plat_has_semaphore(const struct platform_info_checks *chk)
1095 return chk->has_semaphore;
1098 cl_bool plat_has_external_semaphore(const struct platform_info_checks *chk)
1100 return chk->has_external_semaphore;
1103 #define PINFO_COND(symbol, name, sfx, typ, funcptr) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, &funcptr }
1104 #define PINFO(symbol, name, sfx, typ) { symbol, #symbol, "Platform " name, sfx, &platform_info_##typ, NULL }
1105 struct platform_info_traits pinfo_traits[] = {
1106 PINFO(CL_PLATFORM_NAME, "Name", NULL, str),
1107 PINFO(CL_PLATFORM_VENDOR, "Vendor", NULL, str),
1108 PINFO(CL_PLATFORM_VERSION, "Version", NULL, str),
1109 PINFO(CL_PLATFORM_PROFILE, "Profile", NULL, str),
1110 PINFO(CL_PLATFORM_EXTENSIONS, "Extensions", NULL, str),
1111 PINFO_COND(CL_PLATFORM_EXTENSIONS_WITH_VERSION, "Extensions with Version", NULL, ext_version, plat_has_ext_ver),
1112 PINFO_COND(CL_PLATFORM_NUMERIC_VERSION, "Numeric Version", NULL, version, plat_has_ext_ver),
1113 PINFO_COND(CL_PLATFORM_ICD_SUFFIX_KHR, "Extensions function suffix", NULL, str, khr_icd_p),
1114 PINFO_COND(CL_PLATFORM_MAX_KEYS_AMD, "Max metadata object keys (AMD)", NULL, sz, plat_has_amd_object_metadata),
1115 PINFO_COND(CL_PLATFORM_HOST_TIMER_RESOLUTION, "Host timer resolution", "ns", ulong, plat_is_21),
1116 PINFO_COND(CL_PLATFORM_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR, "External memory handle types", NULL, ext_mem, plat_has_ext_mem),
1117 PINFO_COND(CL_PLATFORM_SEMAPHORE_TYPES_KHR, "Semaphore types", NULL, semaphore_types, plat_has_semaphore),
1118 PINFO_COND(CL_PLATFORM_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR, "External semaphore import types", NULL, ext_semaphore_handles, plat_has_external_semaphore),
1119 PINFO_COND(CL_PLATFORM_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR, "External semaphore export types", NULL, ext_semaphore_handles, plat_has_external_semaphore),
1123 /* Collect (and optionally show) information on a specific platform,
1124 * initializing relevant arrays and optionally showing the collected
1128 gatherPlatformInfo(struct platform_list *plist, cl_uint p, const struct opt_out *output)
1131 cl_uint n = 0; /* number of platform properties shown, for JSON */
1133 struct platform_data *pdata = plist->pdata + p;
1134 struct platform_info_checks *pinfo_checks = plist->platform_checks + p;
1135 struct platform_info_ret ret;
1136 struct info_loc loc;
1138 pinfo_checks->plat_version = 10;
1140 INIT_RET(ret, "platform");
1141 reset_loc(&loc, __func__);
1142 loc.plat = plist->platform[p];
1144 for (loc.line = 0; loc.line < ARRAY_SIZE(pinfo_traits); ++loc.line) {
1145 const struct platform_info_traits *traits = pinfo_traits + loc.line;
1148 /* checked is true if there was no condition to check for, or if the
1149 * condition was satisfied
1151 int checked = !(traits->check_func && !traits->check_func(pinfo_checks));
1153 if (output->cond == COND_PROP_CHECK && !checked)
1156 loc.sname = traits->sname;
1157 loc.pname = (output->mode == CLINFO_HUMAN ?
1158 traits->pname : traits->sname);
1159 loc.param.plat = traits->param;
1161 cur_sfx = (output->mode == CLINFO_HUMAN && traits->sfx) ? traits->sfx : empty_str;
1163 reset_strbuf(&ret.str);
1164 reset_strbuf(&ret.err_str);
1165 ret.needs_escaping = CL_FALSE;
1166 traits->show_func(&ret, &loc, pinfo_checks, output);
1168 /* The property is skipped if this was a conditional property,
1169 * unsatisfied, there was an error retrieving it and cond_prop_mode is not
1172 if (ret.err && !checked && output->cond != COND_PROP_SHOW)
1175 /* The property gets printed if we are not just listing,
1176 * or if the user requested a property and this one matches.
1177 * Otherwise, we're just gathering information */
1178 requested = (output->prop && strstr(loc.sname, output->prop) != NULL);
1179 if (output->detailed || requested) {
1181 json_strbuf(RET_BUF(ret), loc.pname, n++, ret.err || ret.needs_escaping);
1183 show_strbuf(RET_BUF(ret), loc.pname, CL_FALSE, ret.err);
1190 /* post-processing */
1192 switch (traits->param) {
1193 case CL_PLATFORM_NAME:
1194 /* Store name for future reference */
1195 len = strlen(ret.str.buf);
1196 ALLOC(pdata->pname, len+1, "platform name copy");
1197 /* memcpy instead of strncpy since we already have the len
1198 * and memcpy is possibly more optimized */
1199 memcpy(pdata->pname, ret.str.buf, len);
1200 pdata->pname[len] = '\0';
1202 case CL_PLATFORM_VERSION:
1203 /* compute numeric value for OpenCL version */
1204 pinfo_checks->plat_version = getOpenCLVersion(ret.str.buf + 7);
1206 case CL_PLATFORM_EXTENSIONS:
1207 pinfo_checks->has_khr_icd = !!strstr(ret.str.buf, "cl_khr_icd");
1208 pinfo_checks->has_amd_object_metadata = !!strstr(ret.str.buf, "cl_amd_object_metadata");
1209 pinfo_checks->has_external_memory = !!strstr(ret.str.buf, "cl_khr_external_memory");
1210 pinfo_checks->has_semaphore = !!strstr(ret.str.buf, "cl_khr_semaphore");
1211 pinfo_checks->has_external_semaphore = !!strstr(ret.str.buf, "cl_khr_external_semaphore");
1212 pdata->has_amd_offline = !!strstr(ret.str.buf, "cl_amd_offline_devices");
1214 case CL_PLATFORM_ICD_SUFFIX_KHR:
1215 /* Store ICD suffix for future reference */
1216 len = strlen(ret.str.buf);
1217 ALLOC(pdata->sname, len+1, "platform ICD suffix copy");
1218 /* memcpy instead of strncpy since we already have the len
1219 * and memcpy is possibly more optimized */
1220 memcpy(pdata->sname, ret.str.buf, len);
1221 pdata->sname[len] = '\0';
1229 if (pinfo_checks->plat_version > plist->max_plat_version)
1230 plist->max_plat_version = pinfo_checks->plat_version;
1232 /* if no CL_PLATFORM_ICD_SUFFIX_KHR, use P### as short/symbolic name */
1233 if (!pdata->sname) {
1234 #define SNAME_MAX 32
1235 ALLOC(pdata->sname, SNAME_MAX+1, "platform symbolic name");
1236 snprintf(pdata->sname, SNAME_MAX, "P%" PRIu32 "", p);
1239 len = strlen(pdata->sname);
1240 if (len > plist->max_sname_len)
1241 plist->max_sname_len = len;
1243 ret.err = clGetDeviceIDs(loc.plat, CL_DEVICE_TYPE_ALL, 0, NULL, &pdata->ndevs);
1244 if (ret.err == CL_DEVICE_NOT_FOUND)
1247 CHECK_ERROR(ret.err, "number of devices");
1248 plist->ndevs_total += pdata->ndevs;
1249 plist->dev_offset[p] = p ? plist->dev_offset[p-1] + (pdata-1)->ndevs : 0;
1250 plist_devs_reserve(plist, plist->ndevs_total);
1252 if (pdata->ndevs > 0) {
1253 ret.err = clGetDeviceIDs(loc.plat, CL_DEVICE_TYPE_ALL,
1255 plist->all_devs + plist->dev_offset[p], NULL);
1258 if (pdata->ndevs > plist->max_devs)
1259 plist->max_devs = pdata->ndevs;
1265 * Device properties/extensions used in traits checks, and relevant functions
1266 * TODO add version control for 3.0+ platforms
1269 struct device_info_checks {
1270 const struct platform_info_checks *pinfo_checks;
1271 cl_device_type devtype;
1272 cl_device_mem_cache_type cachetype;
1273 cl_device_local_mem_type lmemtype;
1274 cl_bool image_support;
1275 cl_bool compiler_available;
1276 cl_bool arm_register_alloc_support;
1277 cl_bool arm_warp_count_support;
1279 char has_double[24];
1283 char has_amd_svm[11];
1284 char has_arm_svm[29];
1285 char has_intel_usm[31];
1286 char has_external_memory[23];
1287 char has_semaphore[17];
1288 char has_external_semaphore[26];
1289 char has_arm_core_id[15];
1290 char has_arm_job_slots[26];
1291 char has_arm_scheduling_controls[27];
1292 char has_fission[22];
1293 char has_atomic_counters[26];
1294 char has_image2d_buffer[27];
1295 char has_il_program[18];
1296 char has_intel_queue_families[32];
1297 char has_intel_local_thread[30];
1298 char has_intel_AME[36];
1299 char has_intel_AVC_ME[43];
1300 char has_intel_planar_yuv[20];
1301 char has_intel_required_subgroup_size[32];
1302 char has_altera_dev_temp[29];
1304 char has_pci_bus_info[20];
1306 char has_qcom_ext_host_ptr[21];
1307 char has_simultaneous_sharing[30];
1308 char has_subgroup_named_barrier[30];
1309 char has_command_buffer[25];
1310 char has_mutable_dispatch[27];
1311 char has_terminate_context[25];
1312 char has_terminate_arm[37];
1313 char has_extended_versioning[27];
1314 char has_cxx_for_opencl[22];
1315 char has_device_uuid[19];
1316 cl_uint dev_version;
1317 cl_uint p2p_num_devs;
1320 #define DEFINE_EXT_CHECK(ext) cl_bool dev_has_##ext(const struct device_info_checks *chk) \
1322 return !!(chk->has_##ext[0]); \
1325 DEFINE_EXT_CHECK(half)
1326 DEFINE_EXT_CHECK(double)
1327 DEFINE_EXT_CHECK(nv)
1328 DEFINE_EXT_CHECK(amd)
1329 DEFINE_EXT_CHECK(amd_svm)
1330 DEFINE_EXT_CHECK(arm_svm)
1331 DEFINE_EXT_CHECK(intel_usm)
1332 DEFINE_EXT_CHECK(external_memory)
1333 DEFINE_EXT_CHECK(semaphore)
1334 DEFINE_EXT_CHECK(external_semaphore)
1335 DEFINE_EXT_CHECK(arm_core_id)
1336 DEFINE_EXT_CHECK(arm_job_slots)
1337 DEFINE_EXT_CHECK(arm_scheduling_controls)
1338 DEFINE_EXT_CHECK(fission)
1339 DEFINE_EXT_CHECK(atomic_counters)
1340 DEFINE_EXT_CHECK(il_program)
1341 DEFINE_EXT_CHECK(intel)
1342 DEFINE_EXT_CHECK(intel_queue_families)
1343 DEFINE_EXT_CHECK(intel_local_thread)
1344 DEFINE_EXT_CHECK(intel_AME)
1345 DEFINE_EXT_CHECK(intel_AVC_ME)
1346 DEFINE_EXT_CHECK(intel_planar_yuv)
1347 DEFINE_EXT_CHECK(intel_required_subgroup_size)
1348 DEFINE_EXT_CHECK(altera_dev_temp)
1349 DEFINE_EXT_CHECK(p2p)
1350 DEFINE_EXT_CHECK(pci_bus_info)
1351 DEFINE_EXT_CHECK(spir)
1352 DEFINE_EXT_CHECK(qcom_ext_host_ptr)
1353 DEFINE_EXT_CHECK(simultaneous_sharing)
1354 DEFINE_EXT_CHECK(subgroup_named_barrier)
1355 DEFINE_EXT_CHECK(command_buffer)
1356 DEFINE_EXT_CHECK(mutable_dispatch)
1357 DEFINE_EXT_CHECK(terminate_context)
1358 DEFINE_EXT_CHECK(terminate_arm)
1359 DEFINE_EXT_CHECK(extended_versioning)
1360 DEFINE_EXT_CHECK(cxx_for_opencl)
1361 DEFINE_EXT_CHECK(device_uuid)
1363 /* In the version checks we negate the opposite conditions
1364 * instead of double-negating the actual condition
1367 // device supports 1.1
1368 cl_bool dev_is_11(const struct device_info_checks *chk)
1370 return !(chk->dev_version < 11);
1374 // device supports 1.2
1375 cl_bool dev_is_12(const struct device_info_checks *chk)
1377 return !(chk->dev_version < 12);
1380 // device supports 2.0
1381 cl_bool dev_is_20(const struct device_info_checks *chk)
1383 return !(chk->dev_version < 20);
1386 // device supports 2.1
1387 cl_bool dev_is_21(const struct device_info_checks *chk)
1389 return !(chk->dev_version < 21);
1392 // device does not support 2.0
1393 cl_bool dev_not_20(const struct device_info_checks *chk)
1395 return !(chk->dev_version >= 20);
1398 // device supports 3.0
1399 cl_bool dev_is_30(const struct device_info_checks *chk)
1401 return !(chk->dev_version < 30);
1404 // device has extended versioning: 3.0 or has_extended_versioning
1405 cl_bool dev_has_ext_ver(const struct device_info_checks *chk)
1407 return dev_is_30(chk) || dev_has_extended_versioning(chk);
1410 cl_bool dev_is_gpu(const struct device_info_checks *chk)
1412 return !!(chk->devtype & CL_DEVICE_TYPE_GPU);
1415 cl_bool dev_is_gpu_amd(const struct device_info_checks *chk)
1417 return dev_is_gpu(chk) && dev_has_amd(chk);
1420 /* Device supports cl_amd_device_attribute_query v4 */
1421 cl_bool dev_has_amd_v4(const struct device_info_checks *chk)
1423 /* We don't actually have a criterion to check if the device
1424 * supports a specific version of an extension, so for the time
1425 * being rely on them being GPU devices with cl_amd_device_attribute_query
1426 * and the platform supporting OpenCL 2.0 or later
1427 * TODO FIXME tune criteria
1429 return dev_is_gpu(chk) && dev_has_amd(chk) && plat_is_20(chk->pinfo_checks);
1432 /* Device supports cl_intel_device_attribute_query and is a GPU */
1433 cl_bool dev_is_gpu_intel(const struct device_info_checks *chk)
1435 return dev_is_gpu(chk) && dev_has_intel(chk);
1438 /* Device supports cl_arm_core_id v2 */
1439 cl_bool dev_has_arm_core_id_v2(const struct device_info_checks *chk)
1441 /* We don't actually have a criterion to check if the device
1442 * supports a specific version of an extension, so for the time
1443 * being rely on them having cl_arm_core_id and the platform
1444 * supporting OpenCL 1.2 or later
1445 * TODO FIXME tune criteria
1447 return dev_has_arm_core_id(chk) && plat_is_12(chk->pinfo_checks);
1450 /* Device supports register allocation queries */
1451 cl_bool dev_has_arm_register_alloc(const struct device_info_checks *chk)
1453 return dev_has_arm_scheduling_controls(chk) && chk->arm_register_alloc_support;
1456 /* Device supports warp */
1457 cl_bool dev_has_arm_warp_count_support(const struct device_info_checks *chk)
1459 return dev_has_arm_scheduling_controls(chk) && chk->arm_warp_count_support;
1462 cl_bool dev_has_svm(const struct device_info_checks *chk)
1464 return dev_is_20(chk) || dev_has_amd_svm(chk);
1467 cl_bool dev_has_partition(const struct device_info_checks *chk)
1469 return dev_is_12(chk) || dev_has_fission(chk);
1472 cl_bool dev_has_cache(const struct device_info_checks *chk)
1474 return chk->cachetype != CL_NONE;
1477 cl_bool dev_has_lmem(const struct device_info_checks *chk)
1479 return chk->lmemtype != CL_NONE;
1482 cl_bool dev_has_il(const struct device_info_checks *chk)
1484 return dev_is_21(chk) || dev_has_il_program(chk);
1487 cl_bool dev_has_images(const struct device_info_checks *chk)
1489 return chk->image_support;
1492 cl_bool dev_has_images_12(const struct device_info_checks *chk)
1494 return dev_has_images(chk) && dev_is_12(chk);
1497 cl_bool dev_has_images_20(const struct device_info_checks *chk)
1499 return dev_has_images(chk) && dev_is_20(chk);
1502 cl_bool dev_has_image2d_buffer(const struct device_info_checks *chk)
1504 return dev_has_images_20(chk) || !!(chk->has_image2d_buffer[0]);
1507 cl_bool dev_has_compiler(const struct device_info_checks *chk)
1509 return chk->compiler_available;
1512 cl_bool dev_has_compiler_11(const struct device_info_checks *chk)
1514 return dev_is_11(chk) && dev_has_compiler(chk);
1517 cl_bool dev_has_p2p_devs(const struct device_info_checks *chk)
1519 return dev_has_p2p(chk) && chk->p2p_num_devs > 0;
1523 void identify_device_extensions(const char *extensions, struct device_info_checks *chk)
1525 #define _HAS_EXT(ext) (strstr(extensions, ext))
1526 #define CPY_EXT(what, ext) do { \
1527 strncpy(chk->has_##what, has+1, sizeof(ext)); \
1528 chk->has_##what[sizeof(ext)-1] = '\0'; \
1530 #define CHECK_EXT(what, ext) do { \
1531 has = _HAS_EXT(" " #ext " "); \
1532 if (has) CPY_EXT(what, #ext); \
1536 CHECK_EXT(half, cl_khr_fp16);
1537 CHECK_EXT(spir, cl_khr_spir);
1538 CHECK_EXT(double, cl_khr_fp64);
1539 if (!dev_has_double(chk))
1540 CHECK_EXT(double, cl_amd_fp64);
1541 if (!dev_has_double(chk))
1542 CHECK_EXT(double, cl_APPLE_fp64_basic_ops);
1543 CHECK_EXT(nv, cl_nv_device_attribute_query);
1544 CHECK_EXT(amd, cl_amd_device_attribute_query);
1545 CHECK_EXT(intel, cl_intel_device_attribute_query);
1546 CHECK_EXT(amd_svm, cl_amd_svm);
1547 CHECK_EXT(arm_svm, cl_arm_shared_virtual_memory);
1548 CHECK_EXT(intel_usm, cl_intel_unified_shared_memory);
1549 CHECK_EXT(external_memory, cl_khr_external_memory);
1550 CHECK_EXT(semaphore, cl_khr_semaphore);
1551 CHECK_EXT(external_semaphore, cl_khr_external_semaphore);
1552 CHECK_EXT(arm_core_id, cl_arm_core_id);
1553 CHECK_EXT(arm_job_slots, cl_arm_job_slot_selection);
1554 CHECK_EXT(arm_scheduling_controls, cl_arm_scheduling_controls);
1555 CHECK_EXT(fission, cl_ext_device_fission);
1556 CHECK_EXT(atomic_counters, cl_ext_atomic_counters_64);
1557 if (dev_has_atomic_counters(chk))
1558 CHECK_EXT(atomic_counters, cl_ext_atomic_counters_32);
1559 CHECK_EXT(image2d_buffer, cl_khr_image2d_from_buffer);
1560 CHECK_EXT(il_program, cl_khr_il_program);
1561 CHECK_EXT(intel_queue_families, cl_intel_command_queue_families);
1562 CHECK_EXT(intel_local_thread, cl_intel_exec_by_local_thread);
1563 CHECK_EXT(intel_AME, cl_intel_advanced_motion_estimation);
1564 CHECK_EXT(intel_AVC_ME, cl_intel_device_side_avc_motion_estimation);
1565 CHECK_EXT(intel_planar_yuv, cl_intel_planar_yuv);
1566 CHECK_EXT(intel_required_subgroup_size, cl_intel_required_subgroup_size);
1567 CHECK_EXT(altera_dev_temp, cl_altera_device_temperature);
1568 CHECK_EXT(p2p, cl_amd_copy_buffer_p2p);
1569 CHECK_EXT(pci_bus_info, cl_khr_pci_bus_info);
1570 CHECK_EXT(qcom_ext_host_ptr, cl_qcom_ext_host_ptr);
1571 CHECK_EXT(simultaneous_sharing, cl_intel_simultaneous_sharing);
1572 CHECK_EXT(subgroup_named_barrier, cl_khr_subgroup_named_barrier);
1573 CHECK_EXT(command_buffer, cl_khr_command_buffer);
1574 CHECK_EXT(mutable_dispatch, cl_khr_mutable_dispatch);
1575 CHECK_EXT(terminate_context, cl_khr_terminate_context);
1576 CHECK_EXT(terminate_arm, cl_arm_controlled_kernel_termination);
1577 CHECK_EXT(extended_versioning, cl_khr_extended_versioning);
1578 CHECK_EXT(cxx_for_opencl, cl_ext_cxx_for_opencl);
1579 CHECK_EXT(device_uuid, cl_khr_device_uuid);
1584 * Device info print functions
1587 #define _GET_VAL(ret, loc, val) \
1588 ret->err = REPORT_ERROR_LOC(ret, \
1589 clGetDeviceInfo((loc)->dev, (loc)->param.dev, sizeof(val), &(val), NULL), \
1591 CHECK_SIZE(ret, loc, val, clGetDeviceInfo, (loc)->dev, (loc)->param.dev);
1593 #define _GET_VAL_VALUES(ret, loc) \
1594 REALLOC(val, numval, loc->sname); \
1595 ret->err = REPORT_ERROR_LOC(ret, \
1596 clGetDeviceInfo(loc->dev, loc->param.dev, szval, val, NULL), \
1598 if (ret->err) { free(val); val = NULL; } \
1600 #define _GET_VAL_ARRAY(ret, loc) \
1601 ret->err = REPORT_ERROR_LOC(ret, \
1602 clGetDeviceInfo(loc->dev, loc->param.dev, 0, NULL, &szval), \
1603 loc, "get number of %s"); \
1604 numval = szval/sizeof(*val); \
1605 if (!ret->err && numval > 0) { \
1606 _GET_VAL_VALUES(ret, loc) \
1609 #define GET_VAL(ret, loc, field) do { \
1610 _GET_VAL(ret, (loc), ret->value.field) \
1613 #define GET_VAL_ARRAY(ret, loc) do { \
1614 _GET_VAL_ARRAY(ret, (loc)) \
1617 #define DEFINE_DEVINFO_FETCH(type, field) \
1619 device_fetch_##type(struct device_info_ret *ret, \
1620 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk), \
1621 const struct opt_out *output) \
1623 GET_VAL(ret, loc, field); \
1624 return ret->value.field; \
1627 DEFINE_DEVINFO_FETCH(size_t, s)
1628 DEFINE_DEVINFO_FETCH(cl_bool, b)
1629 DEFINE_DEVINFO_FETCH(cl_uint, u32)
1630 DEFINE_DEVINFO_FETCH(cl_version, u32)
1631 DEFINE_DEVINFO_FETCH(cl_ulong, u64)
1632 DEFINE_DEVINFO_FETCH(cl_bitfield, u64)
1633 DEFINE_DEVINFO_FETCH(cl_device_type, devtype)
1634 DEFINE_DEVINFO_FETCH(cl_device_mem_cache_type, cachetype)
1635 DEFINE_DEVINFO_FETCH(cl_device_local_mem_type, lmemtype)
1636 DEFINE_DEVINFO_FETCH(cl_device_topology_amd, devtopo_amd)
1637 DEFINE_DEVINFO_FETCH(cl_device_pci_bus_info_khr, devtopo_khr)
1638 DEFINE_DEVINFO_FETCH(cl_device_affinity_domain, affinity_domain)
1639 DEFINE_DEVINFO_FETCH(cl_device_fp_config, fpconfig)
1640 DEFINE_DEVINFO_FETCH(cl_command_queue_properties, qprop)
1641 DEFINE_DEVINFO_FETCH(cl_device_exec_capabilities, execap)
1642 DEFINE_DEVINFO_FETCH(cl_device_svm_capabilities, svmcap)
1643 DEFINE_DEVINFO_FETCH(cl_device_terminate_capability_khr, termcap)
1645 #define DEV_FETCH_LOC(type, var, loc) \
1646 type var = device_fetch_##type(ret, loc, chk, output)
1647 #define DEV_FETCH(type, var) DEV_FETCH_LOC(type, var, loc)
1649 #define FMT_VAL(loc, ret, fmt, val) if (!ret->err) strbuf_append(loc->pname, &ret->str, fmt, val)
1651 #define DEFINE_DEVINFO_SHOW(how, type, field, fmt) \
1653 device_info_##how(struct device_info_ret *ret, \
1654 const struct info_loc *loc, const struct device_info_checks* chk, \
1655 const struct opt_out *output) \
1657 DEV_FETCH(type, val); \
1658 if (!ret->err) FMT_VAL(loc, ret, fmt, val); \
1661 DEFINE_DEVINFO_SHOW(int, cl_uint, u32, "%" PRIu32)
1662 DEFINE_DEVINFO_SHOW(hex, cl_uint, u32, output->json ? "%" PRIu32 : "%#" PRIx32)
1663 DEFINE_DEVINFO_SHOW(long, cl_ulong, u64, "%" PRIu64)
1664 DEFINE_DEVINFO_SHOW(sz, size_t, s, "%" PRIuS)
1667 device_info_str(struct device_info_ret *ret,
1668 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1669 const struct opt_out* UNUSED(output))
1671 GET_STRING_LOC(ret, loc, clGetDeviceInfo, loc->dev, loc->param.dev);
1672 ret->needs_escaping = CL_TRUE;
1676 device_info_bool(struct device_info_ret *ret,
1677 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1678 const struct opt_out *output)
1680 DEV_FETCH(cl_bool, val);
1682 const char * const * str = (output->mode == CLINFO_HUMAN ?
1683 bool_str : output->json ? bool_json_str : bool_raw_str);
1684 strbuf_append(loc->pname, &ret->str, "%s", str[val]);
1689 device_info_bits(struct device_info_ret *ret,
1690 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1691 const struct opt_out *output)
1693 DEV_FETCH(cl_uint, val);
1695 strbuf_append(loc->pname, &ret->str, "%" PRIu32 " bits (%" PRIu32 " bytes)", val, val/8);
1699 device_info_version(struct device_info_ret *ret,
1700 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1701 const struct opt_out *output)
1703 GET_VAL(ret, loc, u32);
1705 strbuf_append(loc->pname, &ret->str,
1706 output->json ? "{ \" raw \" : %" PRIu32 ", \"version\" :" : "%#" PRIx32,
1708 if (output->json || output->mode == CLINFO_HUMAN) {
1709 strbuf_version(loc->pname, &ret->str,
1710 output->json ? " \"" : " (",
1712 output->json ? "\" }" : ")");
1718 device_info_ext_version(struct device_info_ret *ret,
1719 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1720 const struct opt_out *output)
1722 cl_name_version *val = NULL;
1723 size_t szval = 0, numval = 0;
1724 GET_VAL_ARRAY(ret, loc);
1726 strbuf_name_version(loc->pname, &ret->str, val, numval, output);
1732 device_info_ext_mem(struct device_info_ret *ret,
1733 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1734 const struct opt_out *output)
1736 cl_external_memory_handle_type_khr *val = NULL;
1737 size_t szval = 0, numval = 0;
1738 GET_VAL_ARRAY(ret, loc);
1740 strbuf_ext_mem(loc->pname, &ret->str, val, numval, output);
1746 device_info_semaphore_types(struct device_info_ret *ret,
1747 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1748 const struct opt_out *output)
1750 cl_semaphore_type_khr *val = NULL;
1751 size_t szval = 0, numval = 0;
1752 GET_VAL_ARRAY(ret, loc);
1754 strbuf_semaphore_type(loc->pname, &ret->str, val, numval, output);
1760 device_info_ext_semaphore_handles(struct device_info_ret *ret,
1761 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1762 const struct opt_out *output)
1764 cl_external_semaphore_handle_type_khr *val = NULL;
1765 size_t szval = 0, numval = 0;
1766 GET_VAL_ARRAY(ret, loc);
1768 strbuf_ext_semaphore_handle(loc->pname, &ret->str, val, numval, output);
1773 void strbuf_mem(const char *what, struct _strbuf *str, cl_ulong val)
1775 double dbl = (double)val;
1777 while (dbl > 1024 && sfx < memsfx_end) {
1781 strbuf_append(what, str, " (%.4lg%s)", dbl, memsfx[sfx]);
1785 device_info_mem(struct device_info_ret *ret,
1786 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1787 const struct opt_out *output)
1789 GET_VAL(ret, loc, u64);
1791 strbuf_append(loc->pname, &ret->str, "%" PRIu64, ret->value.u64);
1792 if (output->mode == CLINFO_HUMAN && ret->value.u64 > 1024)
1793 strbuf_mem(loc->pname, &ret->str, ret->value.u64);
1798 device_info_mem_int(struct device_info_ret *ret,
1799 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1800 const struct opt_out *output)
1802 GET_VAL(ret, loc, u32);
1804 strbuf_append(loc->pname, &ret->str, "%" PRIu32, ret->value.u32);
1805 if (output->mode == CLINFO_HUMAN && ret->value.u32 > 1024)
1806 strbuf_mem(loc->pname, &ret->str, ret->value.u32);
1811 device_info_mem_sz(struct device_info_ret *ret,
1812 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1813 const struct opt_out *output)
1815 GET_VAL(ret, loc, s);
1817 strbuf_append(loc->pname, &ret->str, "%" PRIuS, ret->value.s);
1818 if (output->mode == CLINFO_HUMAN && ret->value.s > 1024)
1819 strbuf_mem(loc->pname, &ret->str, ret->value.s);
1824 device_info_free_mem_amd(struct device_info_ret *ret,
1825 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1826 const struct opt_out *output)
1828 // Apparently, with the introduction of ROCm, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD
1829 // returns 1 or 2 values depending on how it's called: if it's called with a
1830 // szval < 2*sizeof(size_t), it will only return 1 value, otherwise it will return 2.
1831 // At least now these are documented in the ROCm source code: the first value
1832 // is the total amount of free memory, and the second is the size of the largest
1833 // free block. So let's just manually ask for both values
1834 GET_VAL(ret, loc, u64v2);
1838 strbuf_append_str_len(loc->pname, &ret->str, " [", 2);
1839 for (cursor = 0; cursor < 2; ++cursor) {
1840 cl_ulong v = ret->value.u64v2.s[cursor];
1842 strbuf_append_str(loc->pname, &ret->str,
1843 output->json ? comma_str : spc_str);
1844 strbuf_append(loc->pname, &ret->str, "%" PRIuS, v);
1845 if (output->mode == CLINFO_HUMAN)
1846 strbuf_mem(loc->pname, &ret->str, v*UINT64_C(1024));
1849 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
1854 device_info_time_offset(struct device_info_ret *ret,
1855 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1856 const struct opt_out *output)
1858 GET_VAL(ret, loc, u64);
1860 time_t time = ret->value.u64/UINT64_C(1000000000);
1861 strbuf_append(loc->pname, &ret->str, "%" PRIu64 "ns (", ret->value.u64);
1862 strbuf_append_str(loc->pname, &ret->str, ctime(&time));
1863 /* overwrite ctime's newline with the closing parenthesis */
1864 ret->str.buf[ret->str.end - 1] = ')';
1869 device_info_intptr(struct device_info_ret *ret,
1870 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1871 const struct opt_out *output)
1874 size_t szval = 0, numval = 0;
1875 GET_VAL_ARRAY(ret, loc);
1878 set_separator(output->mode == CLINFO_HUMAN ? comma_str : output->json ? comma_str : spc_str);
1880 strbuf_append_str_len(loc->pname, &ret->str, " [", 2);
1881 for (counter = 0; counter < numval; ++counter) {
1882 if (counter > 0) strbuf_append_str(loc->pname, &ret->str, sep);
1883 strbuf_append(loc->pname, &ret->str, "%" PRId32, val[counter]);
1886 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
1887 // TODO: ret->value.??? = val;
1893 device_info_szptr_sep(struct device_info_ret *ret, const char *human_sep,
1894 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
1895 const struct opt_out *output)
1898 size_t szval = 0, numval = 0;
1899 GET_VAL_ARRAY(ret, loc);
1902 set_separator(output->mode == CLINFO_HUMAN ? human_sep : output->json ? comma_str : spc_str);
1904 strbuf_append_str_len(loc->pname, &ret->str, " [", 2);
1905 for (counter = 0; counter < numval; ++counter) {
1906 if (counter > 0) strbuf_append_str(loc->pname, &ret->str, sep);
1907 strbuf_append(loc->pname, &ret->str, "%" PRIuS, val[counter]);
1910 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
1911 // TODO: ret->value.??? = val;
1918 device_info_szptr_times(struct device_info_ret *ret,
1919 const struct info_loc *loc, const struct device_info_checks* chk,
1920 const struct opt_out *output)
1922 device_info_szptr_sep(ret, times_str, loc, chk, output);
1926 device_info_szptr_comma(struct device_info_ret *ret,
1927 const struct info_loc *loc, const struct device_info_checks* chk,
1928 const struct opt_out *output)
1930 device_info_szptr_sep(ret, comma_str, loc, chk, output);
1934 getWGsizes(struct device_info_ret *ret, const struct info_loc *loc, size_t *wgm, size_t wgm_sz,
1935 const struct opt_out* UNUSED(output))
1939 cl_context_properties ctxpft[] = {
1940 CL_CONTEXT_PLATFORM, (cl_context_properties)loc->plat,
1943 cl_context ctx = NULL;
1944 cl_program prg = NULL;
1945 cl_kernel krn = NULL;
1947 ret->err = CL_SUCCESS;
1949 ctx = clCreateContext(ctxpft, 1, &loc->dev, NULL, NULL, &ret->err);
1950 if (REPORT_ERROR(&ret->err_str, ret->err, "create context")) goto out;
1951 prg = clCreateProgramWithSource(ctx, ARRAY_SIZE(sources), sources, NULL, &ret->err);
1952 if (REPORT_ERROR(&ret->err_str, ret->err, "create program")) goto out;
1953 ret->err = clBuildProgram(prg, 1, &loc->dev, NULL, NULL, NULL);
1954 log_err = REPORT_ERROR(&ret->err_str, ret->err, "build program");
1956 /* for a program build failure, dump the log to stderr before bailing */
1957 if (log_err == CL_BUILD_PROGRAM_FAILURE) {
1958 struct _strbuf logbuf;
1959 init_strbuf(&logbuf, "program build log");
1960 GET_STRING(&logbuf, ret->err,
1961 clGetProgramBuildInfo, CL_PROGRAM_BUILD_LOG, "CL_PROGRAM_BUILD_LOG", prg, loc->dev);
1962 if (ret->err == CL_SUCCESS) {
1965 fputs("=== CL_PROGRAM_BUILD_LOG ===\n", stderr);
1966 fputs(logbuf.buf, stderr);
1969 free_strbuf(&logbuf);
1974 for (cursor = 0; cursor < wgm_sz; ++cursor) {
1975 strbuf_append(__func__, &ret->str, "sum%u", 1<<cursor);
1977 ret->str.buf[3] = 0; // scalar kernel is called 'sum'
1978 krn = clCreateKernel(prg, ret->str.buf, &ret->err);
1979 reset_strbuf(&ret->str);
1980 if (REPORT_ERROR(&ret->err_str, ret->err, "create kernel")) goto out;
1981 ret->err = clGetKernelWorkGroupInfo(krn, loc->dev, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE,
1982 sizeof(*wgm), wgm + cursor, NULL);
1983 if (REPORT_ERROR(&ret->err_str, ret->err, "get kernel info")) goto out;
1984 clReleaseKernel(krn);
1990 clReleaseKernel(krn);
1992 clReleaseProgram(prg);
1994 clReleaseContext(ctx);
1999 device_info_wg(struct device_info_ret *ret,
2000 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2001 const struct opt_out *output)
2003 /* preferred workgroup size multiple for each kernel
2004 * have not found a platform where the WG multiple changes,
2005 * but keep this flexible (this can grow up to 5)
2007 #define NUM_KERNELS 1
2008 size_t wgm[NUM_KERNELS] = {0};
2010 getWGsizes(ret, loc, wgm, NUM_KERNELS, output);
2012 strbuf_append("get WG sizes", &ret->str, "%" PRIuS, wgm[0]);
2014 ret->value.s = wgm[0];
2018 device_info_img_sz_2d(struct device_info_ret *ret,
2019 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2020 const struct opt_out *output)
2022 struct info_loc loc2 = *loc;
2023 size_t width = 0, height = 0;
2024 _GET_VAL(ret, loc, height); /* HEIGHT */
2026 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_IMAGE2D_MAX_WIDTH);
2027 _GET_VAL(ret, &loc2, width);
2029 strbuf_append("image size 2D", &ret->str, "%" PRIuS "x%" PRIuS, width, height);
2032 ret->value.u64v.s[0] = width;
2033 ret->value.u64v.s[1] = height;
2037 device_info_img_sz_intel_planar_yuv(struct device_info_ret *ret,
2038 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2039 const struct opt_out *output)
2041 struct info_loc loc2 = *loc;
2042 size_t width = 0, height = 0;
2043 _GET_VAL(ret, loc, height); /* HEIGHT */
2045 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL);
2046 _GET_VAL(ret, &loc2, width);
2048 strbuf_append("image size planar YUV", &ret->str, "%" PRIuS "x%" PRIuS, width, height);
2051 ret->value.u64v.s[0] = width;
2052 ret->value.u64v.s[1] = height;
2057 device_info_img_sz_3d(struct device_info_ret *ret,
2058 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2059 const struct opt_out *output)
2061 struct info_loc loc2 = *loc;
2062 size_t width = 0, height = 0, depth = 0;
2063 _GET_VAL(ret, loc, height); /* HEIGHT */
2065 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_IMAGE3D_MAX_WIDTH);
2066 _GET_VAL(ret, &loc2, width);
2068 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_IMAGE3D_MAX_DEPTH);
2069 _GET_VAL(ret, &loc2, depth);
2071 strbuf_append("image size 3D", &ret->str,
2072 "%" PRIuS "x%" PRIuS "x%" PRIuS,
2073 width, height, depth);
2077 ret->value.u64v.s[0] = width;
2078 ret->value.u64v.s[1] = height;
2079 ret->value.u64v.s[2] = depth;
2082 void strbuf_bitfield(const char *what, struct _strbuf *str,
2083 cl_bitfield bits, const char *bits_name,
2084 const char * const *bit_str, size_t bit_str_count,
2085 const struct opt_out *output)
2087 const char *quote = output->json ? "\"" : "";
2088 /* number of matches so far, for separator placement */
2092 /* leftovers bits */
2093 cl_bitfield known_mask, extra;
2095 set_common_separator(output);
2098 strbuf_append(what, str,
2099 "{ \"raw\" : %" PRIu64 ", \"%s\" : [ ",
2103 for (i = 0; i < bit_str_count; ++i) {
2104 if (bits & (1UL << i)) {
2105 strbuf_append(what, str, "%s%s%s%s",
2106 (count > 0 ? sep : ""),
2107 quote, bit_str[i], quote);
2112 /* check for extra bits */
2113 known_mask = ((cl_bitfield)(1) << bit_str_count) - 1;
2114 extra = bits & ~known_mask;
2116 strbuf_append(what, str, "%s%s%#" PRIx64 "%s",
2117 (count > 0 ? sep : ""), quote, extra, quote);
2122 strbuf_append_str(what, str, " ] }");
2127 device_info_bitfield(struct device_info_ret *ret,
2128 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2129 const struct opt_out *output,
2130 const cl_bitfield bits,
2131 const size_t bit_str_count, /* number of entries in bit_str */
2132 const char * const * bit_str, /* array of strings describing the bits */
2133 const char * bits_name) /* JSON name for this bitfield */
2135 strbuf_bitfield(loc->pname, &ret->str, bits, bits_name, bit_str, bit_str_count, output);
2139 /* This could use device_info_bitfield, but we prefer to go through fields in reverse,
2140 * so we just dup the code
2143 device_info_devtype(struct device_info_ret *ret,
2144 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2145 const struct opt_out *output)
2147 GET_VAL(ret, loc, devtype);
2149 const char *quote = output->json ? "\"" : "";
2150 const char * const *devstr = (output->mode == CLINFO_HUMAN ?
2151 device_type_str : device_type_raw_str);
2152 cl_uint i = (cl_uint)actual_devtype_count;
2153 /* number of matches so far, for separator placement */
2155 /* leftovers bits */
2156 cl_device_type known_mask, extra;
2158 set_common_separator(output);
2161 strbuf_append(loc->pname, &ret->str,
2162 "{ \"raw\" : %" PRIu64 ", \"type\" : [ ",
2163 ret->value.devtype);
2165 /* iterate over device type strings, appending their textual form
2167 for (; i > 0; --i) {
2168 /* assemble CL_DEVICE_TYPE_* from index i */
2169 cl_device_type cur = (cl_device_type)(1) << (i-1);
2170 if (ret->value.devtype & cur) {
2171 /* match: add separator if not first match */
2172 strbuf_append(loc->pname, &ret->str, "%s%s%s%s",
2173 (count > 0 ? sep : ""),
2174 quote, devstr[i], quote);
2179 /* check for extra bits */
2180 known_mask = ((cl_device_type)(1) << actual_devtype_count) - 1;
2181 extra = ret->value.devtype & ~known_mask;
2183 strbuf_append(loc->pname, &ret->str, "%s%s%#" PRIx64 "%s",
2184 (count > 0 ? sep : ""), quote, extra, quote);
2188 strbuf_append_str(loc->pname, &ret->str, " ] }");
2193 device_info_cachetype(struct device_info_ret *ret,
2194 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2195 const struct opt_out *output)
2197 GET_VAL(ret, loc, cachetype);
2199 const char * const *ar = (output->mode == CLINFO_HUMAN ?
2200 cache_type_str : cache_type_raw_str);
2201 strbuf_append_str(loc->pname, &ret->str, ar[ret->value.cachetype]);
2202 ret->needs_escaping = CL_TRUE;
2207 device_info_lmemtype(struct device_info_ret *ret,
2208 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2209 const struct opt_out *output)
2211 GET_VAL(ret, loc, lmemtype);
2213 const char * const *ar = (output->mode == CLINFO_HUMAN ?
2214 lmem_type_str : lmem_type_raw_str);
2215 strbuf_append_str(loc->pname, &ret->str, ar[ret->value.lmemtype]);
2216 ret->needs_escaping = CL_TRUE;
2221 device_info_atomic_caps(struct device_info_ret *ret,
2222 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2223 const struct opt_out *output)
2225 GET_VAL(ret, loc, bits);
2227 device_info_bitfield(ret, loc, chk, output, ret->value.bits,
2228 atomic_cap_count, (output->mode == CLINFO_HUMAN ?
2229 atomic_cap_str : atomic_cap_raw_str),
2235 device_info_device_enqueue_caps(struct device_info_ret *ret,
2236 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2237 const struct opt_out *output)
2239 GET_VAL(ret, loc, bits);
2241 device_info_bitfield(ret, loc, chk, output, ret->value.bits,
2242 device_enqueue_cap_count, (output->mode == CLINFO_HUMAN ?
2243 device_enqueue_cap_str : device_enqueue_cap_raw_str),
2248 /* cl_arm_core_id */
2250 device_info_core_ids(struct device_info_ret *ret,
2251 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2252 const struct opt_out *output)
2255 GET_VAL(ret, loc, u64);
2256 val = ret->value.u64;
2259 const char *quote = output->json ? "\"" : "";
2260 /* The value is a bitfield where each set bit corresponds to a core ID
2261 * value that can be returned by the device-side function. We print them
2262 * here as ranges, such as 0-4, 8-12 */
2263 int range_start = -1;
2267 strbuf_append(loc->pname, &ret->str,
2268 "{ \"raw\" : %" PRIu64 ", \"core_ids\" : [ ",
2271 set_separator(empty_str);
2272 #define CORE_ID_END 64
2274 /* Find the start of the range */
2275 while ((cur_bit < CORE_ID_END) && !((val >> cur_bit) & 1))
2277 range_start = cur_bit++;
2279 /* Find the end of the range */
2280 while ((cur_bit < CORE_ID_END) && ((val >> cur_bit) & 1))
2283 /* print the range [range_start, cur_bit[ */
2284 if (range_start >= 0 && range_start < CORE_ID_END) {
2285 strbuf_append(loc->pname, &ret->str, "%s%s%d", sep, quote, range_start);
2286 if (cur_bit - range_start > 1)
2287 strbuf_append(loc->pname, &ret->str, "-%d", cur_bit - 1);
2288 set_separator(comma_str);
2290 strbuf_append_str(loc->pname, &ret->str, quote);
2292 } while (cur_bit < CORE_ID_END);
2295 strbuf_append_str(loc->pname, &ret->str, " ] }");
2299 /* cl_arm_job_slot_selection */
2301 device_info_job_slots(struct device_info_ret *ret,
2302 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2303 const struct opt_out *output)
2306 GET_VAL(ret, loc, u32);
2307 val = ret->value.u32;
2310 const char *quote = output->json ? "\"" : "";
2311 /* The value is a bitfield where each set bit corresponds to an available job slot.
2312 * We print them here as ranges, such as 0-4, 8-12 */
2313 int range_start = -1;
2317 strbuf_append(loc->pname, &ret->str,
2318 "{ \"raw\" : %" PRIu32 ", \"slots\" : [ ",
2321 set_separator(empty_str);
2322 #define JOB_SLOT_END 32
2324 /* Find the start of the range */
2325 while ((cur_bit < JOB_SLOT_END) && !((val >> cur_bit) & 1))
2327 range_start = cur_bit++;
2329 /* Find the end of the range */
2330 while ((cur_bit < JOB_SLOT_END) && ((val >> cur_bit) & 1))
2333 /* print the range [range_start, cur_bit[ */
2334 if (range_start >= 0 && range_start < JOB_SLOT_END) {
2335 strbuf_append(loc->pname, &ret->str, "%s%s%d", sep, quote, range_start);
2336 if (cur_bit - range_start > 1)
2337 strbuf_append(loc->pname, &ret->str, "-%d", cur_bit - 1);
2338 set_separator(comma_str);
2340 strbuf_append_str(loc->pname, &ret->str, quote);
2342 } while (cur_bit < JOB_SLOT_END);
2345 strbuf_append_str(loc->pname, &ret->str, " ] }");
2349 void devtopo_pci_str(struct device_info_ret *ret, const cl_device_pci_bus_info_khr *devtopo)
2351 strbuf_append("devtopo", &ret->str, "PCI-E, %04x:%02x:%02x.%u",
2352 devtopo->pci_domain,
2354 devtopo->pci_device, devtopo->pci_function);
2355 ret->value.devtopo_khr = *devtopo;
2359 device_info_devtopo_khr(struct device_info_ret *ret,
2360 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2361 const struct opt_out *output)
2363 GET_VAL(ret, loc, devtopo_khr);
2364 /* TODO how to do this in CLINFO_RAW mode */
2366 devtopo_pci_str(ret, &ret->value.devtopo_khr);
2368 ret->needs_escaping = CL_TRUE;
2373 /* stringify a cl_device_topology_amd */
2374 void devtopo_amd_str(struct device_info_ret *ret, const cl_device_topology_amd *devtopo)
2376 cl_device_pci_bus_info_khr devtopo_info;
2378 switch (devtopo->raw.type) {
2382 case CL_DEVICE_TOPOLOGY_TYPE_PCIE_AMD:
2383 devtopo_info.pci_domain = 0;
2384 devtopo_info.pci_bus = devtopo->pcie.bus;
2385 devtopo_info.pci_device = devtopo->pcie.device;
2386 devtopo_info.pci_function = devtopo->pcie.function;
2387 devtopo_pci_str(ret, &devtopo_info);
2390 strbuf_append("devtopo", &ret->str, "<unknown (%u): %u %u %u %u %u>",
2392 devtopo->raw.data[0], devtopo->raw.data[1],
2393 devtopo->raw.data[2],
2394 devtopo->raw.data[3], devtopo->raw.data[4]);
2399 device_info_devtopo_amd(struct device_info_ret *ret,
2400 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2401 const struct opt_out *output)
2403 GET_VAL(ret, loc, devtopo_amd);
2404 /* TODO how to do this in CLINFO_RAW mode */
2406 devtopo_amd_str(ret, &ret->value.devtopo_amd);
2408 ret->needs_escaping = CL_TRUE;
2412 /* we assemble a clinfo_device_topology_pci struct from the NVIDIA info */
2414 device_info_devtopo_nv(struct device_info_ret *ret,
2415 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2416 const struct opt_out *output)
2418 struct info_loc loc2 = *loc;
2419 cl_device_pci_bus_info_khr devtopo;
2420 DEV_FETCH(cl_uint, val); /* CL_DEVICE_PCI_BUS_ID_NV */
2422 devtopo.pci_bus = val & 0xff;
2423 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_PCI_SLOT_ID_NV);
2424 _GET_VAL(ret, &loc2, val);
2428 devtopo.pci_device = (val >> 3) & 0xff;
2429 devtopo.pci_function = val & 7;
2431 /* CL_DEVICE_PCI_DOMAIN_ID_NV is not supported in older drivers,
2432 * but we have no way to check other than querying, and recovering
2433 * in the CL_INVALID_VALUE case */
2434 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_PCI_DOMAIN_ID_NV);
2435 safe_err = clGetDeviceInfo(loc2.dev, CL_DEVICE_PCI_DOMAIN_ID_NV,
2436 sizeof(val), &val, NULL);
2437 if (safe_err == CL_SUCCESS) {
2438 devtopo.pci_domain = val;
2439 } else if (safe_err == CL_INVALID_VALUE) {
2440 devtopo.pci_domain = 0;
2442 REPORT_ERROR_LOC(ret, safe_err, &loc2, "get CL_DEVICE_PCI_DOMAIN_ID_NV");
2445 devtopo_pci_str(ret, &devtopo);
2450 /* NVIDIA Compute Capability */
2452 device_info_cc_nv(struct device_info_ret *ret,
2453 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2454 const struct opt_out *output)
2456 struct info_loc loc2 = *loc;
2457 cl_uint major = 0, minor = 0;
2458 _GET_VAL(ret, loc, major); /* MAJOR */
2460 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV);
2461 _GET_VAL(ret, &loc2, minor);
2463 strbuf_append("NV CC", &ret->str, "%" PRIu32 ".%" PRIu32 "", major, minor);
2466 ret->value.u32v.s[0] = major;
2467 ret->value.u32v.s[1] = minor;
2472 device_info_gfxip_amd(struct device_info_ret *ret,
2473 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2474 const struct opt_out *output)
2476 struct info_loc loc2 = *loc;
2477 cl_uint major = 0, minor = 0;
2478 _GET_VAL(ret, loc, major); /* MAJOR */
2480 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_GFXIP_MINOR_AMD);
2481 _GET_VAL(ret, &loc2, minor);
2483 strbuf_append("AMD GFXIP", &ret->str, "%" PRIu32 ".%" PRIu32 "", major, minor);
2486 ret->value.u32v.s[0] = major;
2487 ret->value.u32v.s[1] = minor;
2490 /* Intel feature capabilities */
2492 device_info_intel_features(struct device_info_ret *ret,
2493 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2494 const struct opt_out *output)
2496 GET_VAL(ret, loc, bits);
2497 device_info_bitfield(ret, loc, chk, output, ret->value.bits, intel_features_count,
2498 (output->mode == CLINFO_HUMAN ? intel_features_str : intel_features_raw_str),
2504 /* Device Partition, CLINFO_HUMAN header */
2506 device_info_partition_header(struct device_info_ret *ret,
2507 const struct info_loc *UNUSED(loc), const struct device_info_checks *chk,
2508 const struct opt_out* UNUSED(output))
2510 cl_bool is_12 = dev_is_12(chk);
2511 cl_bool has_fission = dev_has_fission(chk);
2512 strbuf_append("dev partition", &ret->str, "(%s%s%s%s)",
2513 (is_12 ? core : empty_str),
2514 (is_12 && has_fission ? comma_str : empty_str),
2516 (!(is_12 || has_fission) ? na : empty_str));
2518 ret->err = CL_SUCCESS;
2521 /* Device partition properties */
2523 device_info_partition_types(struct device_info_ret *ret,
2524 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2525 const struct opt_out *output)
2527 size_t numval = 0, szval = 0, cursor = 0;
2528 cl_device_partition_property *val = NULL;
2529 const char * const *ptstr = (output->mode == CLINFO_HUMAN ?
2530 partition_type_str : partition_type_raw_str);
2532 GET_VAL_ARRAY(ret, loc);
2535 const char *quote = output->json ? "\"" : "";
2536 set_common_separator(output);
2538 strbuf_append_str_len(loc->pname, &ret->str, "[ ", 2);
2540 for (cursor = 0; cursor < numval; ++cursor) {
2543 /* add separator for values past the first */
2544 if (cursor > 0) strbuf_append_str(loc->pname, &ret->str, sep);
2546 switch (val[cursor]) {
2547 case 0: str_idx = 0; break;
2548 case CL_DEVICE_PARTITION_EQUALLY: str_idx = 1; break;
2549 case CL_DEVICE_PARTITION_BY_COUNTS: str_idx = 2; break;
2550 case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN: str_idx = 3; break;
2551 case CL_DEVICE_PARTITION_BY_NAMES_INTEL: str_idx = 4; break;
2553 strbuf_append(loc->pname, &ret->str,
2554 "%sby <unknown> (%#" PRIxPTR ")%s",
2555 quote, val[cursor], quote);
2559 /* string length, minus _EXT */
2560 size_t slen = strlen(ptstr[str_idx]);
2561 if (output->mode == CLINFO_RAW && str_idx > 0)
2563 strbuf_append_str(loc->pname, &ret->str, quote);
2564 strbuf_append_str_len(loc->pname, &ret->str, ptstr[str_idx], slen);
2565 strbuf_append_str(loc->pname, &ret->str, quote);
2569 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
2570 // TODO ret->value.??? = val
2576 device_info_partition_types_ext(struct device_info_ret *ret,
2577 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2578 const struct opt_out *output)
2580 size_t numval = 0, szval = 0, cursor = 0;
2581 cl_device_partition_property_ext *val = NULL;
2582 const char * const *ptstr = (output->mode == CLINFO_HUMAN ?
2583 partition_type_str : partition_type_raw_str);
2585 GET_VAL_ARRAY(ret, loc);
2588 const char *quote = output->json ? "\"" : "";
2589 set_common_separator(output);
2591 strbuf_append_str_len(loc->pname, &ret->str, "[ ", 1);
2593 for (cursor = 0; cursor < numval; ++cursor) {
2596 /* add separator for values past the first */
2597 if (cursor > 0) strbuf_append_str(loc->pname, &ret->str, sep);
2599 switch (val[cursor]) {
2600 case 0: str_idx = 0; break;
2601 case CL_DEVICE_PARTITION_EQUALLY_EXT: str_idx = 1; break;
2602 case CL_DEVICE_PARTITION_BY_COUNTS_EXT: str_idx = 2; break;
2603 case CL_DEVICE_PARTITION_BY_AFFINITY_DOMAIN_EXT: str_idx = 3; break;
2604 case CL_DEVICE_PARTITION_BY_NAMES_EXT: str_idx = 4; break;
2606 strbuf_append(loc->pname, &ret->str,
2607 "%sby <unknown> (%#" PRIx64 ")%s",
2608 quote, val[cursor], quote);
2612 strbuf_append(loc->pname, &ret->str, "%s%s%s",
2613 quote, ptstr[str_idx], quote);
2617 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
2618 // TODO ret->value.??? = val
2624 /* Device partition affinity domains */
2626 device_info_partition_affinities(struct device_info_ret *ret,
2627 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2628 const struct opt_out *output)
2630 GET_VAL(ret, loc, affinity_domain);
2633 device_info_bitfield(ret, loc, chk, output, ret->value.affinity_domain,
2634 affinity_domain_count, (output->mode == CLINFO_HUMAN ?
2635 affinity_domain_str : affinity_domain_raw_str),
2641 device_info_partition_affinities_ext(struct device_info_ret *ret,
2642 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2643 const struct opt_out *output)
2645 size_t numval = 0, szval = 0, cursor = 0;
2646 cl_device_partition_property_ext *val = NULL;
2647 const char * const *ptstr = (output->mode == CLINFO_HUMAN ?
2648 affinity_domain_ext_str : affinity_domain_raw_ext_str);
2650 GET_VAL_ARRAY(ret, loc);
2653 const char *quote = output->json ? "\"" : "";
2654 set_common_separator(output);
2656 strbuf_append_str_len(loc->pname, &ret->str, "[ ", 2);
2658 for (cursor = 0; cursor < numval; ++cursor) {
2661 /* add separator for values past the first */
2662 if (cursor > 0) strbuf_append_str(loc->pname, &ret->str, sep);
2664 switch (val[cursor]) {
2665 case CL_AFFINITY_DOMAIN_NUMA_EXT: str_idx = 0; break;
2666 case CL_AFFINITY_DOMAIN_L4_CACHE_EXT: str_idx = 1; break;
2667 case CL_AFFINITY_DOMAIN_L3_CACHE_EXT: str_idx = 2; break;
2668 case CL_AFFINITY_DOMAIN_L2_CACHE_EXT: str_idx = 3; break;
2669 case CL_AFFINITY_DOMAIN_L1_CACHE_EXT: str_idx = 4; break;
2670 case CL_AFFINITY_DOMAIN_NEXT_FISSIONABLE_EXT: str_idx = 5; break;
2672 strbuf_append(loc->pname, &ret->str,
2673 "%s<unknown> (%#" PRIx64 ")%s",
2674 quote, val[cursor], quote);
2678 strbuf_append(loc->pname, &ret->str, "%s%s%s",
2679 quote, ptstr[str_idx], quote);
2683 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
2684 // TODO: ret->value.??? = val
2689 /* Preferred / native vector widths */
2691 device_info_vecwidth(struct device_info_ret *ret,
2692 const struct info_loc *loc, const struct device_info_checks *chk,
2693 const struct opt_out *output)
2695 struct info_loc loc2 = *loc;
2696 cl_uint preferred = 0, native = 0;
2697 _GET_VAL(ret, loc, preferred);
2699 /* we get called with PREFERRED, NATIVE is at +0x30 offset, except for HALF,
2700 * which is at +0x08 */
2702 (loc2.param.dev == CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF ? 0x08 : 0x30);
2703 /* TODO update loc2.sname */
2704 _GET_VAL(ret, &loc2, native);
2707 const char *ext = (loc2.param.dev == CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF ?
2708 chk->has_half : (loc2.param.dev == CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE ?
2709 chk->has_double : NULL));
2710 strbuf_append(loc->pname, &ret->str, "%8u / %-8u", preferred, native);
2712 strbuf_append(loc->pname, &ret->str, " (%s)", *ext ? ext : na);
2715 ret->value.u32v.s[0] = preferred;
2716 ret->value.u32v.s[1] = native;
2719 /* Floating-point configurations */
2721 device_info_fpconf(struct device_info_ret *ret,
2722 const struct info_loc *loc, const struct device_info_checks *chk,
2723 const struct opt_out *output)
2725 /* When in HUMAN output, we are called unconditionally,
2726 * so we have to do some manual checks ourselves */
2727 const cl_bool get_it = (output->mode != CLINFO_HUMAN) ||
2728 (loc->param.dev == CL_DEVICE_SINGLE_FP_CONFIG) ||
2729 (loc->param.dev == CL_DEVICE_HALF_FP_CONFIG && dev_has_half(chk)) ||
2730 (loc->param.dev == CL_DEVICE_DOUBLE_FP_CONFIG && dev_has_double(chk));
2732 GET_VAL(ret, loc, fpconfig);
2734 if (ret->err && !get_it) {
2735 ret->err = CL_SUCCESS;
2736 ret->value.fpconfig = 0;
2740 strbuf_append(loc->pname, &ret->str,
2741 "{ \"raw\" : %" PRIu64 ", \"config\" : [ ",
2742 ret->value.fpconfig);
2747 const char * const *fpstr = (output->mode == CLINFO_HUMAN ?
2748 fp_conf_str : fp_conf_raw_str);
2749 set_common_separator(output);
2750 if (output->mode == CLINFO_HUMAN) {
2751 const char *why = na;
2752 switch (loc->param.dev) {
2753 case CL_DEVICE_HALF_FP_CONFIG:
2755 why = chk->has_half;
2757 case CL_DEVICE_SINGLE_FP_CONFIG:
2760 case CL_DEVICE_DOUBLE_FP_CONFIG:
2762 why = chk->has_double;
2765 /* "this can't happen" (unless OpenCL starts supporting _other_ floating-point formats, maybe) */
2766 fprintf(stderr, "unsupported floating-point configuration parameter %s\n", loc->pname);
2768 /* show 'why' it's being shown */
2769 strbuf_append(loc->pname, &ret->str, "(%s)", why);
2772 const char *quote = output->json ? "\"" : "";
2773 size_t num_flags = fp_conf_count;
2774 /* The last flag, CL_FP_CORRECTLY_ROUNDED_DIVIDE_SQRT is only considered
2775 * in the single-precision case. half and double don't consider it,
2776 * so we skip it altogether */
2777 if (loc->param.dev != CL_DEVICE_SINGLE_FP_CONFIG)
2780 for (i = 0; i < num_flags; ++i) {
2781 cl_device_fp_config cur = (cl_device_fp_config)(1) << i;
2782 cl_bool present = !!(ret->value.fpconfig & cur);
2783 if (output->mode == CLINFO_HUMAN) {
2784 strbuf_append(loc->pname, &ret->str, "\n%s" I2_STR "%s",
2785 line_pfx, fpstr[i], bool_str[present]);
2786 } else if (present) {
2787 strbuf_append(loc->pname, &ret->str, "%s%s%s%s",
2788 (count > 0 ? sep : ""), quote, fpstr[i], quote);
2795 strbuf_append_str(loc->pname, &ret->str, " ] }");
2798 /* Queue properties */
2800 device_info_qprop(struct device_info_ret *ret,
2801 const struct info_loc *loc, const struct device_info_checks *chk,
2802 const struct opt_out *output)
2804 GET_VAL(ret, loc, qprop);
2806 const char * const *qpstr = (output->mode == CLINFO_HUMAN ?
2807 queue_prop_str : queue_prop_raw_str);
2809 if (output->mode != CLINFO_HUMAN) {
2810 device_info_bitfield(ret, loc, chk, output, ret->value.qprop,
2811 queue_prop_count, qpstr, "queue_prop");
2812 } else { /* output->mode == CLINFO_HUMAN */
2813 for (cl_uint i = 0; i < queue_prop_count; ++i) {
2814 cl_command_queue_properties cur = (cl_command_queue_properties)(1) << i;
2815 cl_bool present =!!(ret->value.qprop & cur);
2816 strbuf_append(loc->pname, &ret->str, "\n%s" I2_STR "%s",
2817 line_pfx, qpstr[i], bool_str[present]);
2819 /* TODO FIXME extra bits? */
2820 if (loc->param.dev == CL_DEVICE_QUEUE_PROPERTIES && dev_has_intel_local_thread(chk))
2821 strbuf_append(loc->pname, &ret->str, "\n%s" I2_STR "%s",
2822 line_pfx, "Local thread execution (Intel)", bool_str[CL_TRUE]);
2828 device_info_command_buffer_caps(struct device_info_ret *ret,
2829 const struct info_loc *loc, const struct device_info_checks *chk,
2830 const struct opt_out *output)
2832 GET_VAL(ret, loc, cmdbufcap);
2834 device_info_bitfield(ret, loc, chk, output, ret->value.cmdbufcap,
2835 command_buffer_count,
2836 (output->mode == CLINFO_RAW ? command_buffer_raw_str : command_buffer_str),
2842 device_info_mutable_dispatch_caps(struct device_info_ret *ret,
2843 const struct info_loc *loc, const struct device_info_checks *chk,
2844 const struct opt_out *output)
2846 GET_VAL(ret, loc, cmdbufcap);
2848 device_info_bitfield(ret, loc, chk, output, ret->value.cmdbufcap,
2849 mutable_dispatch_count,
2850 (output->mode == CLINFO_RAW ? mutable_dispatch_raw_str : mutable_dispatch_str),
2856 device_info_intel_usm_cap(struct device_info_ret *ret,
2857 const struct info_loc *loc, const struct device_info_checks *chk,
2858 const struct opt_out *output)
2860 GET_VAL(ret, loc, svmcap);
2862 device_info_bitfield(ret, loc, chk, output, ret->value.svmcap,
2863 intel_usm_cap_count,
2864 (output->mode == CLINFO_RAW ? intel_usm_cap_raw_str : intel_usm_cap_str),
2869 /* Device queue family properties */
2871 strbuf_intel_queue_family(const char *what, struct _strbuf *str, const cl_queue_family_properties_intel *fams, size_t num_fams,
2872 const struct opt_out *output)
2874 realloc_strbuf(str, num_fams*(CL_QUEUE_FAMILY_MAX_NAME_SIZE_INTEL + 512), "queue families");
2876 strbuf_append_str(what, str, "{");
2878 for (size_t i = 0; i < num_fams; ++i) {
2879 const cl_queue_family_properties_intel *fam = fams + i;
2880 set_separator(output->mode == CLINFO_HUMAN ? full_padding : output->json ? comma_str : spc_str);
2881 if (i > 0) strbuf_append_str(what, str, sep);
2882 if (output->json || output->mode == CLINFO_HUMAN) {
2883 strbuf_append(what, str,
2885 "\"%s\" : { \"count\" : %u" :
2887 fam->name, fam->count);
2889 strbuf_append(what, str, "%s:%u:", fam->name, fam->count);
2893 strbuf_append(what, str, ", \"proprerties\" : ");
2894 else if (output->mode == CLINFO_HUMAN)
2895 strbuf_append(what, str, "\n%115s", "Queue properties" INDENT);
2896 strbuf_bitfield(what, str, fam->properties, "properties",
2897 output->mode == CLINFO_RAW ? queue_prop_raw_str : queue_prop_str,
2898 queue_prop_count, output);
2901 strbuf_append(what, str, ", \"capabilities\" : ");
2902 else if (output->mode == CLINFO_HUMAN)
2903 strbuf_append(what, str, "\n%115s", "Capabilities" INDENT);
2904 else strbuf_append(what, str, ":");
2905 strbuf_bitfield(what, str, fam->properties, "capabilities",
2906 output->mode == CLINFO_RAW ? intel_queue_cap_raw_str : intel_queue_cap_str,
2907 intel_queue_cap_count, output);
2909 strbuf_append(what, str, "}");
2912 strbuf_append_str(what, str, " }");
2916 device_info_qfamily_prop(struct device_info_ret *ret,
2917 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2918 const struct opt_out *output)
2920 cl_queue_family_properties_intel *val = NULL;
2921 size_t szval = 0, numval = 0;
2922 GET_VAL_ARRAY(ret, loc);
2924 strbuf_intel_queue_family(loc->pname, &ret->str, val, numval, output);
2925 // TODO: ret->value.??? = val;
2931 /* Execution capabilities */
2933 device_info_execap(struct device_info_ret *ret,
2934 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2935 const struct opt_out *output)
2937 GET_VAL(ret, loc, execap);
2939 const char * const *qpstr = (output->mode == CLINFO_HUMAN ?
2940 execap_str : execap_raw_str);
2942 if (output->mode != CLINFO_HUMAN) {
2943 device_info_bitfield(ret, loc, chk, output, ret->value.execap,
2944 execap_count, qpstr, "type");
2945 } else { /* output->mode == CLINFO_HUMAN */
2946 for (cl_uint i = 0; i < execap_count; ++i) {
2947 cl_device_exec_capabilities cur = (cl_device_exec_capabilities)(1) << i;
2948 cl_bool present =!!(ret->value.execap & cur);
2949 strbuf_append(loc->pname, &ret->str, "\n%s" I2_STR "%s",
2950 line_pfx, qpstr[i], bool_str[present]);
2956 /* Arch bits and endianness (HUMAN) */
2958 device_info_arch(struct device_info_ret *ret,
2959 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
2960 const struct opt_out *output)
2962 struct info_loc loc2 = *loc;
2963 DEV_FETCH(cl_uint, bits);
2964 RESET_LOC_PARAM(loc2, dev, CL_DEVICE_ENDIAN_LITTLE);
2966 DEV_FETCH_LOC(cl_bool, val, &loc2);
2968 strbuf_append(loc->pname, &ret->str, "%" PRIu32 ", %s", bits, endian_str[val]);
2973 /* SVM capabilities */
2975 device_info_svm_cap(struct device_info_ret *ret,
2976 const struct info_loc *loc, const struct device_info_checks *chk,
2977 const struct opt_out *output)
2979 const cl_bool is_20 = dev_is_20(chk);
2980 const cl_bool checking_core = (loc->param.dev == CL_DEVICE_SVM_CAPABILITIES);
2981 const cl_bool has_amd_svm = (checking_core && dev_has_amd_svm(chk));
2982 GET_VAL(ret, loc, svmcap);
2985 const char * const *scstr = (output->mode == CLINFO_HUMAN ?
2986 svm_cap_str : svm_cap_raw_str);
2988 if (output->mode != CLINFO_HUMAN) {
2989 device_info_bitfield(ret, loc, chk, output, ret->value.svmcap,
2990 svm_cap_count, scstr, "capabilities");
2991 } else { /* output->mode == CLINFO_HUMAN */
2992 if (checking_core) {
2993 /* show 'why' it's being shown */
2994 strbuf_append(loc->pname, &ret->str, "(%s%s%s)",
2995 (is_20 ? core : empty_str),
2996 (is_20 && has_amd_svm ? comma_str : empty_str),
2999 for (cl_uint i = 0; i < svm_cap_count; ++i) {
3000 cl_device_svm_capabilities cur = (cl_device_svm_capabilities)(1) << i;
3001 cl_bool present = !!(ret->value.svmcap & cur);
3002 strbuf_append(loc->pname, &ret->str, "\n%s" I2_STR "%s",
3003 line_pfx, scstr[i], bool_str[present]);
3009 /* Device terminate capability */
3011 device_info_terminate_capability(struct device_info_ret *ret,
3012 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3013 const struct opt_out *output)
3015 GET_VAL(ret, loc, termcap);
3018 device_info_bitfield(ret, loc, chk, output, ret->value.termcap,
3019 terminate_capability_count, (output->mode == CLINFO_HUMAN ?
3020 terminate_capability_str : terminate_capability_raw_str),
3025 /* Device terminate capability */
3027 device_info_terminate_arm(struct device_info_ret *ret,
3028 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3029 const struct opt_out *output)
3031 GET_VAL(ret, loc, termcap);
3034 device_info_bitfield(ret, loc, chk, output, ret->value.termcap,
3035 terminate_capability_arm_count, (output->mode == CLINFO_HUMAN ?
3036 terminate_capability_arm_str : terminate_capability_arm_raw_str),
3042 /* ARM scheduling controls */
3044 device_info_arm_scheduling_controls(struct device_info_ret *ret,
3045 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3046 const struct opt_out *output)
3048 GET_VAL(ret, loc, sched_controls);
3051 device_info_bitfield(ret, loc, chk, output, ret->value.sched_controls,
3052 arm_scheduling_controls_count, (output->mode == CLINFO_HUMAN ?
3053 arm_scheduling_controls_str : arm_scheduling_controls_raw_str),
3054 "scheduling controls");
3059 device_info_p2p_dev_list(struct device_info_ret *ret,
3060 const struct info_loc *loc, const struct device_info_checks *chk,
3061 const struct opt_out* UNUSED(output))
3063 // Contrary to most array values in OpenCL, the AMD platform does not support querying
3064 // CL_DEVICE_P2P_DEVICES_AMD with a NULL ptr to get the number of results.
3065 // The user is assumed to have queried for the CL_DEVICE_NUM_P2P_DEVICES_AMD first,
3066 // and to have allocated the return array beforehand.
3067 cl_device_id *val = NULL;
3068 size_t numval = chk->p2p_num_devs, szval = numval*sizeof(*val);
3069 _GET_VAL_VALUES(ret, loc);
3072 strbuf_append_str_len(loc->pname, &ret->str, "[ ", 2);
3073 set_common_separator(output);
3074 for (cursor = 0; cursor < numval; ++cursor) {
3075 strbuf_append(loc->pname, &ret->str, "%s%p",
3076 (cursor > 0 ? sep : ""), (void*)val[cursor]);
3078 strbuf_append_str_len(loc->pname, &ret->str, " ]", 2);
3079 // TODO: ret->value.??? = val;
3085 device_info_interop_list(struct device_info_ret *ret,
3086 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3087 const struct opt_out *output)
3089 cl_uint *val = NULL;
3090 size_t szval = 0, numval = 0;
3091 GET_VAL_ARRAY(ret, loc);
3094 const cl_interop_name *interop_name_end = cl_interop_names + num_known_interops;
3095 cl_uint human_raw = output->mode - CLINFO_HUMAN;
3096 const char *groupsep = (output->mode == CLINFO_HUMAN ? comma_str : vbar_str);
3097 cl_bool first = CL_TRUE;
3099 for (cursor = 0; cursor < numval; ++cursor) {
3100 cl_uint current = val[cursor];
3101 if (!current && cursor < numval - 1) {
3102 /* A null value is used as group terminator, but we only print it
3103 * if it's not the final one
3105 strbuf_append_str(loc->pname, &ret->str, groupsep);
3109 cl_bool found = CL_FALSE;
3110 const cl_interop_name *n = cl_interop_names;
3113 strbuf_append_str(loc->pname, &ret->str, " ");
3116 while (n < interop_name_end) {
3117 if (current >= n->from && current <= n->to) {
3124 cl_uint i = current - n->from;
3125 strbuf_append(loc->pname, &ret->str, "%s", n->value[i][human_raw]);
3127 strbuf_append(loc->pname, &ret->str, "%#" PRIx32, val[cursor]);
3132 // TODO: ret->value.??? = val;
3135 ret->needs_escaping = CL_TRUE;
3139 void device_info_uuid(struct device_info_ret *ret,
3140 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3141 const struct opt_out *output)
3143 cl_uchar uuid[CL_UUID_SIZE_KHR];
3144 _GET_VAL(ret, loc, uuid);
3146 strbuf_append(loc->pname, &ret->str,
3151 "%02x%02x%02x%02x%02x%02x",
3152 uuid[0], uuid[1], uuid[2], uuid[3], uuid[4],
3156 uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]);
3158 ret->needs_escaping = CL_TRUE;
3161 void device_info_luid(struct device_info_ret *ret,
3162 const struct info_loc *loc, const struct device_info_checks* UNUSED(chk),
3163 const struct opt_out *output)
3165 cl_uchar uuid[CL_LUID_SIZE_KHR];
3166 _GET_VAL(ret, loc, uuid);
3168 /* TODO not sure this is the correct representation for LUIDs? */
3169 strbuf_append(loc->pname, &ret->str, "%02x%02x-%02x%02x%02x%02x%02x%02x",
3171 uuid[2], uuid[3], uuid[4], uuid[5], uuid[6], uuid[7]);
3173 ret->needs_escaping = CL_TRUE;
3178 * Device info traits
3181 /* A CL_FALSE param means "just print pname" */
3183 struct device_info_traits {
3184 enum output_modes output_mode;
3185 cl_device_info param; // CL_DEVICE_*
3186 const char *sname; // "CL_DEVICE_*"
3187 const char *pname; // "Device *"
3188 const char *sfx; // suffix for the output in non-raw mode
3189 /* pointer to function that retrieves the parameter */
3190 void (*show_func)(struct device_info_ret *,
3191 const struct info_loc *, const struct device_info_checks *,
3192 const struct opt_out *);
3193 /* pointer to function that checks if the parameter should be retrieved */
3194 cl_bool (*check_func)(const struct device_info_checks *);
3197 #define DINFO_SFX(symbol, name, sfx, typ) symbol, #symbol, name, sfx, device_info_##typ
3198 #define DINFO(symbol, name, typ) symbol, #symbol, name, NULL, device_info_##typ
3200 struct device_info_traits dinfo_traits[] = {
3201 { CLINFO_BOTH, DINFO(CL_DEVICE_NAME, "Device Name", str), NULL },
3202 { CLINFO_BOTH, DINFO(CL_DEVICE_VENDOR, "Device Vendor", str), NULL },
3203 { CLINFO_BOTH, DINFO(CL_DEVICE_VENDOR_ID, "Device Vendor ID", hex), NULL },
3204 { CLINFO_BOTH, DINFO(CL_DEVICE_VERSION, "Device Version", str), NULL },
3206 /* This has to be made before calling NUMERIC_VERSION , since to know if it's supported
3207 * we need to know about the extensions */
3208 { CLINFO_BOTH, DINFO(CL_DEVICE_EXTENSIONS, "Device Extensions", str), NULL },
3209 { CLINFO_BOTH, DINFO(CL_DEVICE_EXTENSIONS_WITH_VERSION, "Device Extensions with Version", ext_version), dev_has_ext_ver },
3211 { CLINFO_BOTH, DINFO(CL_DEVICE_UUID_KHR, "Device UUID", uuid), dev_has_device_uuid },
3212 { CLINFO_BOTH, DINFO(CL_DRIVER_UUID_KHR, "Driver UUID", uuid), dev_has_device_uuid },
3213 { CLINFO_BOTH, DINFO(CL_DEVICE_LUID_VALID_KHR, "Valid Device LUID", bool), dev_has_device_uuid },
3214 { CLINFO_BOTH, DINFO(CL_DEVICE_LUID_KHR, "Device LUID", luid), dev_has_device_uuid },
3215 { CLINFO_BOTH, DINFO(CL_DEVICE_NODE_MASK_KHR, "Device Node Mask", hex), dev_has_device_uuid },
3217 { CLINFO_BOTH, DINFO(CL_DEVICE_NUMERIC_VERSION, "Device Numeric Version", version), dev_has_ext_ver },
3218 { CLINFO_BOTH, DINFO(CL_DRIVER_VERSION, "Driver Version", str), NULL },
3219 { CLINFO_BOTH, DINFO(CL_DEVICE_OPENCL_C_VERSION, "Device OpenCL C Version", str), dev_is_11 },
3220 { CLINFO_BOTH, DINFO(CL_DEVICE_OPENCL_C_NUMERIC_VERSION_KHR, "Device OpenCL C Numeric Version", version), dev_has_extended_versioning },
3221 { CLINFO_BOTH, DINFO(CL_DEVICE_OPENCL_C_ALL_VERSIONS, "Device OpenCL C all versions", ext_version), dev_is_30 },
3222 { CLINFO_BOTH, DINFO(CL_DEVICE_OPENCL_C_FEATURES, "Device OpenCL C features", ext_version), dev_is_30 },
3224 { CLINFO_BOTH, DINFO(CL_DEVICE_CXX_FOR_OPENCL_NUMERIC_VERSION_EXT, "Device C++ for OpenCL Numeric Version", version), dev_has_cxx_for_opencl },
3226 { CLINFO_BOTH, DINFO(CL_DEVICE_LATEST_CONFORMANCE_VERSION_PASSED, "Latest conformance test passed", str), dev_is_30 },
3227 { CLINFO_BOTH, DINFO(CL_DEVICE_TYPE, "Device Type", devtype), NULL },
3229 { CLINFO_BOTH, DINFO(CL_DEVICE_BOARD_NAME_AMD, "Device Board Name (AMD)", str), dev_has_amd },
3230 { CLINFO_BOTH, DINFO(CL_DEVICE_PCIE_ID_AMD, "Device PCI-e ID (AMD)", hex), dev_is_gpu_amd },
3231 { CLINFO_BOTH, DINFO(CL_DEVICE_TOPOLOGY_AMD, "Device Topology (AMD)", devtopo_amd), dev_has_amd },
3233 /* Device Topology (NV) is multipart, so different for HUMAN and RAW */
3234 { CLINFO_HUMAN, DINFO(CL_DEVICE_PCI_BUS_ID_NV, "Device Topology (NV)", devtopo_nv), dev_has_nv },
3235 { CLINFO_RAW, DINFO(CL_DEVICE_PCI_BUS_ID_NV, "Device PCI bus (NV)", int), dev_has_nv },
3236 { CLINFO_RAW, DINFO(CL_DEVICE_PCI_SLOT_ID_NV, "Device PCI slot (NV)", int), dev_has_nv },
3237 { CLINFO_RAW, DINFO(CL_DEVICE_PCI_DOMAIN_ID_NV, "Device PCI domain (NV)", int), dev_has_nv },
3239 /* Device Topology / PCI bus info (KHR) */
3240 { CLINFO_BOTH, DINFO(CL_DEVICE_PCI_BUS_INFO_KHR, "Device PCI bus info (KHR)", devtopo_khr), dev_has_pci_bus_info },
3242 { CLINFO_BOTH, DINFO(CL_DEVICE_PROFILE, "Device Profile", str), NULL },
3243 { CLINFO_BOTH, DINFO(CL_DEVICE_AVAILABLE, "Device Available", bool), NULL },
3244 { CLINFO_BOTH, DINFO(CL_DEVICE_COMPILER_AVAILABLE, "Compiler Available", bool), NULL },
3245 { CLINFO_BOTH, DINFO(CL_DEVICE_LINKER_AVAILABLE, "Linker Available", bool), dev_is_12 },
3247 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_COMPUTE_UNITS, "Max compute units", int), NULL },
3248 { CLINFO_HUMAN, DINFO(CL_DEVICE_COMPUTE_UNITS_BITFIELD_ARM, "Available core IDs (ARM)", core_ids), dev_has_arm_core_id_v2 },
3249 { CLINFO_RAW, DINFO(CL_DEVICE_COMPUTE_UNITS_BITFIELD_ARM, "Available core IDs (ARM)", long), dev_has_arm_core_id_v2 },
3250 { CLINFO_HUMAN, DINFO(CL_DEVICE_JOB_SLOTS_ARM, "Available job slots (ARM)", job_slots), dev_has_arm_job_slots },
3251 { CLINFO_RAW, DINFO(CL_DEVICE_JOB_SLOTS_ARM, "Available job slots (ARM)", int), dev_has_arm_job_slots },
3252 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, "SIMD per compute unit (AMD)", int), dev_is_gpu_amd },
3253 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_WIDTH_AMD, "SIMD width (AMD)", int), dev_is_gpu_amd },
3254 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, "SIMD instruction width (AMD)", int), dev_is_gpu_amd },
3255 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_MAX_CLOCK_FREQUENCY, "Max clock frequency", "MHz", int), NULL },
3257 /* Device Compute Capability (NV) is multipart, so different for HUMAN and RAW */
3258 { CLINFO_HUMAN, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, "Compute Capability (NV)", cc_nv), dev_has_nv },
3259 { CLINFO_RAW, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, INDENT "Compute Capability Major (NV)", int), dev_has_nv },
3260 { CLINFO_RAW, DINFO(CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, INDENT "Compute Capability Minor (NV)", int), dev_has_nv },
3262 /* GFXIP (AMD) is multipart, so different for HUMAN and RAW */
3263 /* TODO: find a better human-friendly name than GFXIP; v3 of the cl_amd_device_attribute_query
3264 * extension specification calls it “core engine GFXIP”, which honestly is not better than
3265 * our name choice. */
3266 { CLINFO_HUMAN, DINFO(CL_DEVICE_GFXIP_MAJOR_AMD, "Graphics IP (AMD)", gfxip_amd), dev_is_gpu_amd },
3267 { CLINFO_RAW, DINFO(CL_DEVICE_GFXIP_MAJOR_AMD, INDENT "Graphics IP MAJOR (AMD)", int), dev_is_gpu_amd },
3268 { CLINFO_RAW, DINFO(CL_DEVICE_GFXIP_MINOR_AMD, INDENT "Graphics IP MINOR (AMD)", int), dev_is_gpu_amd },
3270 /* Device IP version (Intel) */
3271 { CLINFO_BOTH, DINFO(CL_DEVICE_IP_VERSION_INTEL, "Device IP (Intel)", version), dev_is_gpu_intel },
3272 { CLINFO_BOTH, DINFO(CL_DEVICE_ID_INTEL, "Device ID (Intel)", int), dev_is_gpu_intel },
3273 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_SLICES_INTEL, "Slices (Intel)", int), dev_is_gpu_intel },
3274 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_SUB_SLICES_PER_SLICE_INTEL, "Sub-slices per slice (Intel)", int), dev_is_gpu_intel },
3275 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_EUS_PER_SUB_SLICE_INTEL, "EUs per sub-slice (Intel)", int), dev_is_gpu_intel },
3276 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_THREADS_PER_EU_INTEL, "Threads per EU (Intel)", int), dev_is_gpu_intel },
3277 { CLINFO_BOTH, DINFO(CL_DEVICE_FEATURE_CAPABILITIES_INTEL, "Feature capabilities (Intel)", intel_features), dev_is_gpu_intel },
3279 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_CORE_TEMPERATURE_ALTERA, "Core Temperature (Altera)", " C", int), dev_has_altera_dev_temp },
3281 /* Device partition support: summary is only presented in HUMAN case */
3282 { CLINFO_HUMAN, DINFO(CL_DEVICE_PARTITION_MAX_SUB_DEVICES, "Device Partition", partition_header), dev_has_partition },
3283 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_MAX_SUB_DEVICES, INDENT "Max number of sub-devices", int), dev_is_12 },
3284 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_PROPERTIES, INDENT "Supported partition types", partition_types), dev_is_12 },
3285 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_AFFINITY_DOMAIN, INDENT "Supported affinity domains", partition_affinities), dev_is_12 },
3286 { CLINFO_BOTH, DINFO(CL_DEVICE_PARTITION_TYPES_EXT, INDENT "Supported partition types (ext)", partition_types_ext), dev_has_fission },
3287 { CLINFO_BOTH, DINFO(CL_DEVICE_AFFINITY_DOMAINS_EXT, INDENT "Supported affinity domains (ext)", partition_affinities_ext), dev_has_fission },
3289 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, "Max work item dimensions", int), NULL },
3290 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_ITEM_SIZES, "Max work item sizes", szptr_times), NULL },
3291 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_GROUP_SIZE, "Max work group size", sz), NULL },
3293 /* cl_amd_device_attribute_query v4 */
3294 { CLINFO_BOTH, DINFO(CL_DEVICE_PREFERRED_WORK_GROUP_SIZE_AMD, "Preferred work group size (AMD)", sz), dev_has_amd_v4 },
3295 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WORK_GROUP_SIZE_AMD, "Max work group size (AMD)", sz), dev_has_amd_v4 },
3297 { CLINFO_BOTH, DINFO(CL_DEVICE_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, "Preferred work group size multiple (device)", sz), dev_is_30 },
3298 { CLINFO_BOTH, DINFO(CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, "Preferred work group size multiple (kernel)", wg), dev_has_compiler_11 },
3299 { CLINFO_BOTH, DINFO(CL_DEVICE_WARP_SIZE_NV, "Warp size (NV)", int), dev_has_nv },
3300 { CLINFO_BOTH, DINFO(CL_DEVICE_WAVEFRONT_WIDTH_AMD, "Wavefront width (AMD)", int), dev_is_gpu_amd },
3301 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_NUM_SUB_GROUPS, "Max sub-groups per work group", int), dev_is_21 },
3302 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_NAMED_BARRIER_COUNT_KHR, "Max named sub-group barriers", int), dev_has_subgroup_named_barrier },
3303 { CLINFO_BOTH, DINFO(CL_DEVICE_SUB_GROUP_SIZES_INTEL, "Sub-group sizes (Intel)", szptr_comma), dev_has_intel_required_subgroup_size },
3305 /* Preferred/native vector widths: header is only presented in HUMAN case, that also pairs
3306 * PREFERRED and NATIVE in a single line */
3307 #define DINFO_VECWIDTH(Type, type) \
3308 { CLINFO_HUMAN, DINFO(CL_DEVICE_PREFERRED_VECTOR_WIDTH_##Type, INDENT #type, vecwidth), NULL }, \
3309 { CLINFO_RAW, DINFO(CL_DEVICE_PREFERRED_VECTOR_WIDTH_##Type, INDENT #type, int), NULL }, \
3310 { CLINFO_RAW, DINFO(CL_DEVICE_NATIVE_VECTOR_WIDTH_##Type, INDENT #type, int), dev_is_11 }
3312 { CLINFO_HUMAN, DINFO(CL_FALSE, "Preferred / native vector sizes", str), NULL },
3313 DINFO_VECWIDTH(CHAR, char),
3314 DINFO_VECWIDTH(SHORT, short),
3315 DINFO_VECWIDTH(INT, int),
3316 DINFO_VECWIDTH(LONG, long),
3317 DINFO_VECWIDTH(HALF, half), /* this should be excluded for 1.0 */
3318 DINFO_VECWIDTH(FLOAT, float),
3319 DINFO_VECWIDTH(DOUBLE, double),
3321 /* Floating point configurations */
3322 #define DINFO_FPCONF(Type, type, cond) \
3323 { CLINFO_HUMAN, DINFO(CL_DEVICE_##Type##_FP_CONFIG, #type "-precision Floating-point support", fpconf), NULL }, \
3324 { CLINFO_RAW, DINFO(CL_DEVICE_##Type##_FP_CONFIG, #type "-precision Floating-point support", fpconf), cond }
3326 DINFO_FPCONF(HALF, Half, dev_has_half),
3327 DINFO_FPCONF(SINGLE, Single, NULL),
3328 DINFO_FPCONF(DOUBLE, Double, dev_has_double),
3330 /* Address bits and endianness are written together for HUMAN, separate for RAW */
3331 { CLINFO_HUMAN, DINFO(CL_DEVICE_ADDRESS_BITS, "Address bits", arch), NULL },
3332 { CLINFO_RAW, DINFO(CL_DEVICE_ADDRESS_BITS, "Address bits", int), NULL },
3333 { CLINFO_RAW, DINFO(CL_DEVICE_ENDIAN_LITTLE, "Little Endian", bool), NULL },
3335 /* External memory */
3336 { CLINFO_BOTH, DINFO(CL_DEVICE_EXTERNAL_MEMORY_IMPORT_HANDLE_TYPES_KHR, "External memory handle types", ext_mem), dev_has_external_memory },
3339 { CLINFO_BOTH, DINFO(CL_DEVICE_SEMAPHORE_TYPES_KHR, "Semaphore types", semaphore_types), dev_has_semaphore },
3340 { CLINFO_BOTH, DINFO(CL_DEVICE_SEMAPHORE_IMPORT_HANDLE_TYPES_KHR, "External semaphore import types", ext_semaphore_handles), dev_has_external_semaphore },
3341 { CLINFO_BOTH, DINFO(CL_DEVICE_SEMAPHORE_EXPORT_HANDLE_TYPES_KHR, "External semaphore export types", ext_semaphore_handles), dev_has_external_semaphore },
3344 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_SIZE, "Global memory size", mem), NULL },
3345 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, "Global free memory (AMD)", free_mem_amd), dev_is_gpu_amd },
3346 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, "Global memory channels (AMD)", int), dev_is_gpu_amd },
3347 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, "Global memory banks per channel (AMD)", int), dev_is_gpu_amd },
3348 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, "Global memory bank width (AMD)", bytes_str, int), dev_is_gpu_amd },
3349 { CLINFO_BOTH, DINFO(CL_DEVICE_ERROR_CORRECTION_SUPPORT, "Error Correction support", bool), NULL },
3350 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_MEM_ALLOC_SIZE, "Max memory allocation", mem), NULL },
3351 { CLINFO_BOTH, DINFO(CL_DEVICE_HOST_UNIFIED_MEMORY, "Unified memory for Host and Device", bool), dev_is_11 },
3352 { CLINFO_BOTH, DINFO(CL_DEVICE_INTEGRATED_MEMORY_NV, "Integrated memory (NV)", bool), dev_has_nv },
3354 { CLINFO_BOTH, DINFO(CL_DEVICE_SVM_CAPABILITIES, "Shared Virtual Memory (SVM) capabilities", svm_cap), dev_has_svm },
3355 { CLINFO_BOTH, DINFO(CL_DEVICE_SVM_CAPABILITIES_ARM, "Shared Virtual Memory (SVM) capabilities (ARM)", svm_cap), dev_has_arm_svm },
3357 { CLINFO_HUMAN, DINFO_SFX(CL_FALSE, "Unified Shared Memory (USM)", "(cl_intel_unified_shared_memory)", str), dev_has_intel_usm },
3358 { CLINFO_BOTH, DINFO(CL_DEVICE_HOST_MEM_CAPABILITIES_INTEL, "Host USM capabilities (Intel)", intel_usm_cap), dev_has_intel_usm },
3359 { CLINFO_BOTH, DINFO(CL_DEVICE_DEVICE_MEM_CAPABILITIES_INTEL, "Device USM capabilities (Intel)", intel_usm_cap), dev_has_intel_usm },
3360 { CLINFO_BOTH, DINFO(CL_DEVICE_SINGLE_DEVICE_SHARED_MEM_CAPABILITIES_INTEL, "Single-Device USM caps (Intel)", intel_usm_cap), dev_has_intel_usm },
3361 { CLINFO_BOTH, DINFO(CL_DEVICE_CROSS_DEVICE_SHARED_MEM_CAPABILITIES_INTEL, "Cross-Device USM caps (Intel)", intel_usm_cap), dev_has_intel_usm },
3362 { CLINFO_BOTH, DINFO(CL_DEVICE_SHARED_SYSTEM_MEM_CAPABILITIES_INTEL, "Shared System USM caps (Intel)", intel_usm_cap), dev_has_intel_usm },
3365 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, "Minimum alignment for any data type", bytes_str, int), NULL },
3366 { CLINFO_HUMAN, DINFO(CL_DEVICE_MEM_BASE_ADDR_ALIGN, "Alignment of base address", bits), NULL },
3367 { CLINFO_RAW, DINFO(CL_DEVICE_MEM_BASE_ADDR_ALIGN, "Alignment of base address", int), NULL },
3369 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PAGE_SIZE_QCOM, "Page size (QCOM)", bytes_str, sz), dev_has_qcom_ext_host_ptr },
3370 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_EXT_MEM_PADDING_IN_BYTES_QCOM, "External memory padding (QCOM)", bytes_str, sz), dev_has_qcom_ext_host_ptr },
3372 /* Atomics alignment, with HUMAN-only header */
3373 { CLINFO_HUMAN, DINFO(CL_FALSE, "Preferred alignment for atomics", str), dev_is_20 },
3374 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT, INDENT "SVM", bytes_str, int), dev_is_20 },
3375 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT, INDENT "Global", bytes_str, int), dev_is_20 },
3376 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT, INDENT "Local", bytes_str, int), dev_is_20 },
3378 /* 3.0+ Atomic memory and fence capabilities */
3379 { CLINFO_BOTH, DINFO(CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES, "Atomic memory capabilities", atomic_caps), dev_is_30 },
3380 { CLINFO_BOTH, DINFO(CL_DEVICE_ATOMIC_FENCE_CAPABILITIES, "Atomic fence capabilities", atomic_caps), dev_is_30 },
3382 /* Global variables. TODO some 1.2 devices respond to this too */
3383 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, "Max size for global variable", mem), dev_is_20 },
3384 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, "Preferred total size of global vars", mem), dev_is_20 },
3386 /* Global memory cache */
3387 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, "Global Memory cache type", cachetype), NULL },
3388 { CLINFO_BOTH, DINFO(CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, "Global Memory cache size", mem), dev_has_cache },
3389 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, "Global Memory cache line size", " bytes", int), dev_has_cache },
3392 { CLINFO_BOTH, DINFO(CL_DEVICE_IMAGE_SUPPORT, "Image support", bool), NULL },
3393 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_SAMPLERS, INDENT "Max number of samplers per kernel", int), dev_has_images },
3394 { 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 },
3395 { 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 },
3396 { 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 },
3397 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_IMAGE_PITCH_ALIGNMENT, INDENT "Pitch alignment for 2D image buffers", pixels_str, sz), dev_has_image2d_buffer },
3399 /* Image dimensions are split for RAW, combined for HUMAN */
3400 { CLINFO_HUMAN, DINFO_SFX(CL_DEVICE_IMAGE2D_MAX_HEIGHT, INDENT "Max 2D image size", pixels_str, img_sz_2d), dev_has_images },
3401 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE2D_MAX_HEIGHT, INDENT "Max 2D image height", sz), dev_has_images },
3402 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE2D_MAX_WIDTH, INDENT "Max 2D image width", sz), dev_has_images },
3403 { 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 },
3404 { CLINFO_RAW, DINFO(CL_DEVICE_PLANAR_YUV_MAX_HEIGHT_INTEL, INDENT "Max planar YUV image height", sz), dev_has_intel_planar_yuv },
3405 { CLINFO_RAW, DINFO(CL_DEVICE_PLANAR_YUV_MAX_WIDTH_INTEL, INDENT "Max planar YUV image width", sz), dev_has_intel_planar_yuv },
3406 { CLINFO_HUMAN, DINFO_SFX(CL_DEVICE_IMAGE3D_MAX_HEIGHT, INDENT "Max 3D image size", pixels_str, img_sz_3d), dev_has_images },
3407 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_HEIGHT, INDENT "Max 3D image height", sz), dev_has_images },
3408 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_WIDTH, INDENT "Max 3D image width", sz), dev_has_images },
3409 { CLINFO_RAW, DINFO(CL_DEVICE_IMAGE3D_MAX_DEPTH, INDENT "Max 3D image depth", sz), dev_has_images },
3411 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_READ_IMAGE_ARGS, INDENT "Max number of read image args", int), dev_has_images },
3412 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WRITE_IMAGE_ARGS, INDENT "Max number of write image args", int), dev_has_images },
3413 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, INDENT "Max number of read/write image args", int), dev_has_images_20 },
3416 { CLINFO_BOTH, DINFO(CL_DEVICE_PIPE_SUPPORT, "Pipe support", bool), dev_is_30 },
3417 /* TODO FIXME: the above should be true if dev is [2.0, 3.0[, and the next properties should be nested */
3418 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_PIPE_ARGS, "Max number of pipe args", int), dev_is_20 },
3419 { CLINFO_BOTH, DINFO(CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS, "Max active pipe reservations", int), dev_is_20 },
3420 { CLINFO_BOTH, DINFO(CL_DEVICE_PIPE_MAX_PACKET_SIZE, "Max pipe packet size", mem_int), dev_is_20 },
3423 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_TYPE, "Local memory type", lmemtype), NULL },
3424 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_SIZE, "Local memory size", mem), dev_has_lmem },
3425 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, "Local memory size per CU (AMD)", mem), dev_is_gpu_amd },
3426 { CLINFO_BOTH, DINFO(CL_DEVICE_LOCAL_MEM_BANKS_AMD, "Local memory banks (AMD)", int), dev_is_gpu_amd },
3427 { CLINFO_BOTH, DINFO(CL_DEVICE_REGISTERS_PER_BLOCK_NV, "Registers per block (NV)", int), dev_has_nv },
3429 /* Constant memory */
3430 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_CONSTANT_ARGS, "Max number of constant args", int), NULL },
3431 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, "Max constant buffer size", mem), NULL },
3432 { CLINFO_BOTH, DINFO(CL_DEVICE_PREFERRED_CONSTANT_BUFFER_SIZE_AMD, "Preferred constant buffer size (AMD)", mem_sz), dev_has_amd_v4 },
3434 /* Generic address space support */
3435 { CLINFO_BOTH, DINFO(CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT, "Generic address space support", bool), dev_is_30},
3437 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_PARAMETER_SIZE, "Max size of kernel argument", mem), NULL },
3438 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ATOMIC_COUNTERS_EXT, "Max number of atomic counters", sz), dev_has_atomic_counters },
3440 /* Queue properties */
3441 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_PROPERTIES, "Queue properties", qprop), dev_not_20 },
3442 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_HOST_PROPERTIES, "Queue properties (on host)", qprop), dev_is_20 },
3443 { CLINFO_BOTH, DINFO(CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, "Device enqueue capabilities", device_enqueue_caps), dev_is_30 },
3444 /* TODO FIXME: the above should be true if dev is [2.0, 3.0[, and the next properties should be nested */
3445 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, "Queue properties (on device)", qprop), dev_is_20 },
3446 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE, INDENT "Preferred size", mem), dev_is_20 },
3447 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, INDENT "Max size", mem), dev_is_20 },
3448 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ON_DEVICE_QUEUES, "Max queues on device", int), dev_is_20 },
3449 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_ON_DEVICE_EVENTS, "Max events on device", int), dev_is_20 },
3450 { CLINFO_BOTH, DINFO(CL_DEVICE_QUEUE_FAMILY_PROPERTIES_INTEL, "Device queue families", qfamily_prop), dev_has_intel_queue_families },
3452 /* Command buffers */
3453 { CLINFO_BOTH, DINFO(CL_DEVICE_COMMAND_BUFFER_CAPABILITIES_KHR, "Command buffer capabilities", command_buffer_caps), dev_has_command_buffer },
3454 { CLINFO_BOTH, DINFO(CL_DEVICE_COMMAND_BUFFER_REQUIRED_QUEUE_PROPERTIES_KHR, INDENT "Required queue properties for command buffer", qprop), dev_has_command_buffer },
3455 { CLINFO_BOTH, DINFO(CL_DEVICE_MUTABLE_DISPATCH_CAPABILITIES_KHR, "Mutable dispatch capabilities", mutable_dispatch_caps), dev_has_mutable_dispatch },
3457 /* Terminate context */
3458 { CLINFO_BOTH, DINFO(CL_DEVICE_TERMINATE_CAPABILITY_KHR_1x, "Terminate capability (1.2 define)", terminate_capability), dev_has_terminate_context },
3459 { CLINFO_BOTH, DINFO(CL_DEVICE_TERMINATE_CAPABILITY_KHR, "Terminate capability (2.x and later)", terminate_capability), dev_has_terminate_context },
3461 { CLINFO_BOTH, DINFO(CL_DEVICE_CONTROLLED_TERMINATION_CAPABILITIES_ARM, "Controlled termination caps. (ARM)", terminate_arm), dev_has_terminate_arm },
3464 { CLINFO_BOTH, DINFO(CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, "Prefer user sync for interop", bool), dev_is_12 },
3465 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_SIMULTANEOUS_INTEROPS_INTEL, "Number of simultaneous interops (Intel)", int), dev_has_simultaneous_sharing },
3466 { CLINFO_BOTH, DINFO(CL_DEVICE_SIMULTANEOUS_INTEROPS_INTEL, "Simultaneous interops", interop_list), dev_has_simultaneous_sharing },
3468 /* P2P buffer copy */
3469 { CLINFO_BOTH, DINFO(CL_DEVICE_NUM_P2P_DEVICES_AMD, "Number of P2P devices (AMD)", int), dev_has_p2p },
3470 { CLINFO_BOTH, DINFO(CL_DEVICE_P2P_DEVICES_AMD, "P2P devices (AMD)", p2p_dev_list), dev_has_p2p_devs },
3472 /* Profiling resolution */
3473 { CLINFO_BOTH, DINFO_SFX(CL_DEVICE_PROFILING_TIMER_RESOLUTION, "Profiling timer resolution", "ns", sz), NULL },
3474 { CLINFO_HUMAN, DINFO(CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, "Profiling timer offset since Epoch (AMD)", time_offset), dev_has_amd },
3475 { CLINFO_RAW, DINFO(CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, "Profiling timer offset since Epoch (AMD)", long), dev_has_amd },
3477 /* Kernel execution capabilities */
3478 { CLINFO_BOTH, DINFO(CL_DEVICE_EXECUTION_CAPABILITIES, "Execution capabilities", execap), NULL },
3479 { CLINFO_BOTH, DINFO(CL_DEVICE_NON_UNIFORM_WORK_GROUP_SUPPORT, INDENT "Non-uniform work-groups", bool), dev_is_30 },
3480 { CLINFO_BOTH, DINFO(CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT, INDENT "Work-group collective functions", bool), dev_is_30 },
3481 { CLINFO_BOTH, DINFO(CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS, INDENT "Sub-group independent forward progress", bool), dev_is_21 },
3482 { CLINFO_BOTH, DINFO(CL_DEVICE_THREAD_TRACE_SUPPORTED_AMD, INDENT "Thread trace supported (AMD)", bool), dev_is_gpu_amd },
3483 { CLINFO_BOTH, DINFO(CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, INDENT "Kernel execution timeout (NV)", bool), dev_has_nv },
3484 { CLINFO_BOTH, DINFO(CL_DEVICE_GPU_OVERLAP_NV, INDENT "Concurrent copy and kernel execution (NV)", bool), dev_has_nv },
3485 { CLINFO_BOTH, DINFO(CL_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT_NV, INDENT INDENT "Number of async copy engines", int), dev_has_nv },
3486 { CLINFO_BOTH, DINFO(CL_DEVICE_AVAILABLE_ASYNC_QUEUES_AMD, INDENT "Number of async queues (AMD)", int), dev_has_amd_v4 },
3487 /* TODO FIXME undocumented, experimental */
3488 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_REAL_TIME_COMPUTE_QUEUES_AMD, INDENT "Max real-time compute queues (AMD)", int), dev_has_amd_v4 },
3489 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_REAL_TIME_COMPUTE_UNITS_AMD, INDENT "Max real-time compute units (AMD)", int), dev_has_amd_v4 },
3491 { CLINFO_BOTH, DINFO(CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM, INDENT "Scheduling controls (ARM)", arm_scheduling_controls), dev_has_arm_scheduling_controls },
3492 { CLINFO_BOTH, DINFO(CL_DEVICE_SUPPORTED_REGISTER_ALLOCATIONS_ARM, INDENT "Supported reg allocs (ARM)", intptr), dev_has_arm_register_alloc },
3493 { CLINFO_BOTH, DINFO(CL_DEVICE_MAX_WARP_COUNT_ARM, INDENT "Max warps/CU (ARM)", int), dev_has_arm_warp_count_support },
3495 /* TODO: this should tell if it's being done due to the device being 2.1 or due to it having the extension */
3496 { CLINFO_BOTH, DINFO(CL_DEVICE_IL_VERSION, INDENT "IL version", str), dev_has_il },
3497 { CLINFO_BOTH, DINFO(CL_DEVICE_ILS_WITH_VERSION, INDENT "ILs with version", ext_version), dev_has_ext_ver },
3498 { CLINFO_BOTH, DINFO(CL_DEVICE_SPIR_VERSIONS, INDENT "SPIR versions", str), dev_has_spir },
3499 { CLINFO_BOTH, DINFO(CL_DEVICE_PRINTF_BUFFER_SIZE, "printf() buffer size", mem_sz), dev_is_12 },
3500 { CLINFO_BOTH, DINFO(CL_DEVICE_BUILT_IN_KERNELS, "Built-in kernels", str), dev_is_12 },
3501 { CLINFO_BOTH, DINFO(CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION, "Built-in kernels with version", ext_version), dev_has_ext_ver },
3502 { CLINFO_BOTH, DINFO(CL_DEVICE_ME_VERSION_INTEL, "Motion Estimation accelerator version (Intel)", int), dev_has_intel_AME },
3503 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_VERSION_INTEL, INDENT "Device-side AVC Motion Estimation version", int), dev_has_intel_AVC_ME },
3504 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_SUPPORTS_TEXTURE_SAMPLER_USE_INTEL, INDENT INDENT "Supports texture sampler use", bool), dev_has_intel_AVC_ME },
3505 { CLINFO_BOTH, DINFO(CL_DEVICE_AVC_ME_SUPPORTS_PREEMPTION_INTEL, INDENT INDENT "Supports preemption", bool), dev_has_intel_AVC_ME },
3508 /* Process all the device info in the traits, except if param_whitelist is not NULL,
3509 * in which case only those in the whitelist will be processed.
3510 * If present, the whitelist should be sorted in the order of appearance of the parameters
3511 * in the traits table, and terminated by the value CL_FALSE
3515 printDeviceInfo(cl_device_id dev, const struct platform_list *plist, cl_uint p,
3516 const cl_device_info *param_whitelist, /* list of device info to process, or NULL */
3517 const struct opt_out *output)
3519 char *extensions = NULL;
3521 char *versioned_extensions = NULL;
3523 /* pointers to the traits for CL_DEVICE_EXTENSIONS and CL_DEVICE_EXTENSIONS_WITH_VERSION */
3524 const struct device_info_traits *extensions_traits = NULL;
3525 const struct device_info_traits *versioned_extensions_traits = NULL;
3527 struct device_info_checks chk;
3528 struct device_info_ret ret;
3529 struct info_loc loc;
3531 cl_uint n = 0; /* number of device properties shown, for JSON */
3533 memset(&chk, 0, sizeof(chk));
3534 chk.pinfo_checks = plist->platform_checks + p;
3535 chk.dev_version = 10;
3537 INIT_RET(ret, "device");
3539 reset_loc(&loc, __func__);
3540 loc.plat = plist->platform[p];
3543 for (loc.line = 0; loc.line < ARRAY_SIZE(dinfo_traits); ++loc.line) {
3545 const struct device_info_traits *traits = dinfo_traits + loc.line;
3548 /* checked is true if there was no condition to check for, or if the
3549 * condition was satisfied
3551 int checked = !(traits->check_func && !traits->check_func(&chk));
3553 loc.sname = traits->sname;
3554 loc.pname = (output->mode == CLINFO_HUMAN ?
3555 traits->pname : traits->sname);
3556 loc.param.dev = traits->param;
3558 /* Whitelist check: finish if done traversing the list,
3559 * skip current param if it's not the right one
3561 if ((output->cond == COND_PROP_CHECK || output->brief) && param_whitelist) {
3562 if (*param_whitelist == CL_FALSE)
3564 if (traits->param != *param_whitelist)
3569 /* skip if it's not for this output mode */
3570 if (!(output->mode & traits->output_mode))
3573 if (output->cond == COND_PROP_CHECK && !checked)
3576 cur_sfx = (output->mode == CLINFO_HUMAN && traits->sfx) ? traits->sfx : empty_str;
3578 reset_strbuf(&ret.str);
3579 reset_strbuf(&ret.err_str);
3580 ret.needs_escaping = CL_FALSE;
3582 /* Handle headers */
3583 if (traits->param == CL_FALSE) {
3584 ret.err = CL_SUCCESS;
3585 show_strbuf(&ret.str, loc.pname, 0, ret.err);
3589 traits->show_func(&ret, &loc, &chk, output);
3591 /* Do not print this property if the user requested one and this does not match */
3592 requested = !(output->prop && strstr(loc.sname, output->prop) == NULL);
3593 if (traits->param == CL_DEVICE_EXTENSIONS) {
3594 /* make a backup of the extensions string, regardless of
3595 * errors and requested, because we need the information
3596 * to fetch further information */
3597 const char *msg = RET_BUF(ret)->buf;
3598 ext_len = strlen(msg);
3599 extensions_traits = traits;
3600 /* pad with spaces: this will make it easier to check for extension presence
3601 * without erroneously matching substrings by simply padding the extension name
3604 ALLOC(extensions, ext_len+3, "extensions");
3605 memcpy(extensions + 1, msg, ext_len);
3606 extensions[0] = ' ';
3607 extensions[ext_len+1] = ' ';
3608 extensions[ext_len+2] = '\0';
3609 } else if (traits->param == CL_DEVICE_EXTENSIONS_WITH_VERSION) {
3610 if (ret.err && !checked && output->cond != COND_PROP_SHOW)
3612 /* This will be displayed at the end, after we display the output of CL_DEVICE_EXTENSIONS */
3613 const char *msg = RET_BUF(ret)->buf;
3614 const size_t len = RET_BUF(ret)->sz;
3617 versioned_extensions_traits = traits;
3618 ALLOC(versioned_extensions, len, "versioned extensions");
3619 memcpy(versioned_extensions, msg, len);
3620 } else if (requested) {
3622 /* if there was an error retrieving the property,
3623 * skip if it wasn't expected to work and we
3624 * weren't asked to show everything regardless of
3626 if (!checked && output->cond != COND_PROP_SHOW)
3630 /* on success, but empty result, show (n/a) */
3631 if (ret.str.buf[0] == '\0') {
3632 reset_strbuf(&ret.str);
3633 strbuf_append_str(loc.pname, &ret.str, not_specified(output));
3637 printf("%s%s\n", line_pfx, RET_BUF(ret)->buf);
3638 else if (output->json)
3639 json_strbuf(RET_BUF(ret), loc.pname, n++, ret.err || ret.needs_escaping);
3641 show_strbuf(RET_BUF(ret), loc.pname, 0, ret.err);
3647 switch (traits->param) {
3648 case CL_DEVICE_VERSION:
3649 /* compute numeric value for OpenCL version */
3650 chk.dev_version = getOpenCLVersion(ret.str.buf + 7);
3652 case CL_DEVICE_EXTENSIONS:
3653 identify_device_extensions(extensions, &chk);
3659 case CL_DEVICE_TYPE:
3660 chk.devtype = ret.value.devtype;
3662 case CL_DEVICE_GLOBAL_MEM_CACHE_TYPE:
3663 chk.cachetype = ret.value.cachetype;
3665 case CL_DEVICE_LOCAL_MEM_TYPE:
3666 chk.lmemtype = ret.value.lmemtype;
3668 case CL_DEVICE_IMAGE_SUPPORT:
3669 chk.image_support = ret.value.b;
3671 case CL_DEVICE_COMPILER_AVAILABLE:
3672 chk.compiler_available = ret.value.b;
3674 case CL_DEVICE_NUM_P2P_DEVICES_AMD:
3675 chk.p2p_num_devs = ret.value.u32;
3677 case CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM:
3678 chk.arm_register_alloc_support = !!(ret.value.sched_controls & CL_DEVICE_SCHEDULING_REGISTER_ALLOCATION_ARM);
3679 // TODO warp count support should check for extension version >= 0.4
3680 chk.arm_warp_count_support = !!(ret.value.sched_controls);
3688 // and finally the extensions, if we retrieved them
3691 extensions[ext_len + 1] = '\0';
3693 printf("%s\"%s\" : ", (n > 0 ? comma_str : spc_str),
3694 (output->mode == CLINFO_HUMAN ?
3695 extensions_traits->pname : extensions_traits->sname));
3696 json_stringify(extensions + 1);
3699 printf("%s" I1_STR "%s\n", line_pfx, (output->mode == CLINFO_HUMAN ?
3700 extensions_traits->pname : extensions_traits->sname),
3703 if (versioned_extensions) {
3705 printf("%s\"%s\" : ", (n > 0 ? comma_str : spc_str),
3706 (output->mode == CLINFO_HUMAN ?
3707 versioned_extensions_traits->pname : versioned_extensions_traits->sname));
3708 fputs(versioned_extensions, stdout);
3711 printf("%s" I1_STR "%s\n", line_pfx, (output->mode == CLINFO_HUMAN ?
3712 versioned_extensions_traits->pname :
3713 versioned_extensions_traits->sname),
3714 versioned_extensions);
3718 free(versioned_extensions);
3723 /* list of allowed properties for AMD offline devices */
3724 /* everything else seems to be set to 0, and all the other string properties
3725 * actually segfault the driver */
3727 static const cl_device_info amd_offline_info_whitelist[] = {
3729 /* These are present, but all the same, so just skip them:
3731 CL_DEVICE_VENDOR_ID,
3734 CL_DEVICE_OPENCL_C_VERSION,
3736 CL_DEVICE_EXTENSIONS,
3738 CL_DEVICE_GFXIP_MAJOR_AMD,
3739 CL_DEVICE_GFXIP_MINOR_AMD,
3740 CL_DEVICE_MAX_WORK_GROUP_SIZE,
3744 static const cl_device_info list_info_whitelist[] = {
3749 /* return a list of offline devices from the AMD extension */
3751 fetchOfflineDevicesAMD(const struct platform_list *plist, cl_uint p,
3752 /* the number of devices will be returned in ret->value.u32,
3753 * the associated context in ret->base.ctx;
3755 struct device_info_ret *ret)
3757 cl_platform_id pid = plist->platform[p];
3758 cl_device_id *device = NULL;
3759 cl_uint num_devs = 0;
3760 cl_context ctx = NULL;
3762 cl_context_properties ctxpft[] = {
3763 CL_CONTEXT_PLATFORM, (cl_context_properties)pid,
3764 CL_CONTEXT_OFFLINE_DEVICES_AMD, (cl_context_properties)CL_TRUE,
3768 ctx = clCreateContextFromType(ctxpft, CL_DEVICE_TYPE_ALL,
3769 NULL, NULL, &ret->err);
3770 REPORT_ERROR(&ret->err_str, ret->err, "create context");
3773 ret->err = REPORT_ERROR(&ret->err_str,
3774 clGetContextInfo(ctx, CL_CONTEXT_NUM_DEVICES,
3775 sizeof(num_devs), &num_devs, NULL),
3780 ALLOC(device, num_devs, "offline devices");
3782 ret->err = REPORT_ERROR(&ret->err_str,
3783 clGetContextInfo(ctx, CL_CONTEXT_DEVICES,
3784 num_devs*sizeof(*device), device, NULL),
3789 if (ctx) clReleaseContext(ctx);
3793 ret->value.u32 = num_devs;
3794 ret->base.ctx = ctx;
3799 void printPlatformName(const struct platform_list *plist, cl_uint p, struct _strbuf *str,
3800 const struct opt_out *output)
3802 const struct platform_data *pdata = plist->pdata + p;
3803 const char *brief_prefix = (output->mode == CLINFO_HUMAN ? "Platform #" : "");
3804 const char *title = (output->mode == CLINFO_HUMAN ? pinfo_traits[0].pname :
3805 pinfo_traits[0].sname);
3806 const int prefix_width = -line_pfx_len*(!output->brief);
3807 if (output->brief) {
3808 strbuf_append(__func__, str, "%s%" PRIu32 ": ", brief_prefix, p);
3809 } else if (output->mode == CLINFO_RAW) {
3810 strbuf_append(__func__, str, "[%s/*]", pdata->sname);
3812 sprintf(line_pfx, "%*s", prefix_width, str->buf);
3816 printf("%s%s\n", line_pfx, pdata->pname);
3818 printf("%s" I1_STR "%s\n", line_pfx, title, pdata->pname);
3821 void printPlatformDevices(const struct platform_list *plist, cl_uint p,
3822 const cl_device_id *device, cl_uint ndevs,
3823 struct _strbuf *str, const struct opt_out *output, cl_bool these_are_offline)
3825 const struct platform_data *pdata = plist->pdata + p;
3826 const cl_device_info *param_whitelist = output->brief ? list_info_whitelist :
3827 these_are_offline ? amd_offline_info_whitelist : NULL;
3831 printf("%s\"%s\" : [", (these_are_offline ? comma_str : spc_str),
3832 (these_are_offline ? "offline" : "online"));
3833 else if (output->detailed)
3834 printf("%s" I0_STR "%" PRIu32 "\n",
3836 num_devs_header(output, these_are_offline),
3839 for (d = 0; d < ndevs; ++d) {
3840 const cl_device_id dev = device[d];
3841 if (output->selected && output->device != d) continue;
3842 if (output->brief) {
3843 const cl_bool last_device = (d == ndevs - 1 &&
3844 output->mode != CLINFO_RAW &&
3845 (!output->offline ||
3846 !pdata->has_amd_offline ||
3847 these_are_offline));
3848 if (output->mode == CLINFO_RAW)
3849 sprintf(line_pfx, "%" PRIu32 "%c%" PRIu32 ": ",
3851 these_are_offline ? '*' : '.',
3854 sprintf(line_pfx, " +-- %sDevice #%" PRIu32 ": ",
3855 these_are_offline ? "Offline " : "",
3859 } else if (line_pfx_len > 0) {
3860 cl_int sd = (these_are_offline ? -1 : 1)*(cl_int)d;
3861 strbuf_append(__func__, str, "[%s/%" PRId32 "]", pdata->sname, sd);
3862 sprintf(line_pfx, "%*s", -line_pfx_len, str->buf);
3867 printf("%s{", d > 0 ? comma_str : spc_str);
3869 printDeviceInfo(dev, plist, p, param_whitelist, output);
3873 else if (output->detailed && d < pdata[p].ndevs - 1)
3880 fputs(" ]", stdout);
3884 void showDevices(const struct platform_list *plist, const struct opt_out *output)
3886 const cl_uint num_platforms = plist->num_platforms + (output->null_platform ? 1 : 0);
3887 const cl_uint maxdevs = plist->max_devs;
3888 const struct platform_data *pdata = plist->pdata;
3892 init_strbuf(&str, __func__);
3894 if (output->mode == CLINFO_RAW) {
3896 strbuf_append(__func__, &str, "%" PRIu32 ".%" PRIu32 ": ", num_platforms, maxdevs);
3898 strbuf_append(__func__, &str, "[%*s/%" PRIu32 "] ",
3899 plist->max_sname_len, "", maxdevs);
3902 strbuf_append(__func__, &str, " +-- %sDevice #%" PRIu32 ": ",
3903 (output->offline ? "Offline " : ""), maxdevs);
3904 /* TODO we have no prefix in HUMAN detailed output mode,
3905 * consider adding one
3910 line_pfx_len = (int)(strlen(str.buf) + 1);
3911 REALLOC(line_pfx, line_pfx_len, "line prefix");
3915 for (p = 0; p < num_platforms; ++p) {
3916 /* skip non-selected platforms altogether */
3917 if (output->selected && output->platform != p) continue;
3919 /* Open the JSON devices list for this platform */
3921 printf("%s{", p > 0 ? comma_str : spc_str);
3922 /* skip platform header if only printing specfic properties, */
3923 else if (!output->prop)
3924 printPlatformName(plist, p, &str, output);
3926 printPlatformDevices(plist, p,
3927 get_platform_devs(plist, p), pdata[p].ndevs,
3928 &str, output, CL_FALSE);
3930 if (output->offline && pdata[p].has_amd_offline) {
3931 struct device_info_ret ret;
3932 cl_device_id *devs = NULL;
3934 INIT_RET(ret, "offline device");
3935 if (output->detailed)
3938 devs = fetchOfflineDevicesAMD(plist, p, &ret);
3940 puts(ret.err_str.buf);
3942 printPlatformDevices(plist, p, devs, ret.value.u32,
3943 &str, output, CL_TRUE);
3944 clReleaseContext(ret.base.ctx);
3950 /* Close JSON object for this platform */
3952 fputs(" }", stdout);
3953 else if (output->detailed)
3959 /* check the behavior of clGetPlatformInfo() when given a NULL platform ID */
3960 void checkNullGetPlatformName(const struct opt_out *output)
3962 struct device_info_ret ret;
3963 struct info_loc loc;
3965 INIT_RET(ret, "null ctx");
3966 reset_loc(&loc, __func__);
3967 RESET_LOC_PARAM(loc, plat, CL_PLATFORM_NAME);
3969 ret.err = clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ret.str.sz, ret.str.buf, NULL);
3970 if (ret.err == CL_INVALID_PLATFORM) {
3971 strbuf_append(__func__, &ret.err_str, no_plat(output));
3973 loc.line = __LINE__ + 1;
3974 REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s");
3976 printf(I1_STR "%s\n",
3977 "clGetPlatformInfo(NULL, CL_PLATFORM_NAME, ...)", RET_BUF(ret)->buf);
3981 /* check the behavior of clGetDeviceIDs() when given a NULL platform ID;
3982 * return the index of the default platform in our array of platform IDs,
3983 * or num_platforms (which is an invalid platform index) in case of errors
3984 * or no platform or device found.
3986 cl_uint checkNullGetDevices(const struct platform_list *plist, const struct opt_out *output)
3988 const cl_uint num_platforms = plist->num_platforms;
3989 const struct platform_data *pdata = plist->pdata;
3990 const cl_platform_id *platform = plist->platform;
3992 struct device_info_ret ret;
3993 struct info_loc loc;
3995 cl_uint i = 0; /* generic iterator */
3996 cl_device_id dev = NULL; /* sample device */
3997 cl_platform_id plat = NULL; /* detected platform */
3999 cl_uint found = 0; /* number of platforms found */
4000 cl_uint pidx = num_platforms; /* index of the platform found */
4001 cl_uint numdevs = 0;
4003 INIT_RET(ret, "null get devices");
4005 reset_loc(&loc, __func__);
4006 loc.sname = "device IDs";
4008 ret.err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, 0, NULL, &numdevs);
4009 /* TODO we should check other CL_DEVICE_TYPE_* combinations, since a smart
4010 * implementation might give you a different default platform for GPUs
4012 * Of course the “no devices” case would then need to be handled differently.
4013 * The logic might be maintained similarly, provided we also gather
4014 * the number of devices of each type for each platform, although it's
4015 * obviously more likely to have multiple platforms with no devices
4020 case CL_INVALID_PLATFORM:
4021 strbuf_append_str(__func__, &ret.err_str, no_plat(output));
4023 case CL_DEVICE_NOT_FOUND:
4024 /* No devices were found, see if there are platforms with
4025 * no devices, and if there's only one, assume this is the
4026 * one being used as default by the ICD loader */
4027 for (i = 0; i < num_platforms; ++i) {
4028 if (pdata[i].ndevs == 0) {
4041 strbuf_append_str(__func__, &ret.err_str, (output->mode == CLINFO_HUMAN ?
4042 "<error: 0 devices, no matching platform!>" :
4043 "CL_DEVICE_NOT_FOUND | CL_INVALID_PLATFORM"));
4046 strbuf_append(__func__, &ret.err_str, "%s%s%s%s",
4047 no_dev_found(output),
4048 (output->mode == CLINFO_HUMAN ? " [" : " | "),
4049 (output->mode == CLINFO_HUMAN ? pdata[pidx].pname : pdata[pidx].sname),
4050 (output->mode == CLINFO_HUMAN ? "?]" : "?"));
4052 default: /* found > 1 */
4053 strbuf_append_str(__func__, &ret.err_str, (output->mode == CLINFO_HUMAN ?
4054 "<error: 0 devices, multiple matching platforms!>" :
4055 "CL_DEVICE_NOT_FOUND | ????"));
4060 loc.line = __LINE__+1;
4061 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get number of %s")) break;
4063 /* Determine platform by looking at the CL_DEVICE_PLATFORM of
4064 * one of the devices */
4065 ret.err = clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, 1, &dev, NULL);
4066 loc.line = __LINE__+1;
4067 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s")) break;
4069 RESET_LOC_PARAM(loc, dev, CL_DEVICE_PLATFORM);
4070 ret.err = clGetDeviceInfo(dev, CL_DEVICE_PLATFORM,
4071 sizeof(plat), &plat, NULL);
4072 loc.line = __LINE__+1;
4073 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s")) break;
4075 for (i = 0; i < num_platforms; ++i) {
4076 if (platform[i] == plat) {
4078 strbuf_append(__func__, &ret.str, "%s [%s]",
4079 (output->mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
4084 if (i == num_platforms) {
4085 ret.err = CL_INVALID_PLATFORM;
4086 strbuf_append(__func__, &ret.err_str, "<error: platform %p not found>", (void*)plat);
4089 printf(I1_STR "%s\n",
4090 "clGetDeviceIDs(NULL, CL_DEVICE_TYPE_ALL, ...)", RET_BUF(ret)->buf);
4096 void checkNullCtx(struct device_info_ret *ret,
4097 const struct platform_list *plist, cl_uint pidx, const char *which,
4098 const struct opt_out *output)
4100 const cl_device_id *dev = plist->all_devs + plist->dev_offset[pidx];
4101 struct info_loc loc;
4102 cl_context ctx = clCreateContext(NULL, 1, dev, NULL, NULL, &ret->err);
4104 reset_loc(&loc, __func__);
4106 loc.line = __LINE__+2;
4108 if (!REPORT_ERROR_LOC(ret, ret->err, &loc, "create context with device from %s platform"))
4109 strbuf_append(__func__, &ret->str, "%s [%s]",
4110 (output->mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
4111 plist->pdata[pidx].sname);
4113 clReleaseContext(ctx);
4118 /* check behavior of clCreateContextFromType() with NULL cl_context_properties */
4119 void checkNullCtxFromType(const struct platform_list *plist, const struct opt_out *output)
4121 const cl_uint num_platforms = plist->num_platforms;
4122 const struct platform_data *pdata = plist->pdata;
4123 const cl_platform_id *platform = plist->platform;
4125 size_t t; /* type iterator */
4126 size_t i; /* generic iterator */
4128 cl_context ctx = NULL;
4132 size_t cursz = ndevs*sizeof(cl_device_id);
4133 cl_platform_id plat = NULL;
4134 cl_device_id *devs = NULL;
4136 struct device_info_ret ret;
4137 struct info_loc loc;
4139 const char *platname_prop = (output->mode == CLINFO_HUMAN ?
4140 pinfo_traits[0].pname :
4141 pinfo_traits[0].sname);
4143 const char *devname_prop = (output->mode == CLINFO_HUMAN ?
4144 dinfo_traits[0].pname :
4145 dinfo_traits[0].sname);
4147 reset_loc(&loc, __func__);
4148 INIT_RET(ret, "null ctx from type");
4150 ALLOC(devs, ndevs, "context devices");
4152 for (t = 1; t < devtype_count; ++t) { /* we skip 0 */
4153 loc.sname = device_type_raw_str[t];
4155 strbuf_append(__func__, &ret.str, "clCreateContextFromType(NULL, %s)", loc.sname);
4156 sprintf(def, I1_STR, ret.str.buf);
4157 reset_strbuf(&ret.str);
4159 loc.line = __LINE__+1;
4160 ctx = clCreateContextFromType(NULL, devtype[t], NULL, NULL, &ret.err);
4163 case CL_INVALID_PLATFORM:
4164 strbuf_append_str(__func__, &ret.err_str, no_plat(output)); break;
4165 case CL_DEVICE_NOT_FOUND:
4166 strbuf_append_str(__func__, &ret.err_str, no_dev_found(output)); break;
4167 case CL_INVALID_DEVICE_TYPE: /* e.g. _CUSTOM device on 1.1 platform */
4168 strbuf_append_str(__func__, &ret.err_str, invalid_dev_type(output)); break;
4169 case CL_INVALID_VALUE: /* This is what apple returns for the case above */
4170 strbuf_append_str(__func__, &ret.err_str, invalid_dev_type(output)); break;
4171 case CL_DEVICE_NOT_AVAILABLE:
4172 strbuf_append_str(__func__, &ret.err_str, no_dev_avail(output)); break;
4174 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "create context from type %s")) break;
4176 /* get the devices */
4177 loc.sname = "CL_CONTEXT_DEVICES";
4178 loc.line = __LINE__+2;
4180 ret.err = clGetContextInfo(ctx, CL_CONTEXT_DEVICES, 0, NULL, &szval);
4181 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s size")) break;
4182 if (szval > cursz) {
4183 REALLOC(devs, szval, "context devices");
4187 loc.line = __LINE__+1;
4188 ret.err = clGetContextInfo(ctx, CL_CONTEXT_DEVICES, cursz, devs, NULL);
4189 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s")) break;
4190 ndevs = szval/sizeof(cl_device_id);
4192 ret.err = CL_DEVICE_NOT_FOUND;
4193 strbuf_append_str(__func__, &ret.err_str, "<error: context created with no devices>");
4196 /* get the platform from the first device */
4197 RESET_LOC_PARAM(loc, dev, CL_DEVICE_PLATFORM);
4198 loc.line = __LINE__+1;
4199 ret.err = clGetDeviceInfo(*devs, CL_DEVICE_PLATFORM, sizeof(plat), &plat, NULL);
4200 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s")) break;
4203 for (i = 0; i < num_platforms; ++i) {
4204 if (platform[i] == plat)
4207 if (i == num_platforms) {
4208 ret.err = CL_INVALID_PLATFORM;
4209 strbuf_append(__func__, &ret.err_str, "<error: platform %p not found>", (void*)plat);
4212 strbuf_append(__func__, &ret.str, "%s (%" PRIuS ")",
4213 (output->mode == CLINFO_HUMAN ? "Success" : "CL_SUCCESS"),
4215 strbuf_append(__func__, &ret.str, "\n" I2_STR "%s",
4216 platname_prop, pdata[i].pname);
4218 for (i = 0; i < ndevs; ++i) {
4220 /* for each device, show the device name */
4221 /* TODO some other unique ID too, e.g. PCI address, if available? */
4223 strbuf_append(__func__, &ret.str, "\n" I2_STR, devname_prop);
4225 RESET_LOC_PARAM(loc, dev, CL_DEVICE_NAME);
4227 loc.line = __LINE__+1;
4228 ret.err = clGetDeviceInfo(devs[i], CL_DEVICE_NAME, ret.str.sz - ret.str.end, ret.str.buf + ret.str.end, &szname);
4229 if (REPORT_ERROR_LOC(&ret, ret.err, &loc, "get %s")) break;
4230 ret.str.end += szname - 1;
4233 break; /* had an error earlier, bail */
4237 clReleaseContext(ctx);
4240 printf("%s%s\n", def, RET_BUF(ret)->buf);
4241 reset_strbuf(&ret.str);
4242 reset_strbuf(&ret.err_str);
4248 /* check the behavior of NULL platform in clGetDeviceIDs (see checkNullGetDevices)
4249 * and in clCreateContext() */
4250 void checkNullBehavior(const struct platform_list *plist, const struct opt_out *output)
4252 const cl_uint num_platforms = plist->num_platforms;
4253 const struct platform_data *pdata = plist->pdata;
4256 struct device_info_ret ret;
4258 INIT_RET(ret, "null behavior");
4260 printf("NULL platform behavior\n");
4262 checkNullGetPlatformName(output);
4264 p = checkNullGetDevices(plist, output);
4266 /* If there's a default platform, and it has devices, try
4267 * creating a context with its first device and see if it works */
4269 if (p == num_platforms) {
4270 ret.err = CL_INVALID_PLATFORM;
4271 strbuf_append(__func__, &ret.err_str, no_plat(output));
4272 } else if (pdata[p].ndevs == 0) {
4273 ret.err = CL_DEVICE_NOT_FOUND;
4274 strbuf_append(__func__, &ret.err_str, no_dev_found(output));
4276 if (p < num_platforms) {
4277 checkNullCtx(&ret, plist, p, "default", output);
4279 /* this shouldn't happen, but still ... */
4280 ret.err = CL_OUT_OF_HOST_MEMORY;
4281 strbuf_append_str(__func__, &ret.err_str, "<error: overflow in default platform scan>");
4284 printf(I1_STR "%s\n", "clCreateContext(NULL, ...) [default]", RET_BUF(ret)->buf);
4286 /* Look for a device from a non-default platform, if there are any */
4287 if (p == num_platforms || num_platforms > 1) {
4289 reset_strbuf(&ret.str);
4290 reset_strbuf(&ret.err_str);
4291 while (p2 < num_platforms && (p2 == p || pdata[p2].ndevs == 0)) {
4294 if (p2 < num_platforms) {
4295 checkNullCtx(&ret, plist, p2, "non-default", output);
4297 ret.err = CL_DEVICE_NOT_FOUND;
4298 strbuf_append(__func__, &ret.err_str, "<error: no devices in non-default plaforms>");
4300 printf(I1_STR "%s\n", "clCreateContext(NULL, ...) [other]", RET_BUF(ret)->buf);
4303 checkNullCtxFromType(plist, output);
4309 /* Get properties of the ocl-icd loader, if available */
4310 /* All properties are currently char[] */
4312 /* Function pointer to the ICD loader info function */
4314 typedef cl_int (*icdl_info_fn_ptr)(cl_icdl_info, size_t, void*, size_t*);
4315 icdl_info_fn_ptr clGetICDLoaderInfoOCLICD;
4317 /* We want to auto-detect the OpenCL version supported by the ICD loader.
4318 * To do this, we will progressively find symbols introduced in new APIs,
4319 * until a NULL symbol is found.
4322 struct icd_loader_test {
4325 } icd_loader_tests[] = {
4326 { 11, "clCreateSubBuffer" },
4327 { 12, "clCreateImage" },
4328 { 20, "clSVMAlloc" },
4329 { 21, "clGetHostTimer" },
4330 { 22, "clSetProgramSpecializationConstant" },
4331 { 30, "clSetContextDestructorCallback" },
4336 icdl_info_str(struct icdl_info_ret *ret, const struct info_loc *loc)
4338 GET_STRING_LOC(ret, loc, clGetICDLoaderInfoOCLICD, loc->param.icdl);
4342 struct icdl_info_traits {
4343 cl_icdl_info param; // CL_ICDL_*
4344 const char *sname; // "CL_ICDL_*"
4345 const char *pname; // "ICD loader *"
4348 static const char * const oclicdl_pfx = "OCLICD";
4350 #define LINFO(symbol, name) { symbol, #symbol, "ICD loader " name }
4351 struct icdl_info_traits linfo_traits[] = {
4352 LINFO(CL_ICDL_NAME, "Name"),
4353 LINFO(CL_ICDL_VENDOR, "Vendor"),
4354 LINFO(CL_ICDL_VERSION, "Version"),
4355 LINFO(CL_ICDL_OCL_VERSION, "Profile")
4358 /* The ICD loader info function must be retrieved via clGetExtensionFunctionAddress,
4359 * which returns a void pointer.
4360 * ISO C forbids assignments between function pointers and void pointers,
4361 * but POSIX allows it. To compile without warnings even in -pedantic mode,
4362 * we take advantage of the fact that we _can_ do the conversion via
4363 * pointers-to-pointers. This is supported on most compilers, except
4364 * for some rather old GCC versions whose strict aliasing rules are
4365 * too strict. Disable strict aliasing warnings for these compilers.
4367 #if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46)
4368 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
4371 struct icdl_data oclIcdProps(const struct platform_list *plist, const struct opt_out *output)
4373 const cl_uint max_plat_version = plist->max_plat_version;
4375 struct icdl_data icdl;
4377 /* clinfo may lag behind the OpenCL standard or loader version,
4378 * and we don't want to give a warning if we can't tell if the loader
4379 * correctly supports a version unknown to us
4381 cl_uint clinfo_highest_known_version = 0;
4383 /* Counter that'll be used to walk the icd_loader_tests */
4386 /* We find the clGetICDLoaderInfoOCLICD extension address, which will be used
4387 * to query the ICD loader properties.
4388 * It should be noted that in this specific case we cannot replace the
4389 * call to clGetExtensionFunctionAddress with a call to the superseding function
4390 * clGetExtensionFunctionAddressForPlatform because the extension is in the
4391 * loader itself, not in a specific platform.
4393 void *ptrHack = clGetExtensionFunctionAddress("clGetICDLoaderInfoOCLICD");
4394 clGetICDLoaderInfoOCLICD = *(icdl_info_fn_ptr*)(&ptrHack);
4396 /* Initialize icdl_data ret versions */
4397 icdl.detected_version = 10;
4398 icdl.reported_version = 0;
4400 /* Step #1: try to auto-detect the supported ICD loader version */
4402 struct icd_loader_test check = icd_loader_tests[i];
4403 if (check.symbol == NULL)
4405 if (dlsym(DL_MODULE, check.symbol) == NULL)
4407 clinfo_highest_known_version = icdl.detected_version = check.version;
4411 /* Step #2: query properties from extension, if available */
4412 if (clGetICDLoaderInfoOCLICD != NULL) {
4413 cl_uint n = 0; /* number of ICD loader properties shown, for JSON */
4414 struct info_loc loc;
4415 struct icdl_info_ret ret;
4416 reset_loc(&loc, __func__);
4417 INIT_RET(ret, "ICD loader");
4419 /* TODO think of a sensible header in CLINFO_RAW */
4420 if (output->mode != CLINFO_RAW)
4421 puts("\nICD loader properties");
4424 fputs(", \"icd_loader\" : {", stdout);
4425 } else if (output->mode == CLINFO_RAW) {
4426 line_pfx_len = (int)(strlen(oclicdl_pfx) + 5);
4427 REALLOC(line_pfx, line_pfx_len, "line prefix OCL ICD");
4428 strbuf_append(loc.pname, &ret.str, "[%s/*]", oclicdl_pfx);
4429 sprintf(line_pfx, "%*s", -line_pfx_len, ret.str.buf);
4430 reset_strbuf(&ret.str);
4433 for (loc.line = 0; loc.line < ARRAY_SIZE(linfo_traits); ++loc.line) {
4434 const struct icdl_info_traits *traits = linfo_traits + loc.line;
4436 loc.sname = traits->sname;
4437 loc.pname = (output->mode == CLINFO_HUMAN ?
4438 traits->pname : traits->sname);
4439 loc.param.icdl = traits->param;
4441 reset_strbuf(&ret.str);
4442 reset_strbuf(&ret.err_str);
4443 icdl_info_str(&ret, &loc);
4445 /* Do not print this property if the user requested one and this does not match */
4446 requested = !(output->prop && strstr(loc.sname, output->prop) == NULL);
4449 json_strbuf(RET_BUF(ret), loc.pname, n++, CL_TRUE);
4451 show_strbuf(RET_BUF(ret), loc.pname, 1, ret.err);
4454 if (!ret.err && traits->param == CL_ICDL_OCL_VERSION) {
4455 icdl.reported_version = getOpenCLVersion(ret.str.buf + 7);
4460 printf("%s\"_detected_version\" : \"%" PRIu32 ".%" PRIu32 "\" }",
4461 (n > 0 ? comma_str : spc_str),
4462 SPLIT_CL_VERSION(icdl.detected_version));
4466 /* Step #3: show it */
4467 if (output->mode == CLINFO_HUMAN) {
4468 // for the loader vs platform max version check we use the version we detected
4469 // if the reported version is known to us, and the reported version if it's higher
4470 // than the standard versions we know about
4471 cl_uint max_version_check = icdl.reported_version > clinfo_highest_known_version ?
4472 icdl.reported_version : icdl.detected_version;
4474 if (icdl.reported_version &&
4475 icdl.reported_version <= clinfo_highest_known_version &&
4476 icdl.reported_version != icdl.detected_version) {
4477 printf( "\tNOTE:\tyour OpenCL library declares to support OpenCL %" PRIu32 ".%" PRIu32 ",\n"
4478 "\t\tbut it seems to support up to OpenCL %" PRIu32 ".%" PRIu32 " %s.\n",
4479 SPLIT_CL_VERSION(icdl.reported_version),
4480 SPLIT_CL_VERSION(icdl.detected_version),
4481 icdl.detected_version < icdl.reported_version ?
4485 if (max_version_check < max_plat_version) {
4486 printf( "\tNOTE:\tyour OpenCL library only supports OpenCL %" PRIu32 ".%" PRIu32 ",\n"
4487 "\t\tbut some installed platforms support OpenCL %" PRIu32 ".%" PRIu32 ".\n"
4488 "\t\tPrograms using %" PRIu32 ".%" PRIu32 " features may crash\n"
4489 "\t\tor behave unexpectedly\n",
4490 SPLIT_CL_VERSION(icdl.detected_version),
4491 SPLIT_CL_VERSION(max_plat_version),
4492 SPLIT_CL_VERSION(max_plat_version));
4498 #if defined __GNUC__ && ((__GNUC__*10 + __GNUC_MINOR__) < 46)
4499 #pragma GCC diagnostic warning "-Wstrict-aliasing"
4504 puts("clinfo version 3.0.23.01.25");
4507 void parse_device_spec(const char *str, struct opt_out *output)
4511 fprintf(stderr, "please specify a device in the form P:D where P is the platform number and D the device number\n");
4514 n = sscanf(str, "%d:%d", &p, &d);
4515 if (n != 2 || p < 0 || d < 0) {
4516 fprintf(stderr, "invalid device specification '%s'\n", str);
4519 output->platform = p;
4523 void free_output(struct opt_out *output)
4525 free((char*)output->prop);
4526 output->prop = NULL;
4529 void parse_prop(const char *input, struct opt_out *output)
4531 /* We normalize the property name by upcasing it and replacing the minus sign (-)
4532 * with the underscore (_). If any other character is found, we consider it an error
4535 size_t len = strlen(input);
4537 ALLOC(normalized, len+1, "normalized property name");
4538 for (size_t i = 0; i < len; ++i)
4541 if ( (c == '_') || ( c >= 'A' && c <= 'Z'))
4543 else if (c >= 'a' && c <= 'z')
4544 normalized[i] = 'A' + (c - 'a');
4546 normalized[i] = '_';
4548 fprintf(stderr, "invalid property name substring '%s'\n", input);
4554 fprintf(stderr, "WARNING: only one property name substring supported, discarding %s in favor of %s\n",
4555 output->prop, normalized);
4556 free_output(output);
4558 output->prop = normalized;
4564 puts("Display properties of all available OpenCL platforms and devices");
4565 puts("Usage: clinfo [options ...]\n");
4567 puts("\t--all-props, -a\t\ttry all properties, only show valid ones");
4568 puts("\t--always-all-props, -At\tshow all properties, even if invalid");
4569 puts("\t--human\t\thuman-friendly output (default)");
4570 puts("\t--raw\t\traw output");
4571 puts("\t--offline\talso show offline devices");
4572 puts("\t--null-platform\talso show the NULL platform devices");
4573 puts("\t--list, -l\tonly list the platforms and devices by name");
4574 puts("\t--prop prop-name\tonly list properties matching the given name");
4575 puts("\t--device p:d,");
4576 puts("\t-d p:d\t\tonly show information about device number d from platform number p");
4577 puts("\t-h, -?\t\tshow usage");
4578 puts("\t--version, -v\tshow version\n");
4579 puts("Defaults to raw mode if invoked with");
4580 puts("a name that contains the string \"raw\"");
4583 int main(int argc, char *argv[])
4589 struct opt_out output;
4591 struct platform_list plist;
4594 output.platform = CL_UINT_MAX;
4595 output.device = CL_UINT_MAX;
4597 output.mode = CLINFO_HUMAN;
4598 output.cond = COND_PROP_CHECK;
4599 output.brief = CL_FALSE;
4600 output.offline = CL_FALSE;
4601 output.null_platform = CL_FALSE;
4602 output.json = CL_FALSE;
4603 output.check_size = CL_FALSE;
4605 /* if there's a 'raw' in the program name, switch to raw output mode */
4606 if (strstr(argv[0], "raw"))
4607 output.mode = CLINFO_RAW;
4609 /* process command-line arguments */
4610 while (++a < argc) {
4611 if (!strcmp(argv[a], "-a") || !strcmp(argv[a], "--all-props"))
4612 output.cond = COND_PROP_TRY;
4613 else if (!strcmp(argv[a], "-A") || !strcmp(argv[a], "--always-all-props"))
4614 output.cond = COND_PROP_SHOW;
4615 else if (!strcmp(argv[a], "--raw"))
4616 output.mode = CLINFO_RAW;
4617 else if (!strcmp(argv[a], "--human"))
4618 output.mode = CLINFO_HUMAN;
4619 else if (!strcmp(argv[a], "--offline"))
4620 output.offline = CL_TRUE;
4621 else if (!strcmp(argv[a], "--null-platform"))
4622 output.null_platform = CL_TRUE;
4623 else if (!strcmp(argv[a], "--json"))
4624 output.json = CL_TRUE;
4625 else if (!strcmp(argv[a], "-l") || !strcmp(argv[a], "--list"))
4626 output.brief = CL_TRUE;
4627 else if (!strcmp(argv[a], "-d") || !strcmp(argv[a], "--device")) {
4629 parse_device_spec(argv[a], &output);
4630 } else if (!strncmp(argv[a], "-d", 2)) {
4631 parse_device_spec(argv[a] + 2, &output);
4632 } else if (!strcmp(argv[a], "--prop")) {
4634 parse_prop(argv[a], &output);
4635 } else if (!strcmp(argv[a], "-?") || !strcmp(argv[a], "-h")) {
4637 free_output(&output);
4639 } else if (!strcmp(argv[a], "--version") || !strcmp(argv[a], "-v")) {
4641 free_output(&output);
4644 fprintf(stderr, "ignoring unknown command-line parameter %s\n", argv[a]);
4647 /* If a property was specified, we only print in RAW mode.
4648 * Likewise, JSON format assumes RAW
4650 if (output.prop || output.json)
4651 output.mode = CLINFO_RAW;
4652 output.selected = (output.device != CL_UINT_MAX);
4653 output.detailed = !output.brief && !output.selected && !output.prop;
4655 err = clGetPlatformIDs(0, NULL, &plist.num_platforms);
4656 if (err != CL_PLATFORM_NOT_FOUND_KHR)
4657 CHECK_ERROR(err, "number of platforms");
4659 if (output.detailed && !output.json)
4660 printf(I0_STR "%" PRIu32 "\n",
4661 (output.mode == CLINFO_HUMAN ?
4662 "Number of platforms" : "#PLATFORMS"),
4663 plist.num_platforms);
4665 cl_uint alloced_platforms = 0;
4666 if (plist.num_platforms) {
4667 alloced_platforms = alloc_plist(&plist, &output);
4668 err = clGetPlatformIDs(plist.num_platforms, plist.platform, NULL);
4669 CHECK_ERROR(err, "platform IDs");
4672 ALLOC(line_pfx, 1, "line prefix");
4674 /* Open the JSON object and the JSON platforms list */
4676 fputs("{ \"platforms\" : [", stdout);
4678 for (p = 0; p < alloced_platforms; ++p) {
4679 // skip non-selected platforms altogether
4680 if (output.selected && output.platform != p) continue;
4682 /* Open a JSON object for this platform */
4684 printf("%s{", p > 0 ? comma_str : spc_str);
4686 gatherPlatformInfo(&plist, p, &output);
4688 /* Close JSON object for this platform */
4690 fputs(" }", stdout);
4691 else if (output.detailed)
4695 /* Close JSON platforms list, open JSON devices list */
4696 if (alloced_platforms) {
4698 fputs(" ], \"devices\" : [", stdout);
4700 showDevices(&plist, &output);
4703 /* Close JSON devices list */
4705 fputs(" ]", stdout);
4707 if (output.prop || (output.detailed && !output.selected)) {
4708 if (output.mode != CLINFO_RAW && plist.num_platforms)
4709 checkNullBehavior(&plist, &output);
4710 oclIcdProps(&plist, &output);
4713 /* Close the JSON object */
4715 fputs(" }", stdout);
4720 free_output(&output);