Add first prototype of cllayerinfo. (#175)
* Add first prototype of cllayerinfo.
* Added scheme to silence layers during loading and exit.
* Added a first test of cllayerinfo.
* Fix lock if no layers are found.
* Improve style.
* Copy layer library name as it is transient.
* Add new required definitions.
* Remove deprecated OPENCL_ICD_LOADER_DISABLE_OPENCLON12 CMake option.
* Factor compile definitions.
* Add variable to disable cllayerinfo build.
* Refactor CMake test file.
* Remove options for now as suggested by the working group.
* Remove constants
* Include share.h for mingw
Co-authored-by: Ben Ashbaugh <ben.ashbaugh@intel.com>
* Add cllayerinfo to install and export target.
* Use CMakeDependOption.
Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu>
---------
Co-authored-by: Ben Ashbaugh <ben.ashbaugh@intel.com>
Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93facbe..e855054 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,6 +52,8 @@
# It is currently needed default while the specification is being formalized,
# and to study the performance impact.
option (ENABLE_OPENCL_LAYERS "Enable OpenCL Layers" ON)
+include(CMakeDependentOption)
+cmake_dependent_option(ENABLE_OPENCL_LAYERINFO "Enable building cllayerinfo tool" ON ENABLE_OPENCL_LAYERS OFF)
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(JoinPaths)
@@ -150,8 +152,7 @@
target_link_libraries (OpenCL PUBLIC OpenCL::Headers)
endif ()
-target_compile_definitions (OpenCL
- PRIVATE
+set (OPENCL_COMPILE_DEFINITIONS
CL_TARGET_OPENCL_VERSION=300
OPENCL_ICD_LOADER_VERSION_MAJOR=3
OPENCL_ICD_LOADER_VERSION_MINOR=0
@@ -159,6 +160,11 @@
$<$<BOOL:${ENABLE_OPENCL_LAYERS}>:CL_ENABLE_LAYERS>
)
+target_compile_definitions (OpenCL
+ PRIVATE
+ ${OPENCL_COMPILE_DEFINITIONS}
+)
+
target_include_directories (OpenCL
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
@@ -166,6 +172,44 @@
)
target_link_libraries (OpenCL PUBLIC ${CMAKE_DL_LIBS})
+if (ENABLE_OPENCL_LAYERINFO)
+
+ set (OPENCL_LAYER_INFO_SOURCES
+ loader/cllayerinfo.c
+ ${OPENCL_ICD_LOADER_SOURCES}
+ )
+
+ add_executable(cllayerinfo ${OPENCL_LAYER_INFO_SOURCES})
+
+ add_executable(OpenCL::cllayerinfo ALIAS cllayerinfo)
+
+ target_compile_definitions (cllayerinfo
+ PRIVATE
+ CL_LAYER_INFO
+ ${OPENCL_COMPILE_DEFINITIONS}
+ )
+
+ if (EXISTS ${OPENCL_ICD_LOADER_HEADERS_DIR}/CL/cl.h)
+ target_include_directories (cllayerinfo PUBLIC $<BUILD_INTERFACE:${OPENCL_ICD_LOADER_HEADERS_DIR}>)
+ else ()
+ target_link_libraries (cllayerinfo PUBLIC OpenCL::Headers)
+ endif ()
+
+ if (WIN32)
+ target_link_libraries (cllayerinfo PRIVATE cfgmgr32.lib runtimeobject.lib)
+ else ()
+ target_link_libraries (cllayerinfo PRIVATE ${CMAKE_THREAD_LIBS_INIT})
+ endif ()
+
+ target_link_libraries (cllayerinfo PUBLIC ${CMAKE_DL_LIBS})
+
+ target_include_directories (cllayerinfo
+ PRIVATE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ loader
+ )
+endif ()
+
option (OPENCL_ICD_LOADER_BUILD_TESTING "Enable support for OpenCL ICD Loader testing." OFF)
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR OPENCL_ICD_LOADER_BUILD_TESTING)
@@ -191,6 +235,15 @@
OPTIONAL
)
+if (ENABLE_OPENCL_LAYERINFO)
+ install(
+ TARGETS cllayerinfo
+ EXPORT OpenCLICDLoaderTargets
+ RUNTIME
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
+ )
+endif()
+
export(
EXPORT OpenCLICDLoaderTargets
FILE ${PROJECT_BINARY_DIR}/OpenCLICDLoader/OpenCLICDLoaderTargets.cmake
diff --git a/loader/cllayerinfo.c b/loader/cllayerinfo.c
new file mode 100644
index 0000000..5a85ba8
--- /dev/null
+++ b/loader/cllayerinfo.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2022 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * OpenCL is a trademark of Apple Inc. used under license by Khronos.
+ */
+
+#include "icd.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <CL/cl_layer.h>
+#if defined(_WIN32)
+#include <io.h>
+#include <share.h>
+#include <sys/stat.h>
+#else
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+int stdout_bak, stderr_bak;
+
+// Temporarily deactivate stdout:
+// https://stackoverflow.com/a/4832902
+
+#if defined(_WIN32)
+#define SECURE 1
+#define OPEN _open
+#define OPEN_FLAGS _O_WRONLY
+#define CLOSE _close
+#define DUP _dup
+#define DUP2 _dup2
+#define NULL_STREAM "nul"
+#else
+#define OPEN open
+#define OPEN_FLAGS O_WRONLY
+#define CLOSE close
+#define DUP dup
+#define DUP2 dup2
+#define NULL_STREAM "/dev/null"
+#endif
+
+static inline int
+silence_stream(FILE *file, int fd)
+{
+ int new_fd, fd_bak;
+ fflush(file);
+ fd_bak = DUP(fd);
+#if defined(_WIN32) && SECURE
+ _sopen_s(&new_fd, NULL_STREAM, OPEN_FLAGS, _SH_DENYNO, _S_IWRITE);
+#else
+ new_fd = OPEN(NULL_STREAM, OPEN_FLAGS);
+#endif
+ DUP2(new_fd, fd);
+ CLOSE(new_fd);
+ return fd_bak;
+}
+
+static void silence_layers(void)
+{
+ stdout_bak = silence_stream(stdout, 1);
+ stderr_bak = silence_stream(stderr, 2);
+}
+
+static inline void
+restore_stream(FILE *file, int fd, int fd_bak)
+{
+ fflush(file);
+ DUP2(fd_bak, fd);
+ CLOSE(fd_bak);
+}
+
+static void restore_outputs(void)
+{
+ restore_stream(stdout, 1, stdout_bak);
+ restore_stream(stderr, 2, stderr_bak);
+}
+
+void printLayerInfo(const struct KHRLayer *layer)
+{
+ cl_layer_api_version api_version = 0;
+ pfn_clGetLayerInfo p_clGetLayerInfo = (pfn_clGetLayerInfo)(size_t)layer->p_clGetLayerInfo;
+ cl_int result = CL_SUCCESS;
+ size_t sz;
+
+ printf("%s:\n", layer->libraryName);
+ result = p_clGetLayerInfo(CL_LAYER_API_VERSION, sizeof(api_version), &api_version, NULL);
+ if (CL_SUCCESS == result)
+ printf("\tCL_LAYER_API_VERSION: %d\n", (int)api_version);
+
+ result = p_clGetLayerInfo(CL_LAYER_NAME, 0, NULL, &sz);
+ if (CL_SUCCESS == result)
+ {
+ char *name = (char *)malloc(sz);
+ if (name)
+ {
+ result = p_clGetLayerInfo(CL_LAYER_NAME, sz, name, NULL);
+ if (CL_SUCCESS == result)
+ printf("\tCL_LAYER_NAME: %s\n", name);
+ free(name);
+ }
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ (void)argc;
+ (void)argv;
+ silence_layers();
+ atexit(restore_outputs);
+ khrIcdInitialize();
+ restore_outputs();
+ atexit(silence_layers);
+ const struct KHRLayer *layer = khrFirstLayer;
+ while (layer)
+ {
+ printLayerInfo(layer);
+ layer = layer->next;
+ }
+ return 0;
+}
diff --git a/loader/icd.c b/loader/icd.c
index 5c227fa..bbd6ec3 100644
--- a/loader/icd.c
+++ b/loader/icd.c
@@ -285,6 +285,20 @@
KHR_ICD_TRACE("failed to allocate memory\n");
goto Done;
}
+#ifdef CL_LAYER_INFO
+ {
+ // Not using strdup as it is not standard c
+ size_t sz_name = strlen(libraryName) + 1;
+ layer->libraryName = malloc(sz_name);
+ if (!layer->libraryName)
+ {
+ KHR_ICD_TRACE("failed to allocate memory\n");
+ goto Done;
+ }
+ memcpy(layer->libraryName, libraryName, sz_name);
+ layer->p_clGetLayerInfo = (void *)(size_t)p_clGetLayerInfo;
+ }
+#endif
if (khrFirstLayer) {
targetDispatch = &(khrFirstLayer->dispatch);
diff --git a/loader/icd.h b/loader/icd.h
index 6727155..7d4a191 100644
--- a/loader/icd.h
+++ b/loader/icd.h
@@ -114,6 +114,12 @@
struct _cl_icd_dispatch dispatch;
// The next layer in the chain
struct KHRLayer *next;
+#ifdef CL_LAYER_INFO
+ // The layer library name
+ char *libraryName;
+ // the pointer to the clGetLayerInfo funciton
+ void *p_clGetLayerInfo;
+#endif
};
// the global layer state
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index bf720ea..0d78a79 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -18,17 +18,30 @@
NAME opencl_icd_loader_test
COMMAND icd_loader_test
)
-get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-if(GENERATOR_IS_MULTI_CONFIG)
- set_tests_properties(opencl_icd_loader_test
- PROPERTIES
- ENVIRONMENT OCL_ICD_FILENAMES=$<TARGET_FILE:OpenCLDriverStub>
- WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>"
+
+if (ENABLE_OPENCL_LAYERINFO)
+ add_test (
+ NAME cllayerinfo_test
+ COMMAND cllayerinfo
)
-else()
- set_tests_properties(opencl_icd_loader_test
+endif ()
+
+get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if (GENERATOR_IS_MULTI_CONFIG)
+ set (TEST_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>")
+else ()
+ set (TEST_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
+endif()
+
+set_tests_properties(opencl_icd_loader_test
+ PROPERTIES
+ ENVIRONMENT OCL_ICD_FILENAMES=$<TARGET_FILE:OpenCLDriverStub>
+ WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
+)
+if (ENABLE_OPENCL_LAYERINFO)
+ set_tests_properties(cllayerinfo_test
PROPERTIES
- ENVIRONMENT OCL_ICD_FILENAMES=$<TARGET_FILE:OpenCLDriverStub>
- WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ ENVIRONMENT OPENCL_LAYERS=$<TARGET_FILE:PrintLayer>
+ WORKING_DIRECTORY "${TEST_WORKING_DIRECTORY}"
)
endif()
diff --git a/test/layer/icd_print_layer.c b/test/layer/icd_print_layer.c
index 06525bf..d8bf462 100644
--- a/test/layer/icd_print_layer.c
+++ b/test/layer/icd_print_layer.c
@@ -17,34 +17,58 @@
*/
#include "icd_print_layer.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
struct _cl_icd_dispatch dispatch;
const struct _cl_icd_dispatch *tdispatch;
+static cl_layer_api_version api_version = CL_LAYER_API_VERSION_100;
+static const char name[] = "print_layer";
+
+static inline cl_int
+set_param_value(
+ size_t param_value_size,
+ void *param_value,
+ size_t *param_value_size_ret,
+ size_t src_size,
+ const void *src) {
+ if (param_value && param_value_size < src_size)
+ return CL_INVALID_VALUE;
+ if (param_value)
+ memcpy(param_value, src, src_size);
+ if (param_value_size_ret)
+ *param_value_size_ret = src_size;
+ return CL_SUCCESS;
+}
+
CL_API_ENTRY cl_int CL_API_CALL
clGetLayerInfo(
cl_layer_info param_name,
size_t param_value_size,
void *param_value,
size_t *param_value_size_ret) {
+ size_t sz = 0;
+ const void *src = NULL;
if (param_value_size && !param_value)
return CL_INVALID_VALUE;
if (!param_value && !param_value_size_ret)
return CL_INVALID_VALUE;
switch (param_name) {
case CL_LAYER_API_VERSION:
- if (param_value_size < sizeof(cl_layer_api_version))
- return CL_INVALID_VALUE;
- if (param_value)
- *((cl_layer_api_version *)param_value) = CL_LAYER_API_VERSION_100;
- if (param_value_size_ret)
- *param_value_size_ret = sizeof(cl_layer_api_version);
+ sz = sizeof(api_version);
+ src = &api_version;
+ break;
+ case CL_LAYER_NAME:
+ sz = sizeof(name);
+ src = name;
break;
default:
return CL_INVALID_VALUE;
}
- return CL_SUCCESS;
+ return set_param_value(param_value_size, param_value, param_value_size_ret, sz, src);
}
CL_API_ENTRY cl_int CL_API_CALL
@@ -53,7 +77,7 @@
const struct _cl_icd_dispatch *target_dispatch,
cl_uint *num_entries_out,
const struct _cl_icd_dispatch **layer_dispatch_ret) {
- if (!target_dispatch || !layer_dispatch_ret ||!num_entries_out || num_entries < sizeof(dispatch)/sizeof(dispatch.clGetPlatformIDs))
+ if (!target_dispatch || !layer_dispatch_ret || !num_entries_out || num_entries < sizeof(dispatch)/sizeof(dispatch.clGetPlatformIDs))
return CL_INVALID_VALUE;
_init_dispatch();
@@ -61,6 +85,7 @@
tdispatch = target_dispatch;
*layer_dispatch_ret = &dispatch;
*num_entries_out = sizeof(dispatch)/sizeof(dispatch.clGetPlatformIDs);
+
return CL_SUCCESS;
}