Skip to content

Commit 3723f42

Browse files
committed
proxy: tree-sitter to collect metadata
In cases when the underlying ocl lib does not provide metadata, use tree sitter to parse the kernel source and extract the metadata from that. Uses code generated from: https://github.com/lefp/tree-sitter-opencl.
1 parent dc44a03 commit 3723f42

9 files changed

+759
-7
lines changed

CMakeLists.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -1767,7 +1767,12 @@ if(ENABLE_PROXY_DEVICE)
17671767
set(RENAME_POCL OFF )
17681768
endif()
17691769

1770-
1770+
find_library(TSLIB tree-sitter)
1771+
set(HAVE_TREE_SITTER OFF)
1772+
if(TSLIB)
1773+
set(HAVE_TREE_SITTER ON)
1774+
message("-- FOUND tree sitter library")
1775+
endif()
17711776

17721777
set(BUILD_PROXY 1)
17731778

config.h.in.cmake

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@
112112

113113
#cmakedefine HAVE_OPENCV
114114

115+
#cmakedefine01 HAVE_TREE_SITTER
116+
115117
#cmakedefine HAVE_OCL_ICD
116118
#cmakedefine HAVE_OCL_ICD_30_COMPATIBLE
117119

lib/CL/devices/CMakeLists.txt

+10
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ if(ENABLE_TCE)
125125
endif()
126126

127127
if(ENABLE_PROXY_DEVICE)
128+
if(HAVE_TREE_SITTER)
129+
add_subdirectory("tree_sitter")
130+
list(APPEND POCL_DEVICES_LINK_LIST pocl_tree_sitter_utils tree-sitter)
131+
set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS}"
132+
"$<TARGET_OBJECTS:pocl_tree_sitter_utils>")
133+
endif ()
128134
add_subdirectory("proxy")
129135
set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS}"
130136
"$<TARGET_OBJECTS:pocl-devices-proxy>")
@@ -226,6 +232,10 @@ if(HAVE_OPENCV)
226232
target_link_libraries("pocl-devices" PRIVATE opencv_dnn)
227233
endif ()
228234

235+
if(HAVE_TREE_SITTER)
236+
target_link_libraries("pocl-devices" PRIVATE tree-sitter)
237+
endif()
238+
229239
set(POCL_DEVICES_OBJS "${POCL_DEVICES_OBJS}"
230240
"$<TARGET_OBJECTS:pocl-devices>")
231241
harden("pocl-devices")

lib/CL/devices/proxy/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525

2626
add_pocl_device_library("pocl-devices-proxy" pocl_proxy.hpp pocl_proxy.cpp)
2727

28+
if(HAVE_TREE_SITTER)
29+
target_link_libraries("pocl-devices-proxy" PRIVATE pocl_tree_sitter_utils)
30+
endif()
31+
2832
if(PROXY_USE_LIBOPENCL_STUB)
2933

3034
set(STUB_SOURCES libopencl_stub/openclstub.c libopencl_stub/openclstub.h libopencl_stub/rename_stub.h)

lib/CL/devices/proxy/libopencl_stub/openclstub.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ static int
8282
open_libopencl_so ()
8383
{
8484
char *path = NULL, *str = NULL;
85-
int i;
8685

8786
if ((str = getenv ("LIBOPENCL_SO_PATH")) && access_file (str))
8887
{
@@ -103,7 +102,8 @@ open_libopencl_so ()
103102

104103
if (!path)
105104
{
106-
for (i = 0; i < (sizeof (default_so_paths) / sizeof (char *)); i++)
105+
for (size_t i = 0; i < (sizeof (default_so_paths) / sizeof (char *));
106+
i++)
107107
{
108108
if (access_file (default_so_paths[i]))
109109
{

lib/CL/devices/proxy/pocl_proxy.cpp

+140-4
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@
5858
#error This driver cannot be built when pocl is to be linked against ICD
5959
#endif
6060

61+
#ifndef HAVE_TREE_SITTER
62+
#define HAVE_TREE_SITTER 0
63+
#endif
64+
#if HAVE_TREE_SITTER
65+
#include "pocl_tree_sitter_utils.h"
66+
#endif
67+
6168
/*****************************************************************************/
6269

6370
typedef struct proxy_platform_data_s
@@ -983,6 +990,120 @@ static int get_kernel_metadata(pocl_kernel_metadata_t *meta,
983990
return CL_SUCCESS;
984991
}
985992

993+
#if HAVE_TREE_SITTER
994+
///
995+
/// Use tree sitter to populate metadata from the kernel source string.
996+
///
997+
/// \param source [in]: String of kernel source.
998+
/// \param meta [out]: Populated with metadata of kernel.
999+
/// \param num_devices [in]: device count.
1000+
/// \param device [in]: used to populate metadata.
1001+
/// \param kernel [in]: kernel to get metadata about.
1002+
/// \return CL_SUCCESS or a CL error.
1003+
static int proxy_map_source_to_metadata(const char *source,
1004+
pocl_kernel_metadata_t *meta,
1005+
cl_uint num_devices,
1006+
cl_device_id device, cl_kernel kernel) {
1007+
1008+
char string_value[POCL_MAX_PATHNAME_LENGTH];
1009+
int err;
1010+
size_t size;
1011+
1012+
assert(meta->data == nullptr);
1013+
meta->data = (void **)calloc(num_devices, sizeof(void *));
1014+
meta->has_arg_metadata = (-1);
1015+
1016+
err = clGetKernelInfo(kernel, CL_KERNEL_FUNCTION_NAME, 0, nullptr, &size);
1017+
if (err != CL_SUCCESS || size == 0) {
1018+
POCL_MSG_PRINT_PROXY("Could not get kernel name.\n");
1019+
return err;
1020+
}
1021+
assert(size < POCL_MAX_PATHNAME_LENGTH);
1022+
1023+
err = clGetKernelInfo(kernel, CL_KERNEL_FUNCTION_NAME, size, string_value,
1024+
nullptr);
1025+
if (err != CL_SUCCESS) {
1026+
POCL_MSG_PRINT_PROXY("Could not copy kernel name.\n");
1027+
return err;
1028+
}
1029+
meta->name = (char *)malloc(size);
1030+
memcpy(meta->name, string_value, size);
1031+
1032+
err = get_kernel_info(meta, device, kernel);
1033+
if (err != CL_SUCCESS) {
1034+
POCL_MSG_PRINT_PROXY("Could not get kernel info.\n");
1035+
return err;
1036+
}
1037+
1038+
cl_uint num_args;
1039+
1040+
err = clGetKernelInfo(kernel, CL_KERNEL_NUM_ARGS, sizeof(num_args), &num_args,
1041+
nullptr);
1042+
if (err != CL_SUCCESS) {
1043+
POCL_MSG_PRINT_PROXY("Could not get number of kernel args.\n");
1044+
return err;
1045+
}
1046+
1047+
if (num_args == 0) {
1048+
meta->arg_info = nullptr;
1049+
meta->num_args = 0;
1050+
return CL_SUCCESS;
1051+
}
1052+
1053+
assert(num_args < 10000);
1054+
1055+
meta->num_args = num_args;
1056+
meta->arg_info =
1057+
(pocl_argument_info *)calloc(num_args, sizeof(pocl_argument_info));
1058+
1059+
char empty_buffer[MAX_TESTED_ARG_SIZE];
1060+
1061+
TSParser *parser = ts_parser_new();
1062+
ts_parser_set_language(parser, tree_sitter_opencl());
1063+
TSTree *tree =
1064+
ts_parser_parse_string(parser, nullptr, source, strlen(source));
1065+
TSNode root_node = ts_tree_root_node(tree);
1066+
1067+
int32_t status = 0;
1068+
TSNode kernel_node =
1069+
pocl_ts_find_kernel_params(source, root_node, meta->name, &status);
1070+
uint32_t child_count;
1071+
if (status != CL_SUCCESS) {
1072+
err = CL_KERNEL_ARG_INFO_NOT_AVAILABLE;
1073+
POCL_MSG_WARN("Could not find kernel name in source.\n");
1074+
goto TS_ERROR;
1075+
}
1076+
POCL_PRINT_TS_NODE(source, kernel_node);
1077+
child_count = ts_node_named_child_count(kernel_node);
1078+
assert(num_args == child_count);
1079+
1080+
TSNode child;
1081+
for (cl_uint i = 0; i < num_args; ++i) {
1082+
pocl_argument_info *pi = &meta->arg_info[i];
1083+
child = ts_node_named_child(kernel_node, i);
1084+
err = pocl_ts_map_node_to_arg_info(source, child, pi);
1085+
if (err != CL_SUCCESS) {
1086+
POCL_MSG_WARN("Failed to parse %s arg %d.\n", meta->name, i);
1087+
goto TS_ERROR;
1088+
}
1089+
1090+
POCL_MSG_PRINT_PROXY("KERNEL %s ARGUMENT %u NAME %s "
1091+
"TYPENAME %s TYPE %u SIZE %u\n",
1092+
meta->name, i, pi->name, pi->type_name, pi->type,
1093+
pi->type_size);
1094+
}
1095+
1096+
ts_tree_delete(tree);
1097+
ts_parser_delete(parser);
1098+
return CL_SUCCESS;
1099+
1100+
TS_ERROR:
1101+
ts_tree_delete(tree);
1102+
ts_parser_delete(parser);
1103+
return err;
1104+
}
1105+
#endif
1106+
9861107
static void
9871108
set_build_log (cl_device_id proxy_dev, cl_program program,
9881109
cl_program proxy_prog, unsigned device_i)
@@ -1401,8 +1522,8 @@ pocl_proxy_setup_metadata (cl_device_id device, cl_program program,
14011522
cl_program proxy_prog = (cl_program)program->data[program_device_i];
14021523

14031524
// Return if there is no metadata and we are not building using a binary.
1404-
if (!(d->backend->provides_metadata ||
1405-
(d->backend->supports_il && program->program_il_size > 0)))
1525+
if (!(d->backend->provides_metadata || HAVE_TREE_SITTER ||
1526+
(d->backend->supports_il && program->program_il_size > 0)))
14061527
return 0;
14071528

14081529
assert(program->kernel_meta == NULL);
@@ -1471,8 +1592,9 @@ pocl_proxy_setup_metadata (cl_device_id device, cl_program program,
14711592
index++;
14721593
}
14731594

1474-
} else {
1595+
} else if (d->backend->provides_metadata) {
14751596
for (cl_uint i = 0; i < num_kernels; ++i) {
1597+
14761598
err = get_kernel_metadata(p + i, program->num_devices, proxy_prog,
14771599
d->device_id, kernels[i]);
14781600
if (err != CL_SUCCESS) {
@@ -1483,7 +1605,21 @@ pocl_proxy_setup_metadata (cl_device_id device, cl_program program,
14831605
err = clReleaseKernel(kernels[i]);
14841606
assert(err == CL_SUCCESS);
14851607
}
1486-
}
1608+
} else if (HAVE_TREE_SITTER) {
1609+
for (cl_uint i = 0; i < num_kernels; i++) {
1610+
1611+
err = proxy_map_source_to_metadata(program->source, p + i,
1612+
program->num_devices, d->device_id,
1613+
kernels[i]);
1614+
if (err != CL_SUCCESS) {
1615+
POCL_MSG_WARN("Failed to kernel metadata for index %d.\n", i);
1616+
return 0;
1617+
}
1618+
1619+
err = clReleaseKernel(kernels[i]);
1620+
}
1621+
} else
1622+
return 0;
14871623

14881624
program->kernel_meta = p;
14891625

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#=============================================================================
2+
# CMake build system files
3+
#
4+
# Copyright (c) 2014-2024 pocl developers
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
# THE SOFTWARE.
23+
#
24+
#=============================================================================
25+
include(ExternalProject)
26+
27+
find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI" REQUIRED)
28+
29+
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/external)
30+
ExternalProject_Add(tree_sitter
31+
GIT_REPOSITORY https://github.com/lefp/tree-sitter-opencl.git
32+
# Generate Cmake config
33+
PATCH_COMMAND ${TREE_SITTER_CLI} init
34+
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION} -DBUILD_SHARED_LIBS=OFF
35+
)
36+
37+
add_library(pocl_tree_sitter_utils OBJECT pocl_tree_sitter_utils.c
38+
pocl_tree_sitter_utils.h)
39+
target_include_directories(pocl_tree_sitter_utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${EXTERNAL_INSTALL_LOCATION}/include)
40+
target_link_directories(pocl_tree_sitter_utils PUBLIC ${EXTERNAL_INSTALL_LOCATION}/lib)
41+
add_dependencies(pocl_tree_sitter_utils tree_sitter)
42+
43+
target_link_libraries(pocl_tree_sitter_utils PUBLIC tree-sitter-opencl ${TSLIB})

0 commit comments

Comments
 (0)